<html><head><title>/ansible/roles/install_dpdk_shared/</title></head>
<body>
<h2>/ansible/roles/install_dpdk_shared/</h2>
<ul>
<li><a href='/yardstick/plain/ansible/roles/?h=stable/euphrates&amp;id=3958c3e398c680215e2feaf0c54cc3639d96430d'>../</a></li>
  <li><a href='/yardstick/plain/ansible/roles/install_dpdk_shared/defaults/?h=stable/euphrates&amp;id=3958c3e398c680215e2feaf0c54cc3639d96430d'>defaults</a></li>
  <li><a href='/yardstick/plain/ansible/roles/install_dpdk_shared/tasks/?h=stable/euphrates&amp;id=3958c3e398c680215e2feaf0c54cc3639d96430d'>tasks</a></li>
  <li><a href='/yardstick/plain/ansible/roles/install_dpdk_shared/vars/?h=stable/euphrates&amp;id=3958c3e398c680215e2feaf0c54cc3639d96430d'>vars</a></li>
 </ul>
</body></html>
 <a
        id="lfcollabprojects-logo"
        href="http://collabprojects.linuxfoundation.org"
        >Linux Foundation Collaborative Projects</a
      >
    </div>
  </div>
</div>
<div id='cgit'><table id='header'>
<tr>
<td class='logo' rowspan='2'><a href='/'><img src='/cgit-data/cgit.png' alt='cgit logo'/></a></td>
<td class='main'><a href='/'>index</a> : <a href='/kvmfornfv/'>kvmfornfv</a></td><td class='form'><form method='get'>
<input type='hidden' name='id' value='d9e68e7d2584d6fb83ad212673858a030d3d01a4'/><select name='h' onchange='this.form.submit();'>
<option value='master'>master</option>
<option value='stable/brahmaputra'>stable/brahmaputra</option>
<option value='stable/colorado'>stable/colorado</option>
<option value='stable/danube'>stable/danube</option>
<option value='stable/euphrates' selected='selected'>stable/euphrates</option>
</select> <input type='submit' value='switch'/></form></td></tr>
<tr><td class='sub'></td><td class='sub right'>Grokmirror user</td></tr></table>
<table class='tabs'><tr><td>
<a href='/kvmfornfv/?h=stable/euphrates'>summary</a><a href='/kvmfornfv/refs/?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>refs</a><a href='/kvmfornfv/log/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates'>log</a><a class='active' href='/kvmfornfv/tree/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>tree</a><a href='/kvmfornfv/commit/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>commit</a><a href='/kvmfornfv/diff/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>diff</a><a href='/kvmfornfv/stats/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates'>stats</a></td><td class='form'><form class='right' method='get' action='/kvmfornfv/log/kernel/Documentation/cdrom/cdrom-standard.tex'>
<input type='hidden' name='h' value='stable/euphrates'/><input type='hidden' name='id' value='d9e68e7d2584d6fb83ad212673858a030d3d01a4'/><select name='qt'>
<option value='grep'>log msg</option>
<option value='author'>author</option>
<option value='committer'>committer</option>
<option value='range'>range</option>
</select>
<input class='txt' type='search' size='10' name='q' value=''/>
<input type='submit' value='search'/>
</form>
</td></tr></table>
<div class='path'>path: <a href='/kvmfornfv/tree/?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>root</a>/<a href='/kvmfornfv/tree/kernel?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>kernel</a>/<a href='/kvmfornfv/tree/kernel/Documentation?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>Documentation</a>/<a href='/kvmfornfv/tree/kernel/Documentation/cdrom?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>cdrom</a>/<a href='/kvmfornfv/tree/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>cdrom-standard.tex</a></div><div class='content'>blob: c06233fe52ac2bea917e4e850551b2733f8d341f (<a href='/kvmfornfv/plain/kernel/Documentation/cdrom/cdrom-standard.tex?h=stable/euphrates&amp;id=d9e68e7d2584d6fb83ad212673858a030d3d01a4'>plain</a>)
<table summary='blob content' class='blob'>
<tr><td class='linenumbers'><pre><a id='n1' href='#n1'>1</a>
<a id='n2' href='#n2'>2</a>
<a id='n3' href='#n3'>3</a>
<a id='n4' href='#n4'>4</a>
<a id='n5' href='#n5'>5</a>
<a id='n6' href='#n6'>6</a>
<a id='n7' href='#n7'>7</a>
<a id='n8' href='#n8'>8</a>
<a id='n9' href='#n9'>9</a>
<a id='n10' href='#n10'>10</a>
<a id='n11' href='#n11'>11</a>
<a id='n12' href='#n12'>12</a>
<a id='n13' href='#n13'>13</a>
<a id='n14' href='#n14'>14</a>
<a id='n15' href='#n15'>15</a>
<a id='n16' href='#n16'>16</a>
<a id='n17' href='#n17'>17</a>
<a id='n18' href='#n18'>18</a>
<a id='n19' href='#n19'>19</a>
<a id='n20' href='#n20'>20</a>
<a id='n21' href='#n21'>21</a>
<a id='n22' href='#n22'>22</a>
<a id='n23' href='#n23'>23</a>
<a id='n24' href='#n24'>24</a>
<a id='n25' href='#n25'>25</a>
<a id='n26' href='#n26'>26</a>
<a id='n27' href='#n27'>27</a>
<a id='n28' href='#n28'>28</a>
<a id='n29' href='#n29'>29</a>
<a id='n30' href='#n30'>30</a>
<a id='n31' href='#n31'>31</a>
<a id='n32' href='#n32'>32</a>
<a id='n33' href='#n33'>33</a>
<a id='n34' href='#n34'>34</a>
<a id='n35' href='#n35'>35</a>
<a id='n36' href='#n36'>36</a>
<a id='n37' href='#n37'>37</a>
<a id='n38' href='#n38'>38</a>
<a id='n39' href='#n39'>39</a>
<a id='n40' href='#n40'>40</a>
<a id='n41' href='#n41'>41</a>
<a id='n42' href='#n42'>42</a>
<a id='n43' href='#n43'>43</a>
<a id='n44' href='#n44'>44</a>
<a id='n45' href='#n45'>45</a>
<a id='n46' href='#n46'>46</a>
<a id='n47' href='#n47'>47</a>
<a id='n48' href='#n48'>48</a>
<a id='n49' href='#n49'>49</a>
<a id='n50' href='#n50'>50</a>
<a id='n51' href='#n51'>51</a>
<a id='n52' href='#n52'>52</a>
<a id='n53' href='#n53'>53</a>
<a id='n54' href='#n54'>54</a>
<a id='n55' href='#n55'>55</a>
<a id='n56' href='#n56'>56</a>
<a id='n57' href='#n57'>57</a>
<a id='n58' href='#n58'>58</a>
<a id='n59' href='#n59'>59</a>
<a id='n60' href='#n60'>60</a>
<a id='n61' href='#n61'>61</a>
<a id='n62' href='#n62'>62</a>
<a id='n63' href='#n63'>63</a>
<a id='n64' href='#n64'>64</a>
<a id='n65' href='#n65'>65</a>
<a id='n66' href='#n66'>66</a>
<a id='n67' href='#n67'>67</a>
<a id='n68' href='#n68'>68</a>
<a id='n69' href='#n69'>69</a>
<a id='n70' href='#n70'>70</a>
<a id='n71' href='#n71'>71</a>
<a id='n72' href='#n72'>72</a>
<a id='n73' href='#n73'>73</a>
<a id='n74' href='#n74'>74</a>
<a id='n75' href='#n75'>75</a>
<a id='n76' href='#n76'>76</a>
<a id='n77' href='#n77'>77</a>
<a id='n78' href='#n78'>78</a>
<a id='n79' href='#n79'>79</a>
<a id='n80' href='#n80'>80</a>
<a id='n81' href='#n81'>81</a>
<a id='n82' href='#n82'>82</a>
<a id='n83' href='#n83'>83</a>
<a id='n84' href='#n84'>84</a>
<a id='n85' href='#n85'>85</a>
<a id='n86' href='#n86'>86</a>
<a id='n87' href='#n87'>87</a>
<a id='n88' href='#n88'>88</a>
<a id='n89' href='#n89'>89</a>
<a id='n90' href='#n90'>90</a>
<a id='n91' href='#n91'>91</a>
<a id='n92' href='#n92'>92</a>
<a id='n93' href='#n93'>93</a>
<a id='n94' href='#n94'>94</a>
<a id='n95' href='#n95'>95</a>
<a id='n96' href='#n96'>96</a>
<a id='n97' href='#n97'>97</a>
<a id='n98' href='#n98'>98</a>
<a id='n99' href='#n99'>99</a>
<a id='n100' href='#n100'>100</a>
<a id='n101' href='#n101'>101</a>
<a id='n102' href='#n102'>102</a>
<a id='n103' href='#n103'>103</a>
<a id='n104' href='#n104'>104</a>
<a id='n105' href='#n105'>105</a>
<a id='n106' href='#n106'>106</a>
<a id='n107' href='#n107'>107</a>
<a id='n108' href='#n108'>108</a>
<a id='n109' href='#n109'>109</a>
<a id='n110' href='#n110'>110</a>
<a id='n111' href='#n111'>111</a>
<a id='n112' href='#n112'>112</a>
<a id='n113' href='#n113'>113</a>
<a id='n114' href='#n114'>114</a>
<a id='n115' href='#n115'>115</a>
<a id='n116' href='#n116'>116</a>
<a id='n117' href='#n117'>117</a>
<a id='n118' href='#n118'>118</a>
<a id='n119' href='#n119'>119</a>
<a id='n120' href='#n120'>120</a>
<a id='n121' href='#n121'>121</a>
<a id='n122' href='#n122'>122</a>
<a id='n123' href='#n123'>123</a>
<a id='n124' href='#n124'>124</a>
<a id='n125' href='#n125'>125</a>
<a id='n126' href='#n126'>126</a>
<a id='n127' href='#n127'>127</a>
<a id='n128' href='#n128'>128</a>
<a id='n129' href='#n129'>129</a>
<a id='n130' href='#n130'>130</a>
<a id='n131' href='#n131'>131</a>
<a id='n132' href='#n132'>132</a>
<a id='n133' href='#n133'>133</a>
<a id='n134' href='#n134'>134</a>
<a id='n135' href='#n135'>135</a>
<a id='n136' href='#n136'>136</a>
<a id='n137' href='#n137'>137</a>
<a id='n138' href='#n138'>138</a>
<a id='n139' href='#n139'>139</a>
<a id='n140' href='#n140'>140</a>
<a id='n141' href='#n141'>141</a>
<a id='n142' href='#n142'>142</a>
<a id='n143' href='#n143'>143</a>
<a id='n144' href='#n144'>144</a>
<a id='n145' href='#n145'>145</a>
<a id='n146' href='#n146'>146</a>
<a id='n147' href='#n147'>147</a>
<a id='n148' href='#n148'>148</a>
<a id='n149' href='#n149'>149</a>
<a id='n150' href='#n150'>150</a>
<a id='n151' href='#n151'>151</a>
<a id='n152' href='#n152'>152</a>
<a id='n153' href='#n153'>153</a>
<a id='n154' href='#n154'>154</a>
<a id='n155' href='#n155'>155</a>
<a id='n156' href='#n156'>156</a>
<a id='n157' href='#n157'>157</a>
<a id='n158' href='#n158'>158</a>
<a id='n159' href='#n159'>159</a>
<a id='n160' href='#n160'>160</a>
<a id='n161' href='#n161'>161</a>
<a id='n162' href='#n162'>162</a>
<a id='n163' href='#n163'>163</a>
<a id='n164' href='#n164'>164</a>
<a id='n165' href='#n165'>165</a>
<a id='n166' href='#n166'>166</a>
<a id='n167' href='#n167'>167</a>
<a id='n168' href='#n168'>168</a>
<a id='n169' href='#n169'>169</a>
<a id='n170' href='#n170'>170</a>
<a id='n171' href='#n171'>171</a>
<a id='n172' href='#n172'>172</a>
<a id='n173' href='#n173'>173</a>
<a id='n174' href='#n174'>174</a>
<a id='n175' href='#n175'>175</a>
<a id='n176' href='#n176'>176</a>
<a id='n177' href='#n177'>177</a>
<a id='n178' href='#n178'>178</a>
<a id='n179' href='#n179'>179</a>
<a id='n180' href='#n180'>180</a>
<a id='n181' href='#n181'>181</a>
<a id='n182' href='#n182'>182</a>
<a id='n183' href='#n183'>183</a>
<a id='n184' href='#n184'>184</a>
<a id='n185' href='#n185'>185</a>
<a id='n186' href='#n186'>186</a>
<a id='n187' href='#n187'>187</a>
<a id='n188' href='#n188'>188</a>
<a id='n189' href='#n189'>189</a>
<a id='n190' href='#n190'>190</a>
<a id='n191' href='#n191'>191</a>
<a id='n192' href='#n192'>192</a>
<a id='n193' href='#n193'>193</a>
<a id='n194' href='#n194'>194</a>
<a id='n195' href='#n195'>195</a>
<a id='n196' href='#n196'>196</a>
<a id='n197' href='#n197'>197</a>
<a id='n198' href='#n198'>198</a>
<a id='n199' href='#n199'>199</a>
<a id='n200' href='#n200'>200</a>
<a id='n201' href='#n201'>201</a>
<a id='n202' href='#n202'>202</a>
<a id='n203' href='#n203'>203</a>
<a id='n204' href='#n204'>204</a>
<a id='n205' href='#n205'>205</a>
<a id='n206' href='#n206'>206</a>
<a id='n207' href='#n207'>207</a>
<a id='n208' href='#n208'>208</a>
<a id='n209' href='#n209'>209</a>
<a id='n210' href='#n210'>210</a>
<a id='n211' href='#n211'>211</a>
<a id='n212' href='#n212'>212</a>
<a id='n213' href='#n213'>213</a>
<a id='n214' href='#n214'>214</a>
<a id='n215' href='#n215'>215</a>
<a id='n216' href='#n216'>216</a>
<a id='n217' href='#n217'>217</a>
<a id='n218' href='#n218'>218</a>
<a id='n219' href='#n219'>219</a>
<a id='n220' href='#n220'>220</a>
<a id='n221' href='#n221'>221</a>
<a id='n222' href='#n222'>222</a>
<a id='n223' href='#n223'>223</a>
<a id='n224' href='#n224'>224</a>
<a id='n225' href='#n225'>225</a>
<a id='n226' href='#n226'>226</a>
<a id='n227' href='#n227'>227</a>
<a id='n228' href='#n228'>228</a>
<a id='n229' href='#n229'>229</a>
<a id='n230' href='#n230'>230</a>
<a id='n231' href='#n231'>231</a>
<a id='n232' href='#n232'>232</a>
<a id='n233' href='#n233'>233</a>
<a id='n234' href='#n234'>234</a>
<a id='n235' href='#n235'>235</a>
<a id='n236' href='#n236'>236</a>
<a id='n237' href='#n237'>237</a>
<a id='n238' href='#n238'>238</a>
<a id='n239' href='#n239'>239</a>
<a id='n240' href='#n240'>240</a>
<a id='n241' href='#n241'>241</a>
<a id='n242' href='#n242'>242</a>
<a id='n243' href='#n243'>243</a>
<a id='n244' href='#n244'>244</a>
<a id='n245' href='#n245'>245</a>
<a id='n246' href='#n246'>246</a>
<a id='n247' href='#n247'>247</a>
<a id='n248' href='#n248'>248</a>
<a id='n249' href='#n249'>249</a>
<a id='n250' href='#n250'>250</a>
<a id='n251' href='#n251'>251</a>
<a id='n252' href='#n252'>252</a>
<a id='n253' href='#n253'>253</a>
<a id='n254' href='#n254'>254</a>
<a id='n255' href='#n255'>255</a>
<a id='n256' href='#n256'>256</a>
<a id='n257' href='#n257'>257</a>
<a id='n258' href='#n258'>258</a>
<a id='n259' href='#n259'>259</a>
<a id='n260' href='#n260'>260</a>
<a id='n261' href='#n261'>261</a>
<a id='n262' href='#n262'>262</a>
<a id='n263' href='#n263'>263</a>
<a id='n264' href='#n264'>264</a>
<a id='n265' href='#n265'>265</a>
<a id='n266' href='#n266'>266</a>
<a id='n267' href='#n267'>267</a>
<a id='n268' href='#n268'>268</a>
<a id='n269' href='#n269'>269</a>
<a id='n270' href='#n270'>270</a>
<a id='n271' href='#n271'>271</a>
<a id='n272' href='#n272'>272</a>
<a id='n273' href='#n273'>273</a>
<a id='n274' href='#n274'>274</a>
<a id='n275' href='#n275'>275</a>
<a id='n276' href='#n276'>276</a>
<a id='n277' href='#n277'>277</a>
<a id='n278' href='#n278'>278</a>
<a id='n279' href='#n279'>279</a>
<a id='n280' href='#n280'>280</a>
<a id='n281' href='#n281'>281</a>
<a id='n282' href='#n282'>282</a>
<a id='n283' href='#n283'>283</a>
<a id='n284' href='#n284'>284</a>
<a id='n285' href='#n285'>285</a>
<a id='n286' href='#n286'>286</a>
<a id='n287' href='#n287'>287</a>
<a id='n288' href='#n288'>288</a>
<a id='n289' href='#n289'>289</a>
<a id='n290' href='#n290'>290</a>
<a id='n291' href='#n291'>291</a>
<a id='n292' href='#n292'>292</a>
<a id='n293' href='#n293'>293</a>
<a id='n294' href='#n294'>294</a>
<a id='n295' href='#n295'>295</a>
<a id='n296' href='#n296'>296</a>
<a id='n297' href='#n297'>297</a>
<a id='n298' href='#n298'>298</a>
<a id='n299' href='#n299'>299</a>
<a id='n300' href='#n300'>300</a>
<a id='n301' href='#n301'>301</a>
<a id='n302' href='#n302'>302</a>
<a id='n303' href='#n303'>303</a>
<a id='n304' href='#n304'>304</a>
<a id='n305' href='#n305'>305</a>
<a id='n306' href='#n306'>306</a>
<a id='n307' href='#n307'>307</a>
<a id='n308' href='#n308'>308</a>
<a id='n309' href='#n309'>309</a>
<a id='n310' href='#n310'>310</a>
<a id='n311' href='#n311'>311</a>
<a id='n312' href='#n312'>312</a>
<a id='n313' href='#n313'>313</a>
<a id='n314' href='#n314'>314</a>
<a id='n315' href='#n315'>315</a>
<a id='n316' href='#n316'>316</a>
<a id='n317' href='#n317'>317</a>
<a id='n318' href='#n318'>318</a>
<a id='n319' href='#n319'>319</a>
<a id='n320' href='#n320'>320</a>
<a id='n321' href='#n321'>321</a>
<a id='n322' href='#n322'>322</a>
<a id='n323' href='#n323'>323</a>
<a id='n324' href='#n324'>324</a>
<a id='n325' href='#n325'>325</a>
<a id='n326' href='#n326'>326</a>
<a id='n327' href='#n327'>327</a>
<a id='n328' href='#n328'>328</a>
<a id='n329' href='#n329'>329</a>
<a id='n330' href='#n330'>330</a>
<a id='n331' href='#n331'>331</a>
<a id='n332' href='#n332'>332</a>
<a id='n333' href='#n333'>333</a>
<a id='n334' href='#n334'>334</a>
<a id='n335' href='#n335'>335</a>
<a id='n336' href='#n336'>336</a>
<a id='n337' href='#n337'>337</a>
<a id='n338' href='#n338'>338</a>
<a id='n339' href='#n339'>339</a>
<a id='n340' href='#n340'>340</a>
<a id='n341' href='#n341'>341</a>
<a id='n342' href='#n342'>342</a>
<a id='n343' href='#n343'>343</a>
<a id='n344' href='#n344'>344</a>
<a id='n345' href='#n345'>345</a>
<a id='n346' href='#n346'>346</a>
<a id='n347' href='#n347'>347</a>
<a id='n348' href='#n348'>348</a>
<a id='n349' href='#n349'>349</a>
<a id='n350' href='#n350'>350</a>
<a id='n351' href='#n351'>351</a>
<a id='n352' href='#n352'>352</a>
<a id='n353' href='#n353'>353</a>
<a id='n354' href='#n354'>354</a>
<a id='n355' href='#n355'>355</a>
<a id='n356' href='#n356'>356</a>
<a id='n357' href='#n357'>357</a>
<a id='n358' href='#n358'>358</a>
<a id='n359' href='#n359'>359</a>
<a id='n360' href='#n360'>360</a>
<a id='n361' href='#n361'>361</a>
<a id='n362' href='#n362'>362</a>
<a id='n363' href='#n363'>363</a>
<a id='n364' href='#n364'>364</a>
<a id='n365' href='#n365'>365</a>
<a id='n366' href='#n366'>366</a>
<a id='n367' href='#n367'>367</a>
<a id='n368' href='#n368'>368</a>
<a id='n369' href='#n369'>369</a>
<a id='n370' href='#n370'>370</a>
<a id='n371' href='#n371'>371</a>
<a id='n372' href='#n372'>372</a>
<a id='n373' href='#n373'>373</a>
<a id='n374' href='#n374'>374</a>
<a id='n375' href='#n375'>375</a>
<a id='n376' href='#n376'>376</a>
<a id='n377' href='#n377'>377</a>
<a id='n378' href='#n378'>378</a>
<a id='n379' href='#n379'>379</a>
<a id='n380' href='#n380'>380</a>
<a id='n381' href='#n381'>381</a>
<a id='n382' href='#n382'>382</a>
<a id='n383' href='#n383'>383</a>
<a id='n384' href='#n384'>384</a>
<a id='n385' href='#n385'>385</a>
<a id='n386' href='#n386'>386</a>
<a id='n387' href='#n387'>387</a>
<a id='n388' href='#n388'>388</a>
<a id='n389' href='#n389'>389</a>
<a id='n390' href='#n390'>390</a>
<a id='n391' href='#n391'>391</a>
<a id='n392' href='#n392'>392</a>
<a id='n393' href='#n393'>393</a>
<a id='n394' href='#n394'>394</a>
<a id='n395' href='#n395'>395</a>
<a id='n396' href='#n396'>396</a>
<a id='n397' href='#n397'>397</a>
<a id='n398' href='#n398'>398</a>
<a id='n399' href='#n399'>399</a>
<a id='n400' href='#n400'>400</a>
<a id='n401' href='#n401'>401</a>
<a id='n402' href='#n402'>402</a>
<a id='n403' href='#n403'>403</a>
<a id='n404' href='#n404'>404</a>
<a id='n405' href='#n405'>405</a>
<a id='n406' href='#n406'>406</a>
<a id='n407' href='#n407'>407</a>
<a id='n408' href='#n408'>408</a>
<a id='n409' href='#n409'>409</a>
<a id='n410' href='#n410'>410</a>
<a id='n411' href='#n411'>411</a>
<a id='n412' href='#n412'>412</a>
<a id='n413' href='#n413'>413</a>
<a id='n414' href='#n414'>414</a>
<a id='n415' href='#n415'>415</a>
<a id='n416' href='#n416'>416</a>
<a id='n417' href='#n417'>417</a>
<a id='n418' href='#n418'>418</a>
<a id='n419' href='#n419'>419</a>
<a id='n420' href='#n420'>420</a>
<a id='n421' href='#n421'>421</a>
<a id='n422' href='#n422'>422</a>
<a id='n423' href='#n423'>423</a>
<a id='n424' href='#n424'>424</a>
<a id='n425' href='#n425'>425</a>
<a id='n426' href='#n426'>426</a>
<a id='n427' href='#n427'>427</a>
<a id='n428' href='#n428'>428</a>
<a id='n429' href='#n429'>429</a>
<a id='n430' href='#n430'>430</a>
<a id='n431' href='#n431'>431</a>
<a id='n432' href='#n432'>432</a>
<a id='n433' href='#n433'>433</a>
<a id='n434' href='#n434'>434</a>
<a id='n435' href='#n435'>435</a>
<a id='n436' href='#n436'>436</a>
<a id='n437' href='#n437'>437</a>
<a id='n438' href='#n438'>438</a>
<a id='n439' href='#n439'>439</a>
<a id='n440' href='#n440'>440</a>
<a id='n441' href='#n441'>441</a>
<a id='n442' href='#n442'>442</a>
<a id='n443' href='#n443'>443</a>
<a id='n444' href='#n444'>444</a>
<a id='n445' href='#n445'>445</a>
<a id='n446' href='#n446'>446</a>
<a id='n447' href='#n447'>447</a>
<a id='n448' href='#n448'>448</a>
<a id='n449' href='#n449'>449</a>
<a id='n450' href='#n450'>450</a>
<a id='n451' href='#n451'>451</a>
<a id='n452' href='#n452'>452</a>
<a id='n453' href='#n453'>453</a>
<a id='n454' href='#n454'>454</a>
<a id='n455' href='#n455'>455</a>
<a id='n456' href='#n456'>456</a>
<a id='n457' href='#n457'>457</a>
<a id='n458' href='#n458'>458</a>
<a id='n459' href='#n459'>459</a>
<a id='n460' href='#n460'>460</a>
<a id='n461' href='#n461'>461</a>
<a id='n462' href='#n462'>462</a>
<a id='n463' href='#n463'>463</a>
<a id='n464' href='#n464'>464</a>
<a id='n465' href='#n465'>465</a>
<a id='n466' href='#n466'>466</a>
<a id='n467' href='#n467'>467</a>
<a id='n468' href='#n468'>468</a>
<a id='n469' href='#n469'>469</a>
<a id='n470' href='#n470'>470</a>
<a id='n471' href='#n471'>471</a>
<a id='n472' href='#n472'>472</a>
<a id='n473' href='#n473'>473</a>
<a id='n474' href='#n474'>474</a>
<a id='n475' href='#n475'>475</a>
<a id='n476' href='#n476'>476</a>
<a id='n477' href='#n477'>477</a>
<a id='n478' href='#n478'>478</a>
<a id='n479' href='#n479'>479</a>
<a id='n480' href='#n480'>480</a>
<a id='n481' href='#n481'>481</a>
<a id='n482' href='#n482'>482</a>
<a id='n483' href='#n483'>483</a>
<a id='n484' href='#n484'>484</a>
<a id='n485' href='#n485'>485</a>
<a id='n486' href='#n486'>486</a>
<a id='n487' href='#n487'>487</a>
<a id='n488' href='#n488'>488</a>
<a id='n489' href='#n489'>489</a>
<a id='n490' href='#n490'>490</a>
<a id='n491' href='#n491'>491</a>
<a id='n492' href='#n492'>492</a>
<a id='n493' href='#n493'>493</a>
<a id='n494' href='#n494'>494</a>
<a id='n495' href='#n495'>495</a>
<a id='n496' href='#n496'>496</a>
<a id='n497' href='#n497'>497</a>
<a id='n498' href='#n498'>498</a>
<a id='n499' href='#n499'>499</a>
<a id='n500' href='#n500'>500</a>
<a id='n501' href='#n501'>501</a>
<a id='n502' href='#n502'>502</a>
<a id='n503' href='#n503'>503</a>
<a id='n504' href='#n504'>504</a>
<a id='n505' href='#n505'>505</a>
<a id='n506' href='#n506'>506</a>
<a id='n507' href='#n507'>507</a>
<a id='n508' href='#n508'>508</a>
<a id='n509' href='#n509'>509</a>
<a id='n510' href='#n510'>510</a>
<a id='n511' href='#n511'>511</a>
<a id='n512' href='#n512'>512</a>
<a id='n513' href='#n513'>513</a>
<a id='n514' href='#n514'>514</a>
<a id='n515' href='#n515'>515</a>
<a id='n516' href='#n516'>516</a>
<a id='n517' href='#n517'>517</a>
<a id='n518' href='#n518'>518</a>
<a id='n519' href='#n519'>519</a>
<a id='n520' href='#n520'>520</a>
<a id='n521' href='#n521'>521</a>
<a id='n522' href='#n522'>522</a>
<a id='n523' href='#n523'>523</a>
<a id='n524' href='#n524'>524</a>
<a id='n525' href='#n525'>525</a>
<a id='n526' href='#n526'>526</a>
<a id='n527' href='#n527'>527</a>
<a id='n528' href='#n528'>528</a>
<a id='n529' href='#n529'>529</a>
<a id='n530' href='#n530'>530</a>
<a id='n531' href='#n531'>531</a>
<a id='n532' href='#n532'>532</a>
<a id='n533' href='#n533'>533</a>
<a id='n534' href='#n534'>534</a>
<a id='n535' href='#n535'>535</a>
<a id='n536' href='#n536'>536</a>
<a id='n537' href='#n537'>537</a>
<a id='n538' href='#n538'>538</a>
<a id='n539' href='#n539'>539</a>
<a id='n540' href='#n540'>540</a>
<a id='n541' href='#n541'>541</a>
<a id='n542' href='#n542'>542</a>
<a id='n543' href='#n543'>543</a>
<a id='n544' href='#n544'>544</a>
<a id='n545' href='#n545'>545</a>
<a id='n546' href='#n546'>546</a>
<a id='n547' href='#n547'>547</a>
<a id='n548' href='#n548'>548</a>
<a id='n549' href='#n549'>549</a>
<a id='n550' href='#n550'>550</a>
<a id='n551' href='#n551'>551</a>
<a id='n552' href='#n552'>552</a>
<a id='n553' href='#n553'>553</a>
<a id='n554' href='#n554'>554</a>
<a id='n555' href='#n555'>555</a>
<a id='n556' href='#n556'>556</a>
<a id='n557' href='#n557'>557</a>
<a id='n558' href='#n558'>558</a>
<a id='n559' href='#n559'>559</a>
<a id='n560' href='#n560'>560</a>
<a id='n561' href='#n561'>561</a>
<a id='n562' href='#n562'>562</a>
<a id='n563' href='#n563'>563</a>
<a id='n564' href='#n564'>564</a>
<a id='n565' href='#n565'>565</a>
<a id='n566' href='#n566'>566</a>
<a id='n567' href='#n567'>567</a>
<a id='n568' href='#n568'>568</a>
<a id='n569' href='#n569'>569</a>
<a id='n570' href='#n570'>570</a>
<a id='n571' href='#n571'>571</a>
<a id='n572' href='#n572'>572</a>
<a id='n573' href='#n573'>573</a>
<a id='n574' href='#n574'>574</a>
<a id='n575' href='#n575'>575</a>
<a id='n576' href='#n576'>576</a>
<a id='n577' href='#n577'>577</a>
<a id='n578' href='#n578'>578</a>
<a id='n579' href='#n579'>579</a>
<a id='n580' href='#n580'>580</a>
<a id='n581' href='#n581'>581</a>
<a id='n582' href='#n582'>582</a>
<a id='n583' href='#n583'>583</a>
<a id='n584' href='#n584'>584</a>
<a id='n585' href='#n585'>585</a>
<a id='n586' href='#n586'>586</a>
<a id='n587' href='#n587'>587</a>
<a id='n588' href='#n588'>588</a>
<a id='n589' href='#n589'>589</a>
<a id='n590' href='#n590'>590</a>
<a id='n591' href='#n591'>591</a>
<a id='n592' href='#n592'>592</a>
<a id='n593' href='#n593'>593</a>
<a id='n594' href='#n594'>594</a>
<a id='n595' href='#n595'>595</a>
<a id='n596' href='#n596'>596</a>
<a id='n597' href='#n597'>597</a>
<a id='n598' href='#n598'>598</a>
<a id='n599' href='#n599'>599</a>
<a id='n600' href='#n600'>600</a>
<a id='n601' href='#n601'>601</a>
<a id='n602' href='#n602'>602</a>
<a id='n603' href='#n603'>603</a>
<a id='n604' href='#n604'>604</a>
<a id='n605' href='#n605'>605</a>
<a id='n606' href='#n606'>606</a>
<a id='n607' href='#n607'>607</a>
<a id='n608' href='#n608'>608</a>
<a id='n609' href='#n609'>609</a>
<a id='n610' href='#n610'>610</a>
<a id='n611' href='#n611'>611</a>
<a id='n612' href='#n612'>612</a>
<a id='n613' href='#n613'>613</a>
<a id='n614' href='#n614'>614</a>
<a id='n615' href='#n615'>615</a>
<a id='n616' href='#n616'>616</a>
<a id='n617' href='#n617'>617</a>
<a id='n618' href='#n618'>618</a>
<a id='n619' href='#n619'>619</a>
<a id='n620' href='#n620'>620</a>
<a id='n621' href='#n621'>621</a>
<a id='n622' href='#n622'>622</a>
<a id='n623' href='#n623'>623</a>
<a id='n624' href='#n624'>624</a>
<a id='n625' href='#n625'>625</a>
<a id='n626' href='#n626'>626</a>
<a id='n627' href='#n627'>627</a>
<a id='n628' href='#n628'>628</a>
<a id='n629' href='#n629'>629</a>
<a id='n630' href='#n630'>630</a>
<a id='n631' href='#n631'>631</a>
<a id='n632' href='#n632'>632</a>
<a id='n633' href='#n633'>633</a>
<a id='n634' href='#n634'>634</a>
<a id='n635' href='#n635'>635</a>
<a id='n636' href='#n636'>636</a>
<a id='n637' href='#n637'>637</a>
<a id='n638' href='#n638'>638</a>
<a id='n639' href='#n639'>639</a>
<a id='n640' href='#n640'>640</a>
<a id='n641' href='#n641'>641</a>
<a id='n642' href='#n642'>642</a>
<a id='n643' href='#n643'>643</a>
<a id='n644' href='#n644'>644</a>
<a id='n645' href='#n645'>645</a>
<a id='n646' href='#n646'>646</a>
<a id='n647' href='#n647'>647</a>
<a id='n648' href='#n648'>648</a>
<a id='n649' href='#n649'>649</a>
<a id='n650' href='#n650'>650</a>
<a id='n651' href='#n651'>651</a>
<a id='n652' href='#n652'>652</a>
<a id='n653' href='#n653'>653</a>
<a id='n654' href='#n654'>654</a>
<a id='n655' href='#n655'>655</a>
<a id='n656' href='#n656'>656</a>
<a id='n657' href='#n657'>657</a>
<a id='n658' href='#n658'>658</a>
<a id='n659' href='#n659'>659</a>
<a id='n660' href='#n660'>660</a>
<a id='n661' href='#n661'>661</a>
<a id='n662' href='#n662'>662</a>
<a id='n663' href='#n663'>663</a>
<a id='n664' href='#n664'>664</a>
<a id='n665' href='#n665'>665</a>
<a id='n666' href='#n666'>666</a>
<a id='n667' href='#n667'>667</a>
<a id='n668' href='#n668'>668</a>
<a id='n669' href='#n669'>669</a>
<a id='n670' href='#n670'>670</a>
<a id='n671' href='#n671'>671</a>
<a id='n672' href='#n672'>672</a>
<a id='n673' href='#n673'>673</a>
<a id='n674' href='#n674'>674</a>
<a id='n675' href='#n675'>675</a>
<a id='n676' href='#n676'>676</a>
<a id='n677' href='#n677'>677</a>
<a id='n678' href='#n678'>678</a>
<a id='n679' href='#n679'>679</a>
<a id='n680' href='#n680'>680</a>
<a id='n681' href='#n681'>681</a>
<a id='n682' href='#n682'>682</a>
<a id='n683' href='#n683'>683</a>
<a id='n684' href='#n684'>684</a>
<a id='n685' href='#n685'>685</a>
<a id='n686' href='#n686'>686</a>
<a id='n687' href='#n687'>687</a>
<a id='n688' href='#n688'>688</a>
<a id='n689' href='#n689'>689</a>
<a id='n690' href='#n690'>690</a>
<a id='n691' href='#n691'>691</a>
<a id='n692' href='#n692'>692</a>
<a id='n693' href='#n693'>693</a>
<a id='n694' href='#n694'>694</a>
<a id='n695' href='#n695'>695</a>
<a id='n696' href='#n696'>696</a>
<a id='n697' href='#n697'>697</a>
<a id='n698' href='#n698'>698</a>
<a id='n699' href='#n699'>699</a>
<a id='n700' href='#n700'>700</a>
<a id='n701' href='#n701'>701</a>
<a id='n702' href='#n702'>702</a>
<a id='n703' href='#n703'>703</a>
<a id='n704' href='#n704'>704</a>
<a id='n705' href='#n705'>705</a>
<a id='n706' href='#n706'>706</a>
<a id='n707' href='#n707'>707</a>
<a id='n708' href='#n708'>708</a>
<a id='n709' href='#n709'>709</a>
<a id='n710' href='#n710'>710</a>
<a id='n711' href='#n711'>711</a>
<a id='n712' href='#n712'>712</a>
<a id='n713' href='#n713'>713</a>
<a id='n714' href='#n714'>714</a>
<a id='n715' href='#n715'>715</a>
<a id='n716' href='#n716'>716</a>
<a id='n717' href='#n717'>717</a>
<a id='n718' href='#n718'>718</a>
<a id='n719' href='#n719'>719</a>
<a id='n720' href='#n720'>720</a>
<a id='n721' href='#n721'>721</a>
<a id='n722' href='#n722'>722</a>
<a id='n723' href='#n723'>723</a>
<a id='n724' href='#n724'>724</a>
<a id='n725' href='#n725'>725</a>
<a id='n726' href='#n726'>726</a>
<a id='n727' href='#n727'>727</a>
<a id='n728' href='#n728'>728</a>
<a id='n729' href='#n729'>729</a>
<a id='n730' href='#n730'>730</a>
<a id='n731' href='#n731'>731</a>
<a id='n732' href='#n732'>732</a>
<a id='n733' href='#n733'>733</a>
<a id='n734' href='#n734'>734</a>
<a id='n735' href='#n735'>735</a>
<a id='n736' href='#n736'>736</a>
<a id='n737' href='#n737'>737</a>
<a id='n738' href='#n738'>738</a>
<a id='n739' href='#n739'>739</a>
<a id='n740' href='#n740'>740</a>
<a id='n741' href='#n741'>741</a>
<a id='n742' href='#n742'>742</a>
<a id='n743' href='#n743'>743</a>
<a id='n744' href='#n744'>744</a>
<a id='n745' href='#n745'>745</a>
<a id='n746' href='#n746'>746</a>
<a id='n747' href='#n747'>747</a>
<a id='n748' href='#n748'>748</a>
<a id='n749' href='#n749'>749</a>
<a id='n750' href='#n750'>750</a>
<a id='n751' href='#n751'>751</a>
<a id='n752' href='#n752'>752</a>
<a id='n753' href='#n753'>753</a>
<a id='n754' href='#n754'>754</a>
<a id='n755' href='#n755'>755</a>
<a id='n756' href='#n756'>756</a>
<a id='n757' href='#n757'>757</a>
<a id='n758' href='#n758'>758</a>
<a id='n759' href='#n759'>759</a>
<a id='n760' href='#n760'>760</a>
<a id='n761' href='#n761'>761</a>
<a id='n762' href='#n762'>762</a>
<a id='n763' href='#n763'>763</a>
<a id='n764' href='#n764'>764</a>
<a id='n765' href='#n765'>765</a>
<a id='n766' href='#n766'>766</a>
<a id='n767' href='#n767'>767</a>
<a id='n768' href='#n768'>768</a>
<a id='n769' href='#n769'>769</a>
<a id='n770' href='#n770'>770</a>
<a id='n771' href='#n771'>771</a>
<a id='n772' href='#n772'>772</a>
<a id='n773' href='#n773'>773</a>
<a id='n774' href='#n774'>774</a>
<a id='n775' href='#n775'>775</a>
<a id='n776' href='#n776'>776</a>
<a id='n777' href='#n777'>777</a>
<a id='n778' href='#n778'>778</a>
<a id='n779' href='#n779'>779</a>
<a id='n780' href='#n780'>780</a>
<a id='n781' href='#n781'>781</a>
<a id='n782' href='#n782'>782</a>
<a id='n783' href='#n783'>783</a>
<a id='n784' href='#n784'>784</a>
<a id='n785' href='#n785'>785</a>
<a id='n786' href='#n786'>786</a>
<a id='n787' href='#n787'>787</a>
<a id='n788' href='#n788'>788</a>
<a id='n789' href='#n789'>789</a>
<a id='n790' href='#n790'>790</a>
<a id='n791' href='#n791'>791</a>
<a id='n792' href='#n792'>792</a>
<a id='n793' href='#n793'>793</a>
<a id='n794' href='#n794'>794</a>
<a id='n795' href='#n795'>795</a>
<a id='n796' href='#n796'>796</a>
<a id='n797' href='#n797'>797</a>
<a id='n798' href='#n798'>798</a>
<a id='n799' href='#n799'>799</a>
<a id='n800' href='#n800'>800</a>
<a id='n801' href='#n801'>801</a>
<a id='n802' href='#n802'>802</a>
<a id='n803' href='#n803'>803</a>
<a id='n804' href='#n804'>804</a>
<a id='n805' href='#n805'>805</a>
<a id='n806' href='#n806'>806</a>
<a id='n807' href='#n807'>807</a>
<a id='n808' href='#n808'>808</a>
<a id='n809' href='#n809'>809</a>
<a id='n810' href='#n810'>810</a>
<a id='n811' href='#n811'>811</a>
<a id='n812' href='#n812'>812</a>
<a id='n813' href='#n813'>813</a>
<a id='n814' href='#n814'>814</a>
<a id='n815' href='#n815'>815</a>
<a id='n816' href='#n816'>816</a>
<a id='n817' href='#n817'>817</a>
<a id='n818' href='#n818'>818</a>
<a id='n819' href='#n819'>819</a>
<a id='n820' href='#n820'>820</a>
<a id='n821' href='#n821'>821</a>
<a id='n822' href='#n822'>822</a>
<a id='n823' href='#n823'>823</a>
<a id='n824' href='#n824'>824</a>
<a id='n825' href='#n825'>825</a>
<a id='n826' href='#n826'>826</a>
<a id='n827' href='#n827'>827</a>
<a id='n828' href='#n828'>828</a>
<a id='n829' href='#n829'>829</a>
<a id='n830' href='#n830'>830</a>
<a id='n831' href='#n831'>831</a>
<a id='n832' href='#n832'>832</a>
<a id='n833' href='#n833'>833</a>
<a id='n834' href='#n834'>834</a>
<a id='n835' href='#n835'>835</a>
<a id='n836' href='#n836'>836</a>
<a id='n837' href='#n837'>837</a>
<a id='n838' href='#n838'>838</a>
<a id='n839' href='#n839'>839</a>
<a id='n840' href='#n840'>840</a>
<a id='n841' href='#n841'>841</a>
<a id='n842' href='#n842'>842</a>
<a id='n843' href='#n843'>843</a>
<a id='n844' href='#n844'>844</a>
<a id='n845' href='#n845'>845</a>
<a id='n846' href='#n846'>846</a>
<a id='n847' href='#n847'>847</a>
<a id='n848' href='#n848'>848</a>
<a id='n849' href='#n849'>849</a>
<a id='n850' href='#n850'>850</a>
<a id='n851' href='#n851'>851</a>
<a id='n852' href='#n852'>852</a>
<a id='n853' href='#n853'>853</a>
<a id='n854' href='#n854'>854</a>
<a id='n855' href='#n855'>855</a>
<a id='n856' href='#n856'>856</a>
<a id='n857' href='#n857'>857</a>
<a id='n858' href='#n858'>858</a>
<a id='n859' href='#n859'>859</a>
<a id='n860' href='#n860'>860</a>
<a id='n861' href='#n861'>861</a>
<a id='n862' href='#n862'>862</a>
<a id='n863' href='#n863'>863</a>
<a id='n864' href='#n864'>864</a>
<a id='n865' href='#n865'>865</a>
<a id='n866' href='#n866'>866</a>
<a id='n867' href='#n867'>867</a>
<a id='n868' href='#n868'>868</a>
<a id='n869' href='#n869'>869</a>
<a id='n870' href='#n870'>870</a>
<a id='n871' href='#n871'>871</a>
<a id='n872' href='#n872'>872</a>
<a id='n873' href='#n873'>873</a>
<a id='n874' href='#n874'>874</a>
<a id='n875' href='#n875'>875</a>
<a id='n876' href='#n876'>876</a>
<a id='n877' href='#n877'>877</a>
<a id='n878' href='#n878'>878</a>
<a id='n879' href='#n879'>879</a>
<a id='n880' href='#n880'>880</a>
<a id='n881' href='#n881'>881</a>
<a id='n882' href='#n882'>882</a>
<a id='n883' href='#n883'>883</a>
<a id='n884' href='#n884'>884</a>
<a id='n885' href='#n885'>885</a>
<a id='n886' href='#n886'>886</a>
<a id='n887' href='#n887'>887</a>
<a id='n888' href='#n888'>888</a>
<a id='n889' href='#n889'>889</a>
<a id='n890' href='#n890'>890</a>
<a id='n891' href='#n891'>891</a>
<a id='n892' href='#n892'>892</a>
<a id='n893' href='#n893'>893</a>
<a id='n894' href='#n894'>894</a>
<a id='n895' href='#n895'>895</a>
<a id='n896' href='#n896'>896</a>
<a id='n897' href='#n897'>897</a>
<a id='n898' href='#n898'>898</a>
<a id='n899' href='#n899'>899</a>
<a id='n900' href='#n900'>900</a>
<a id='n901' href='#n901'>901</a>
<a id='n902' href='#n902'>902</a>
<a id='n903' href='#n903'>903</a>
<a id='n904' href='#n904'>904</a>
<a id='n905' href='#n905'>905</a>
<a id='n906' href='#n906'>906</a>
<a id='n907' href='#n907'>907</a>
<a id='n908' href='#n908'>908</a>
<a id='n909' href='#n909'>909</a>
<a id='n910' href='#n910'>910</a>
<a id='n911' href='#n911'>911</a>
<a id='n912' href='#n912'>912</a>
<a id='n913' href='#n913'>913</a>
<a id='n914' href='#n914'>914</a>
<a id='n915' href='#n915'>915</a>
<a id='n916' href='#n916'>916</a>
<a id='n917' href='#n917'>917</a>
<a id='n918' href='#n918'>918</a>
<a id='n919' href='#n919'>919</a>
<a id='n920' href='#n920'>920</a>
<a id='n921' href='#n921'>921</a>
<a id='n922' href='#n922'>922</a>
<a id='n923' href='#n923'>923</a>
<a id='n924' href='#n924'>924</a>
<a id='n925' href='#n925'>925</a>
<a id='n926' href='#n926'>926</a>
<a id='n927' href='#n927'>927</a>
<a id='n928' href='#n928'>928</a>
<a id='n929' href='#n929'>929</a>
<a id='n930' href='#n930'>930</a>
<a id='n931' href='#n931'>931</a>
<a id='n932' href='#n932'>932</a>
<a id='n933' href='#n933'>933</a>
<a id='n934' href='#n934'>934</a>
<a id='n935' href='#n935'>935</a>
<a id='n936' href='#n936'>936</a>
<a id='n937' href='#n937'>937</a>
<a id='n938' href='#n938'>938</a>
<a id='n939' href='#n939'>939</a>
<a id='n940' href='#n940'>940</a>
<a id='n941' href='#n941'>941</a>
<a id='n942' href='#n942'>942</a>
<a id='n943' href='#n943'>943</a>
<a id='n944' href='#n944'>944</a>
<a id='n945' href='#n945'>945</a>
<a id='n946' href='#n946'>946</a>
<a id='n947' href='#n947'>947</a>
<a id='n948' href='#n948'>948</a>
<a id='n949' href='#n949'>949</a>
<a id='n950' href='#n950'>950</a>
<a id='n951' href='#n951'>951</a>
<a id='n952' href='#n952'>952</a>
<a id='n953' href='#n953'>953</a>
<a id='n954' href='#n954'>954</a>
<a id='n955' href='#n955'>955</a>
<a id='n956' href='#n956'>956</a>
<a id='n957' href='#n957'>957</a>
<a id='n958' href='#n958'>958</a>
<a id='n959' href='#n959'>959</a>
<a id='n960' href='#n960'>960</a>
<a id='n961' href='#n961'>961</a>
<a id='n962' href='#n962'>962</a>
<a id='n963' href='#n963'>963</a>
<a id='n964' href='#n964'>964</a>
<a id='n965' href='#n965'>965</a>
<a id='n966' href='#n966'>966</a>
<a id='n967' href='#n967'>967</a>
<a id='n968' href='#n968'>968</a>
<a id='n969' href='#n969'>969</a>
<a id='n970' href='#n970'>970</a>
<a id='n971' href='#n971'>971</a>
<a id='n972' href='#n972'>972</a>
<a id='n973' href='#n973'>973</a>
<a id='n974' href='#n974'>974</a>
<a id='n975' href='#n975'>975</a>
<a id='n976' href='#n976'>976</a>
<a id='n977' href='#n977'>977</a>
<a id='n978' href='#n978'>978</a>
<a id='n979' href='#n979'>979</a>
<a id='n980' href='#n980'>980</a>
<a id='n981' href='#n981'>981</a>
<a id='n982' href='#n982'>982</a>
<a id='n983' href='#n983'>983</a>
<a id='n984' href='#n984'>984</a>
<a id='n985' href='#n985'>985</a>
<a id='n986' href='#n986'>986</a>
<a id='n987' href='#n987'>987</a>
<a id='n988' href='#n988'>988</a>
<a id='n989' href='#n989'>989</a>
<a id='n990' href='#n990'>990</a>
<a id='n991' href='#n991'>991</a>
<a id='n992' href='#n992'>992</a>
<a id='n993' href='#n993'>993</a>
<a id='n994' href='#n994'>994</a>
<a id='n995' href='#n995'>995</a>
<a id='n996' href='#n996'>996</a>
<a id='n997' href='#n997'>997</a>
<a id='n998' href='#n998'>998</a>
<a id='n999' href='#n999'>999</a>
<a id='n1000' href='#n1000'>1000</a>
<a id='n1001' href='#n1001'>1001</a>
<a id='n1002' href='#n1002'>1002</a>
<a id='n1003' href='#n1003'>1003</a>
<a id='n1004' href='#n1004'>1004</a>
<a id='n1005' href='#n1005'>1005</a>
<a id='n1006' href='#n1006'>1006</a>
<a id='n1007' href='#n1007'>1007</a>
<a id='n1008' href='#n1008'>1008</a>
<a id='n1009' href='#n1009'>1009</a>
<a id='n1010' href='#n1010'>1010</a>
<a id='n1011' href='#n1011'>1011</a>
<a id='n1012' href='#n1012'>1012</a>
<a id='n1013' href='#n1013'>1013</a>
<a id='n1014' href='#n1014'>1014</a>
<a id='n1015' href='#n1015'>1015</a>
<a id='n1016' href='#n1016'>1016</a>
<a id='n1017' href='#n1017'>1017</a>
<a id='n1018' href='#n1018'>1018</a>
<a id='n1019' href='#n1019'>1019</a>
<a id='n1020' href='#n1020'>1020</a>
<a id='n1021' href='#n1021'>1021</a>
<a id='n1022' href='#n1022'>1022</a>
</pre></td>
<td class='lines'><pre><code><style>
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
</style><div class="highlight"><pre><span></span><span class="k">\documentclass</span><span class="nb">{</span>article<span class="nb">}</span>
<span class="k">\def\version</span><span class="nb">{</span><span class="s">$</span><span class="nb">Id: cdrom</span><span class="o">-</span><span class="nb">standard.tex,v </span><span class="m">1</span><span class="nb">.</span><span class="m">9</span><span class="nb"> </span><span class="m">1997</span><span class="o">/</span><span class="m">12</span><span class="o">/</span><span class="m">28</span><span class="nb"> </span><span class="m">15</span><span class="nb">:</span><span class="m">42</span><span class="nb">:</span><span class="m">49</span><span class="nb"> david Exp </span><span class="s">$</span><span class="nb">}</span>
<span class="k">\newcommand</span><span class="nb">{</span><span class="k">\newsection</span><span class="nb">}</span>[1]<span class="nb">{</span><span class="k">\newpage\section</span><span class="nb">{</span>#1<span class="nb">}}</span>

<span class="k">\evensidemargin</span>=0pt
<span class="k">\oddsidemargin</span>=0pt
<span class="k">\topmargin</span>=-<span class="k">\headheight</span> <span class="k">\advance\topmargin</span> by -<span class="k">\headsep</span>
<span class="k">\textwidth</span>=15.99cm <span class="k">\textheight</span>=24.62cm <span class="c">% normal A4, 1&#39;&#39; margin</span>

<span class="k">\def\linux</span><span class="nb">{{</span><span class="k">\sc</span> Linux<span class="nb">}}</span>
<span class="k">\def\cdrom</span><span class="nb">{{</span><span class="k">\sc</span> cd-rom<span class="nb">}}</span>
<span class="k">\def\UCD</span><span class="nb">{{</span><span class="k">\sc</span> Uniform cd-rom Driver<span class="nb">}}</span>
<span class="k">\def\cdromc</span><span class="nb">{{</span><span class="k">\tt</span> <span class="nb">{</span>cdrom.c<span class="nb">}}}</span>
<span class="k">\def\cdromh</span><span class="nb">{{</span><span class="k">\tt</span> <span class="nb">{</span>cdrom.h<span class="nb">}}}</span>
<span class="k">\def\fo</span><span class="nb">{</span><span class="k">\sl</span><span class="nb">}</span>                    <span class="c">% foreign words</span>
<span class="k">\def\ie</span><span class="nb">{{</span><span class="k">\fo</span> i.e.<span class="nb">}}</span>
<span class="k">\def\eg</span><span class="nb">{{</span><span class="k">\fo</span> e.g.<span class="nb">}}</span>

<span class="k">\everymath</span><span class="nb">{</span><span class="k">\it</span><span class="nb">}</span> <span class="k">\everydisplay</span><span class="nb">{</span><span class="k">\it</span><span class="nb">}</span>
<span class="k">\catcode</span> `<span class="k">\_</span>=<span class="k">\active</span> <span class="k">\def</span><span class="nb">_{</span><span class="k">\_\penalty</span>100 <span class="nb">}</span>
<span class="k">\catcode</span>`<span class="k">\&lt;</span>=<span class="k">\active</span> <span class="k">\def</span>&lt;#1&gt;<span class="nb">{{</span><span class="k">\langle\hbox</span><span class="nb">{</span><span class="k">\rm</span>#1<span class="nb">}</span><span class="k">\rangle</span><span class="nb">}}</span>

<span class="k">\begin</span><span class="nb">{</span>document<span class="nb">}</span>
<span class="k">\title</span><span class="nb">{</span>A <span class="k">\linux\ \cdrom\ </span>standard<span class="nb">}</span>
<span class="k">\author</span><span class="nb">{</span>David van Leeuwen<span class="k">\\</span><span class="nb">{</span><span class="k">\normalsize\tt</span> david@ElseWare.cistron.nl<span class="nb">}</span>
<span class="k">\\</span><span class="nb">{</span><span class="k">\footnotesize</span> updated by Erik Andersen <span class="nb">{</span><span class="k">\tt</span>(andersee@debian.org)<span class="nb">}}</span>
<span class="k">\\</span><span class="nb">{</span><span class="k">\footnotesize</span> updated by Jens Axboe <span class="nb">{</span><span class="k">\tt</span>(axboe@image.dk)<span class="nb">}}}</span>
<span class="k">\date</span><span class="nb">{</span>12 March 1999<span class="nb">}</span>

<span class="k">\maketitle</span>

<span class="k">\newsection</span><span class="nb">{</span>Introduction<span class="nb">}</span>

<span class="k">\linux\ </span>is probably the Unix-like operating system that supports
the widest variety of hardware devices. The reasons for this are
presumably 
<span class="k">\begin</span><span class="nb">{</span>itemize<span class="nb">}</span> 
<span class="k">\item</span> 
  The large list of hardware devices available for the many platforms
  that <span class="k">\linux\ </span>now supports (<span class="k">\ie</span>, i386-PCs, Sparc Suns, etc.)
<span class="k">\item</span> 
  The open design of the operating system, such that anybody can write a
  driver for <span class="k">\linux</span>.
<span class="k">\item</span> 
  There is plenty of source code around as examples of how to write a driver.
<span class="k">\end</span><span class="nb">{</span>itemize<span class="nb">}</span>
The openness of <span class="k">\linux</span>, and the many different types of available
hardware has allowed <span class="k">\linux\ </span>to support many different hardware devices.
Unfortunately, the very openness that has allowed <span class="k">\linux\ </span>to support
all these different devices has also allowed the behavior of each
device driver to differ significantly from one device to another.
This divergence of behavior has been very significant for <span class="k">\cdrom\</span>
devices; the way a particular drive reacts to a `standard&#39; <span class="s">$</span><span class="nb">ioctl</span><span class="o">()</span><span class="s">$</span>
call varies greatly from one device driver to another. To avoid making
their drivers totally inconsistent, the writers of <span class="k">\linux\ \cdrom\</span>
drivers generally created new device drivers by understanding, copying,
and then changing an existing one. Unfortunately, this practice did not
maintain uniform behavior across all the <span class="k">\linux\ \cdrom\ </span>drivers. 

This document describes an effort to establish Uniform behavior across
all the different <span class="k">\cdrom\ </span>device drivers for <span class="k">\linux</span>. This document also
defines the various <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s, and how the low-level <span class="k">\cdrom\ </span>device
drivers should implement them. Currently (as of the <span class="k">\linux\ </span>2.1.<span class="s">$</span><span class="nb">x</span><span class="s">$</span>
development kernels) several low-level <span class="k">\cdrom\ </span>device drivers, including
both IDE/ATAPI and SCSI, now use this Uniform interface.

When the <span class="k">\cdrom\ </span>was developed, the interface between the <span class="k">\cdrom\ </span>drive
and the computer was not specified in the standards. As a result, many
different <span class="k">\cdrom\ </span>interfaces were developed. Some of them had their
own proprietary design (Sony, Mitsumi, Panasonic, Philips), other
manufacturers adopted an existing electrical interface and changed
the functionality (CreativeLabs/SoundBlaster, Teac, Funai) or simply
adapted their drives to one or more of the already existing electrical
interfaces (Aztech, Sanyo, Funai, Vertos, Longshine, Optics Storage and
most of the `NoName&#39; manufacturers). In cases where a new drive really
brought its own interface or used its own command set and flow control
scheme, either a separate driver had to be written, or an existing
driver had to be enhanced. History has delivered us <span class="k">\cdrom\ </span>support for
many of these different interfaces. Nowadays, almost all new <span class="k">\cdrom\</span>
drives are either IDE/ATAPI or SCSI, and it is very unlikely that any
manufacturer will create a new interface. Even finding drives for the
old proprietary interfaces is getting difficult.

When (in the 1.3.70&#39;s) I looked at the existing software interface,
which was expressed through <span class="k">\cdromh</span>, it appeared to be a rather wild
set of commands and data formats.<span class="k">\footnote</span><span class="nb">{</span>I cannot recollect what
kernel version I looked at, then, presumably 1.2.13 and 1.3.34---the
latest kernel that I was indirectly involved in.<span class="nb">}</span> It seemed that many
features of the software interface had been added to accommodate the
capabilities of a particular drive, in an <span class="nb">{</span><span class="k">\fo</span> ad hoc<span class="k">\/</span><span class="nb">}</span> manner. More
importantly, it appeared that the behavior of the `standard&#39; commands
was different for most of the different drivers: <span class="k">\eg</span>, some drivers
close the tray if an <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> call occurs when the tray is open, while
others do not. Some drivers lock the door upon opening the device, to
prevent an incoherent file system, but others don&#39;t, to allow software
ejection. Undoubtedly, the capabilities of the different drives vary,
but even when two drives have the same capability their drivers&#39;
behavior was usually different.

I decided to start a discussion on how to make all the <span class="k">\linux\ \cdrom\</span>
drivers behave more uniformly. I began by contacting the developers of
the many <span class="k">\cdrom\ </span>drivers found in the <span class="k">\linux\ </span>kernel. Their reactions
encouraged me to write the <span class="k">\UCD\ </span>which this document is intended to
describe. The implementation of the <span class="k">\UCD\ </span>is in the file <span class="k">\cdromc</span>. This
driver is intended to be an additional software layer that sits on top
of the low-level device drivers for each <span class="k">\cdrom\ </span>drive. By adding this
additional layer, it is possible to have all the different <span class="k">\cdrom\</span>
devices behave <span class="nb">{</span><span class="k">\em</span> exactly<span class="k">\/</span><span class="nb">}</span> the same (insofar as the underlying
hardware will allow).

The goal of the <span class="k">\UCD\ </span>is <span class="nb">{</span><span class="k">\em</span> not<span class="k">\/</span><span class="nb">}</span> to alienate driver developers who
have not yet taken steps to support this effort. The goal of <span class="k">\UCD\ </span>is
simply to give people writing application programs for <span class="k">\cdrom\ </span>drives
<span class="nb">{</span><span class="k">\em</span> one<span class="k">\/</span><span class="nb">}</span> <span class="k">\linux\ \cdrom\ </span>interface with consistent behavior for all
<span class="k">\cdrom\ </span>devices. In addition, this also provides a consistent interface
between the low-level device driver code and the <span class="k">\linux\ </span>kernel. Care
is taken that 100<span class="k">\,\%</span> compatibility exists with the data structures and
programmer&#39;s interface defined in <span class="k">\cdromh</span>. This guide was written to
help <span class="k">\cdrom\ </span>driver developers adapt their code to use the <span class="k">\UCD\ </span>code
defined in <span class="k">\cdromc</span>.

Personally, I think that the most important hardware interfaces are
the IDE/ATAPI drives and, of course, the SCSI drives, but as prices
of hardware drop continuously, it is also likely that people may have
more than one <span class="k">\cdrom\ </span>drive, possibly of mixed types. It is important
that these drives behave in the same way. In December 1994, one of the
cheapest <span class="k">\cdrom\ </span>drives was a Philips cm206, a double-speed proprietary
drive. In the months that I was busy writing a <span class="k">\linux\ </span>driver for it,
proprietary drives became obsolete and IDE/ATAPI drives became the
standard. At the time of the last update to this document (November
1997) it is becoming difficult to even <span class="nb">{</span><span class="k">\em</span> find<span class="nb">}</span> anything less than a
16 speed <span class="k">\cdrom\ </span>drive, and 24 speed drives are common.

<span class="k">\newsection</span><span class="nb">{</span>Standardizing through another software level<span class="nb">}</span>
<span class="k">\label</span><span class="nb">{</span>cdrom.c<span class="nb">}</span>

At the time this document was conceived, all drivers directly
implemented the <span class="k">\cdrom\ </span><span class="s">$</span><span class="nb">ioctl</span><span class="o">()</span><span class="s">$</span> calls through their own routines. This
led to the danger of different drivers forgetting to do important things
like checking that the user was giving the driver valid data. More
importantly, this led to the divergence of behavior, which has already
been discussed.

For this reason, the <span class="k">\UCD\ </span>was created to enforce consistent <span class="k">\cdrom\</span>
drive behavior, and to provide a common set of services to the various
low-level <span class="k">\cdrom\ </span>device drivers. The <span class="k">\UCD\ </span>now provides another
software-level, that separates the <span class="s">$</span><span class="nb">ioctl</span><span class="o">()</span><span class="s">$</span> and <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> implementation
from the actual hardware implementation. Note that this effort has
made few changes which will affect a user&#39;s application programs. The
greatest change involved moving the contents of the various low-level
<span class="k">\cdrom\ </span>drivers&#39; header files to the kernel&#39;s cdrom directory. This was
done to help ensure that the user is only presented with only one cdrom
interface, the interface defined in <span class="k">\cdromh</span>.

<span class="k">\cdrom\ </span>drives are specific enough (<span class="k">\ie</span>, different from other
block-devices such as floppy or hard disc drives), to define a set
of common <span class="nb">{</span><span class="k">\em</span> <span class="k">\cdrom\ </span>device operations<span class="nb">}</span>, <span class="s">$</span><span class="nb">&lt;cdrom</span><span class="o">-</span><span class="nb">device&gt;_dops</span><span class="s">$</span>.
These operations are different from the classical block-device file
operations, <span class="s">$</span><span class="nb">&lt;block</span><span class="o">-</span><span class="nb">device&gt;_fops</span><span class="s">$</span>.

The routines for the <span class="k">\UCD\ </span>interface level are implemented in the file
<span class="k">\cdromc</span>. In this file, the <span class="k">\UCD\ </span>interfaces with the kernel as a block
device by registering the following general <span class="s">$</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">file_operations</span><span class="s">$</span>:
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">struct&amp; file_operations</span><span class="nv">\ </span><span class="nb">cdrom_fops </span><span class="o">=</span><span class="nb"> </span><span class="nv">\{\hidewidth\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL,                  &amp; lseek </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;block_read,            &amp; read</span><span class="o">---</span><span class="nb">general block</span><span class="o">-</span><span class="nb">dev read </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;block_write,           &amp; write</span><span class="o">---</span><span class="nb">general block</span><span class="o">-</span><span class="nb">dev write </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL,                  &amp; readdir </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL,                  &amp; select </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;cdrom_ioctl,           &amp; ioctl </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL,                  &amp; mmap </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;cdrom_open,            &amp; open </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;cdrom_release,         &amp; release </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL,                  &amp; fsync </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL,                  &amp; fasync </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;cdrom_media_changed,   &amp; media change </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">        &amp;NULL                   &amp; revalidate </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nv">\}</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">}</span>
<span class="s">$$</span> 

Every active <span class="k">\cdrom\ </span>device shares this <span class="s">$</span><span class="nb">struct</span><span class="s">$</span>. The routines
declared above are all implemented in <span class="k">\cdromc</span>, since this file is the
place where the behavior of all <span class="k">\cdrom</span>-devices is defined and
standardized. The actual interface to the various types of <span class="k">\cdrom\ </span>
hardware is still performed by various low-level <span class="k">\cdrom</span>-device
drivers. These routines simply implement certain <span class="nb">{</span><span class="k">\em</span> capabilities<span class="k">\/</span><span class="nb">}</span>
that are common to all <span class="k">\cdrom\ </span>(and really, all removable-media
devices).

Registration of a low-level <span class="k">\cdrom\ </span>device driver is now done through
the general routines in <span class="k">\cdromc</span>, not through the Virtual File System
(VFS) any more. The interface implemented in <span class="k">\cdromc\ </span>is carried out
through two general structures that contain information about the
capabilities of the driver, and the specific drives on which the
driver operates. The structures are:
<span class="k">\begin</span><span class="nb">{</span>description<span class="nb">}</span>
<span class="k">\item</span><span class="na">[$cdrom_device_ops$]</span> 
  This structure contains information about the low-level driver for a
  <span class="k">\cdrom\ </span>device. This structure is conceptually connected to the major
  number of the device (although some drivers may have different
  major numbers, as is the case for the IDE driver).
<span class="k">\item</span><span class="na">[$cdrom_device_info$]</span> 
  This structure contains information about a particular <span class="k">\cdrom\ </span>drive,
  such as its device name, speed, etc. This structure is conceptually
  connected to the minor number of the device.
<span class="k">\end</span><span class="nb">{</span>description<span class="nb">}</span>

Registering a particular <span class="k">\cdrom\ </span>drive with the <span class="k">\UCD\ </span>is done by the
low-level device driver though a call to:
<span class="sb">$$</span><span class="nb">register_cdrom</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> &lt;device&gt;_info</span><span class="o">)</span><span class="nb">  </span>
<span class="s">$$</span>
The device information structure, <span class="s">$</span><span class="nb">&lt;device&gt;_info</span><span class="s">$</span>, contains all the
information needed for the kernel to interface with the low-level
<span class="k">\cdrom\ </span>device driver. One of the most important entries in this
structure is a pointer to the <span class="s">$</span><span class="nb">cdrom_device_ops</span><span class="s">$</span> structure of the
low-level driver.

The device operations structure, <span class="s">$</span><span class="nb">cdrom_device_ops</span><span class="s">$</span>, contains a list
of pointers to the functions which are implemented in the low-level
device driver. When <span class="k">\cdromc\ </span>accesses a <span class="k">\cdrom\ </span>device, it does it
through the functions in this structure. It is impossible to know all
the capabilities of future <span class="k">\cdrom\ </span>drives, so it is expected that this
list may need to be expanded from time to time as new technologies are
developed. For example, CD-R and CD-R/W drives are beginning to become
popular, and support will soon need to be added for them. For now, the
current <span class="s">$</span><span class="nb">struct</span><span class="s">$</span> is:
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;</span><span class="nv">\hbox</span><span class="nb"> to </span><span class="m">10</span><span class="nb">em{$#$</span><span class="nv">\hss</span><span class="nb">}&amp;</span>
<span class="nb">  $</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">struct&amp; cdrom_device_ops</span><span class="nv">\ \{</span><span class="nb"> </span><span class="nv">\hidewidth\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> open</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;void&amp; </span><span class="o">(*</span><span class="nb"> release</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"> </span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> drive_status</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb">     </span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> media_changed</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"> </span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> tray_move</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> lock_door</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> select_speed</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> select_disc</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, int</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> get_last_session</span><span class="o">)</span><span class="nb"> </span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, </span>
<span class="nb">        struct</span><span class="nv">\ </span><span class="nb">cdrom_multisession </span><span class="o">*</span><span class="nb">{}</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> get_mcn</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, struct</span><span class="nv">\ </span><span class="nb">cdrom_mcn </span><span class="o">*</span><span class="nb">{}</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> reset</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> audio_ioctl</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, unsigned</span><span class="nv">\ </span><span class="nb">int, </span>
<span class="nb">        void </span><span class="o">*</span><span class="nb">{}</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"> </span>
<span class="nb">  &amp;int&amp; </span><span class="o">(*</span><span class="nb"> dev_ioctl</span><span class="o">)(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">, unsigned</span><span class="nv">\ </span><span class="nb">int, </span>
<span class="nb">        unsigned</span><span class="nv">\ </span><span class="nb">long</span><span class="o">)</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nv">\noalign</span><span class="nb">{</span><span class="nv">\medskip</span><span class="nb">}</span>
<span class="nb">  &amp;const</span><span class="nv">\ </span><span class="nb">int&amp; capability;&amp; capability flags </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;int&amp; n_minors;&amp; number of active minor devices </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nv">\}</span><span class="nb">;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">}</span>
<span class="s">$$</span>
When a low-level device driver implements one of these capabilities,
it should add a function pointer to this <span class="s">$</span><span class="nb">struct</span><span class="s">$</span>. When a particular
function is not implemented, however, this <span class="s">$</span><span class="nb">struct</span><span class="s">$</span> should contain a
NULL instead. The <span class="s">$</span><span class="nb">capability</span><span class="s">$</span> flags specify the capabilities of the
<span class="k">\cdrom\ </span>hardware and/or low-level <span class="k">\cdrom\ </span>driver when a <span class="k">\cdrom\ </span>drive
is registered with the <span class="k">\UCD</span>. The value <span class="s">$</span><span class="nb">n_minors</span><span class="s">$</span> should be a positive
value indicating the number of minor devices that are supported by
the low-level device driver, normally~1. Although these two variables
are `informative&#39; rather than `operational,&#39; they are included in
<span class="s">$</span><span class="nb">cdrom_device_ops</span><span class="s">$</span> because they describe the capability of the <span class="nb">{</span><span class="k">\em</span>
driver<span class="k">\/</span><span class="nb">}</span> rather than the <span class="nb">{</span><span class="k">\em</span> drive<span class="nb">}</span>. Nomenclature has always been
difficult in computer programming.

Note that most functions have fewer parameters than their
<span class="s">$</span><span class="nb">blkdev_fops</span><span class="s">$</span> counterparts. This is because very little of the
information in the structures <span class="s">$</span><span class="nb">inode</span><span class="s">$</span> and <span class="s">$</span><span class="nb">file</span><span class="s">$</span> is used. For most
drivers, the main parameter is the <span class="s">$</span><span class="nb">struct</span><span class="s">$</span> <span class="s">$</span><span class="nb">cdrom_device_info</span><span class="s">$</span>, from
which the major and minor number can be extracted. (Most low-level
<span class="k">\cdrom\ </span>drivers don&#39;t even look at the major and minor number though,
since many of them only support one device.) This will be available
through <span class="s">$</span><span class="nb">dev</span><span class="s">$</span> in <span class="s">$</span><span class="nb">cdrom_device_info</span><span class="s">$</span> described below.

The drive-specific, minor-like information that is registered with
<span class="k">\cdromc</span>, currently contains the following fields:
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;</span><span class="nv">\hbox</span><span class="nb"> to </span><span class="m">10</span><span class="nb">em{$#$</span><span class="nv">\hss</span><span class="nb">}&amp;</span>
<span class="nb">  $</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">struct&amp; cdrom_device_info</span><span class="nv">\ \{</span><span class="nb"> </span><span class="nv">\hidewidth\cr</span><span class="nb"></span>
<span class="nb">  &amp; struct</span><span class="nv">\ </span><span class="nb">cdrom_device_ops </span><span class="o">*</span><span class="nb">&amp; ops;&amp; device operations for this major</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb">&amp; next;&amp; next device_info for this major</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; void </span><span class="o">*</span><span class="nb">&amp;  handle;&amp; driver</span><span class="o">-</span><span class="nb">dependent data</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nv">\noalign</span><span class="nb">{</span><span class="nv">\medskip</span><span class="nb">}</span>
<span class="nb">  &amp; kdev_t&amp;  dev;&amp; device number </span><span class="o">(</span><span class="nb">incorporates minor</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; int&amp; mask;&amp; mask of capability: disables them </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; int&amp; speed;&amp; maximum speed for reading data </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; int&amp; capacity;&amp; number of discs in a jukebox </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nv">\noalign</span><span class="nb">{</span><span class="nv">\medskip</span><span class="nb">}</span>
<span class="nb">  &amp;int&amp; options : </span><span class="m">30</span><span class="nb">;&amp; options flags </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp;unsigned&amp; mc_flags : </span><span class="m">2</span><span class="nb">;&amp; media</span><span class="o">-</span><span class="nb">change buffer flags </span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; int&amp; use_count;&amp; number of times device is opened</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">  &amp; char&amp; name</span><span class="o">[</span><span class="m">20</span><span class="o">]</span><span class="nb">;&amp; name of the device type</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nv">\}\cr</span><span class="nb"></span>
<span class="nb">}</span><span class="s">$$</span>
Using this <span class="s">$</span><span class="nb">struct</span><span class="s">$</span>, a linked list of the registered minor devices is
built, using the <span class="s">$</span><span class="nb">next</span><span class="s">$</span> field. The device number, the device operations
struct and specifications of properties of the drive are stored in this
structure.

The <span class="s">$</span><span class="nb">mask</span><span class="s">$</span> flags can be used to mask out some of the capabilities listed
in <span class="s">$</span><span class="nb">ops</span><span class="nv">\to</span><span class="nb"> capability</span><span class="s">$</span>, if a specific drive doesn&#39;t support a feature
of the driver. The value <span class="s">$</span><span class="nb">speed</span><span class="s">$</span> specifies the maximum head-rate of the
drive, measured in units of normal audio speed (176<span class="k">\,</span>kB/sec raw data or
150<span class="k">\,</span>kB/sec file system data). The value <span class="s">$</span><span class="nb">n_discs</span><span class="s">$</span> should reflect the
number of discs the drive can hold simultaneously, if it is designed
as a juke-box, or otherwise~1. The parameters are declared <span class="s">$</span><span class="nb">const</span><span class="s">$</span>
because they describe properties of the drive, which don&#39;t change after
registration.

A few registers contain variables local to the <span class="k">\cdrom\ </span>drive. The
flags <span class="s">$</span><span class="nb">options</span><span class="s">$</span> are used to specify how the general <span class="k">\cdrom\ </span>routines
should behave. These various flags registers should provide enough
flexibility to adapt to the different users&#39; wishes (and <span class="nb">{</span><span class="k">\em</span> not<span class="k">\/</span><span class="nb">}</span> the
`arbitrary&#39; wishes of the author of the low-level device driver, as is
the case in the old scheme). The register <span class="s">$</span><span class="nb">mc_flags</span><span class="s">$</span> is used to buffer
the information from <span class="s">$</span><span class="nb">media_changed</span><span class="o">()</span><span class="s">$</span> to two separate queues. Other
data that is specific to a minor drive, can be accessed through <span class="s">$</span><span class="nb">handle</span><span class="s">$</span>,
which can point to a data structure specific to the low-level driver.
The fields <span class="s">$</span><span class="nb">use_count</span><span class="s">$</span>, <span class="s">$</span><span class="nb">next</span><span class="s">$</span>, <span class="s">$</span><span class="nb">options</span><span class="s">$</span> and <span class="s">$</span><span class="nb">mc_flags</span><span class="s">$</span> need not be
initialized.

The intermediate software layer that <span class="k">\cdromc\ </span>forms will perform some
additional bookkeeping. The use count of the device (the number of
processes that have the device opened) is registered in <span class="s">$</span><span class="nb">use_count</span><span class="s">$</span>. The
function <span class="s">$</span><span class="nb">cdrom_ioctl</span><span class="o">()</span><span class="s">$</span> will verify the appropriate user-memory regions
for read and write, and in case a location on the CD is transferred,
it will `sanitize&#39; the format by making requests to the low-level
drivers in a standard format, and translating all formats between the
user-software and low level drivers. This relieves much of the drivers&#39;
memory checking and format checking and translation. Also, the necessary
structures will be declared on the program stack.

The implementation of the functions should be as defined in the
following sections. Two functions <span class="nb">{</span><span class="k">\em</span> must<span class="k">\/</span><span class="nb">}</span> be implemented, namely
<span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> and <span class="s">$</span><span class="nb">release</span><span class="o">()</span><span class="s">$</span>. Other functions may be omitted, their
corresponding capability flags will be cleared upon registration.
Generally, a function returns zero on success and negative on error. A
function call should return only after the command has completed, but of
course waiting for the device should not use processor time.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">open</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">purpose</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

<span class="s">$</span><span class="nb">Open</span><span class="o">()</span><span class="s">$</span> should try to open the device for a specific <span class="s">$</span><span class="nb">purpose</span><span class="s">$</span>, which
can be either:
<span class="k">\begin</span><span class="nb">{</span>itemize<span class="nb">}</span>
<span class="k">\item</span><span class="na">[0]</span> Open for reading data, as done by <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>mount()<span class="nb">}}</span> (2), or the
user commands <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>dd<span class="nb">}}</span> or <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>cat<span class="nb">}}</span>.  
<span class="k">\item</span><span class="na">[1]</span> Open for <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> commands, as done by audio-CD playing
programs.
<span class="k">\end</span><span class="nb">{</span>itemize<span class="nb">}</span>
Notice that any strategic code (closing tray upon <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span>, etc.)<span class="k">\ </span>is
done by the calling routine in <span class="k">\cdromc</span>, so the low-level routine
should only be concerned with proper initialization, such as spinning
up the disc, etc. <span class="c">% and device-use count</span>


<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Void</span><span class="nv">\ </span><span class="nb">release</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>


Device-specific actions should be taken such as spinning down the device.
However, strategic actions such as ejection of the tray, or unlocking
the door, should be left over to the general routine <span class="s">$</span><span class="nb">cdrom_release</span><span class="o">()</span><span class="s">$</span>.
This is the only function returning type <span class="s">$</span><span class="nb">void</span><span class="s">$</span>.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">drive_status</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">slot_nr</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>
<span class="k">\label</span><span class="nb">{</span>drive status<span class="nb">}</span>

The function <span class="s">$</span><span class="nb">drive_status</span><span class="s">$</span>, if implemented, should provide
information on the status of the drive (not the status of the disc,
which may or may not be in the drive). If the drive is not a changer,
<span class="s">$</span><span class="nb">slot_nr</span><span class="s">$</span> should be ignored. In <span class="k">\cdromh\ </span>the possibilities are listed: 
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">CDS_NO_INFO&amp; no information available</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDS_NO_DISC&amp; no disc is inserted, tray is closed</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDS_TRAY_OPEN&amp; tray is opened</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDS_DRIVE_NOT_READY&amp; something is wrong, tray is moving?</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDS_DISC_OK&amp; a disc is loaded and everything is fine</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">}</span>
<span class="s">$$</span>

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">media_changed</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">disc_nr</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function is very similar to the original function in <span class="s">$</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb"></span>
<span class="nb">file_operations</span><span class="s">$</span>. It returns 1 if the medium of the device <span class="s">$</span><span class="nb">cdi</span><span class="nv">\to</span><span class="nb"></span>
<span class="nb">dev</span><span class="s">$</span> has changed since the last call, and 0 otherwise. The parameter
<span class="s">$</span><span class="nb">disc_nr</span><span class="s">$</span> identifies a specific slot in a juke-box, it should be
ignored for single-disc drives.  Note that by `re-routing&#39; this
function through <span class="s">$</span><span class="nb">cdrom_media_changed</span><span class="o">()</span><span class="s">$</span>, we can implement separate
queues for the VFS and a new <span class="s">$</span><span class="nb">ioctl</span><span class="o">()</span><span class="s">$</span> function that can report device
changes to software (<span class="k">\eg</span>, an auto-mounting daemon).

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">tray_move</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">position</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function, if implemented, should control the tray movement. (No
other function should control this.) The parameter <span class="s">$</span><span class="nb">position</span><span class="s">$</span> controls
the desired direction of movement:
<span class="k">\begin</span><span class="nb">{</span>itemize<span class="nb">}</span>
<span class="k">\item</span><span class="na">[0]</span> Close tray
<span class="k">\item</span><span class="na">[1]</span> Open tray
<span class="k">\end</span><span class="nb">{</span>itemize<span class="nb">}</span>
This function returns 0 upon success, and a non-zero value upon
error. Note that if the tray is already in the desired position, no
action need be taken, and the return value should be 0. 

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">lock_door</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">lock</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function (and no other code) controls locking of the door, if the
drive allows this. The value of <span class="s">$</span><span class="nb">lock</span><span class="s">$</span> controls the desired locking
state:
<span class="k">\begin</span><span class="nb">{</span>itemize<span class="nb">}</span>
<span class="k">\item</span><span class="na">[0]</span> Unlock door, manual opening is allowed
<span class="k">\item</span><span class="na">[1]</span> Lock door, tray cannot be ejected manually
<span class="k">\end</span><span class="nb">{</span>itemize<span class="nb">}</span>
This function returns 0 upon success, and a non-zero value upon
error. Note that if the door is already in the requested state, no
action need be taken, and the return value should be 0. 

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">select_speed</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">speed</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

Some <span class="k">\cdrom\ </span>drives are capable of changing their head-speed. There
are several reasons for changing the speed of a <span class="k">\cdrom\ </span>drive. Badly
pressed <span class="k">\cdrom</span> s may benefit from less-than-maximum head rate. Modern
<span class="k">\cdrom\ </span>drives can obtain very high head rates (up to <span class="s">$</span><span class="m">24</span><span class="nv">\times</span><span class="s">$</span> is
common).  It has been reported that these drives can make reading
errors at these high speeds, reducing the speed can prevent data loss
in these circumstances.  Finally, some of these drives can
make an annoyingly loud noise, which a lower speed may reduce. <span class="c">%Finally,</span>
<span class="c">%although the audio-low-pass filters probably aren&#39;t designed for it,</span>
<span class="c">%more than real-time playback of audio might be used for high-speed</span>
<span class="c">%copying of audio tracks.</span>

This function specifies the speed at which data is read or audio is
played back. The value of <span class="s">$</span><span class="nb">speed</span><span class="s">$</span> specifies the head-speed of the
drive, measured in units of standard cdrom speed (176<span class="k">\,</span>kB/sec raw data
or 150<span class="k">\,</span>kB/sec file system data). So to request that a <span class="k">\cdrom\ </span>drive
operate at 300<span class="k">\,</span>kB/sec you would call the CDROM<span class="nb">_</span>SELECT<span class="nb">_</span>SPEED <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>
with <span class="s">$</span><span class="nb">speed</span><span class="o">=</span><span class="m">2</span><span class="s">$</span>. The special value `0&#39; means `auto-selection&#39;, <span class="k">\ie</span>,
maximum data-rate or real-time audio rate. If the drive doesn&#39;t have
this `auto-selection&#39; capability, the decision should be made on the
current disc loaded and the return value should be positive. A negative
return value indicates an error.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">select_disc</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, int</span><span class="nv">\ </span><span class="nb">number</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

If the drive can store multiple discs (a juke-box) this function
will perform disc selection. It should return the number of the
selected disc on success, a negative value on error. Currently, only
the ide-cd driver supports this functionality.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">get_last_session</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, struct</span><span class="err">\</span><span class="nb"></span>
<span class="nb">  cdrom_multisession </span><span class="o">*</span><span class="nb"> ms_info</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function should implement the old corresponding <span class="s">$</span><span class="nb">ioctl</span><span class="o">()</span><span class="s">$</span>. For
device <span class="s">$</span><span class="nb">cdi</span><span class="nv">\to</span><span class="nb"> dev</span><span class="s">$</span>, the start of the last session of the current disc
should be returned in the pointer argument <span class="s">$</span><span class="nb">ms_info</span><span class="s">$</span>. Note that
routines in <span class="k">\cdromc\ </span>have sanitized this argument: its requested
format will <span class="nb">{</span><span class="k">\em</span> always<span class="k">\/</span><span class="nb">}</span> be of the type <span class="s">$</span><span class="nb">CDROM_LBA</span><span class="s">$</span> (linear block
addressing mode), whatever the calling software requested. But
sanitization goes even further: the low-level implementation may
return the requested information in <span class="s">$</span><span class="nb">CDROM_MSF</span><span class="s">$</span> format if it wishes so
(setting the <span class="s">$</span><span class="nb">ms_info</span><span class="nv">\rightarrow</span><span class="nb"> addr_format</span><span class="s">$</span> field appropriately, of
course) and the routines in <span class="k">\cdromc\ </span>will make the transformation if
necessary. The return value is 0 upon success.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">get_mcn</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, struct</span><span class="err">\</span><span class="nb"></span>
<span class="nb">  cdrom_mcn </span><span class="o">*</span><span class="nb"> mcn</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

Some discs carry a `Media Catalog Number&#39; (MCN), also called
`Universal Product Code&#39; (UPC). This number should reflect the number
that is generally found in the bar-code on the product. Unfortunately,
the few discs that carry such a number on the disc don&#39;t even use the
same format. The return argument to this function is a pointer to a
pre-declared memory region of type <span class="s">$</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_mcn</span><span class="s">$</span>. The MCN is
expected as a 13-character string, terminated by a null-character.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">reset</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This call should perform a hard-reset on the drive (although in
circumstances that a hard-reset is necessary, a drive may very well not
listen to commands anymore). Preferably, control is returned to the
caller only after the drive has finished resetting. If the drive is no
longer listening, it may be wise for the underlying low-level cdrom
driver to time out.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">audio_ioctl</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, unsigned</span><span class="err">\</span><span class="nb"></span>
<span class="nb">  int</span><span class="nv">\ </span><span class="nb">cmd, void </span><span class="o">*</span><span class="nb"> arg</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

Some of the <span class="k">\cdrom</span>-<span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s defined in <span class="k">\cdromh\ </span>can be
implemented by the routines described above, and hence the function
<span class="s">$</span><span class="nb">cdrom_ioctl</span><span class="s">$</span> will use those. However, most <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s deal with
audio-control. We have decided to leave these to be accessed through a
single function, repeating the arguments <span class="s">$</span><span class="nb">cmd</span><span class="s">$</span> and <span class="s">$</span><span class="nb">arg</span><span class="s">$</span>. Note that
the latter is of type <span class="s">$</span><span class="nb">void</span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>, rather than <span class="s">$</span><span class="nb">unsigned</span><span class="nv">\ </span><span class="nb">long</span><span class="err">\</span><span class="nb"></span>
<span class="nb">int</span><span class="s">$</span>. The routine <span class="s">$</span><span class="nb">cdrom_ioctl</span><span class="o">()</span><span class="s">$</span> does do some useful things,
though. It sanitizes the address format type to <span class="s">$</span><span class="nb">CDROM_MSF</span><span class="s">$</span> (Minutes,
Seconds, Frames) for all audio calls. It also verifies the memory
location of <span class="s">$</span><span class="nb">arg</span><span class="s">$</span>, and reserves stack-memory for the argument. This
makes implementation of the <span class="s">$</span><span class="nb">audio_ioctl</span><span class="o">()</span><span class="s">$</span> much simpler than in the
old driver scheme. For example, you may look up the function
<span class="s">$</span><span class="nb">cm</span><span class="m">206</span><span class="nb">_audio_ioctl</span><span class="o">()</span><span class="s">$</span> in <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>cm206.c<span class="nb">}}</span> that should be updated with
this documentation. 

An unimplemented ioctl should return <span class="s">$</span><span class="o">-</span><span class="nb">ENOSYS</span><span class="s">$</span>, but a harmless request
(<span class="k">\eg</span>, <span class="s">$</span><span class="nb">CDROMSTART</span><span class="s">$</span>) may be ignored by returning 0 (success). Other
errors should be according to the standards, whatever they are. When
an error is returned by the low-level driver, the <span class="k">\UCD\ </span>tries whenever
possible to return the error code to the calling program. (We may decide
to sanitize the return value in <span class="s">$</span><span class="nb">cdrom_ioctl</span><span class="o">()</span><span class="s">$</span> though, in order to
guarantee a uniform interface to the audio-player software.)

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">dev_ioctl</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi, unsigned</span><span class="nv">\ </span><span class="nb">int</span><span class="err">\</span><span class="nb"></span>
<span class="nb">  cmd, unsigned</span><span class="nv">\ </span><span class="nb">long</span><span class="nv">\ </span><span class="nb">arg</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

Some <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s seem to be specific to certain <span class="k">\cdrom\ </span>drives. That is,
they are introduced to service some capabilities of certain drives. In
fact, there are 6 different <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s for reading data, either in some
particular kind of format, or audio data. Not many drives support
reading audio tracks as data, I believe this is because of protection
of copyrights of artists. Moreover, I think that if audio-tracks are
supported, it should be done through the VFS and not via <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s. A
problem here could be the fact that audio-frames are 2352 bytes long,
so either the audio-file-system should ask for 75264 bytes at once
(the least common multiple of 512 and 2352), or the drivers should
bend their backs to cope with this incoherence (to which I would be
opposed).  Furthermore, it is very difficult for the hardware to find
the exact frame boundaries, since there are no synchronization headers
in audio frames.  Once these issues are resolved, this code should be
standardized in <span class="k">\cdromc</span>.

Because there are so many <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s that seem to be introduced to
satisfy certain drivers,<span class="k">\footnote</span><span class="nb">{</span>Is there software around that
  actually uses these? I&#39;d be interested!<span class="nb">}</span> any `non-standard&#39; <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s
are routed through the call <span class="s">$</span><span class="nb">dev_ioctl</span><span class="o">()</span><span class="s">$</span>. In principle, `private&#39;
<span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s should be numbered after the device&#39;s major number, and not
the general <span class="k">\cdrom\ </span><span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> number, <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>0x53<span class="nb">}}</span>. Currently the
non-supported <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s are: <span class="nb">{</span><span class="k">\it</span> CDROMREADMODE1, CDROMREADMODE2,
  CDROMREADAUDIO, CDROMREADRAW, CDROMREADCOOKED, CDROMSEEK,
  CDROMPLAY<span class="k">\-</span>BLK and CDROM<span class="k">\-</span>READALL<span class="nb">}</span>.


<span class="k">\subsection</span><span class="nb">{</span><span class="k">\cdrom\ </span>capabilities<span class="nb">}</span>
<span class="k">\label</span><span class="nb">{</span>capability<span class="nb">}</span>

Instead of just implementing some <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> calls, the interface in
<span class="k">\cdromc\ </span>supplies the possibility to indicate the <span class="nb">{</span><span class="k">\em</span> capabilities<span class="k">\/</span><span class="nb">}</span>
of a <span class="k">\cdrom\ </span>drive. This can be done by ORing any number of
capability-constants that are defined in <span class="k">\cdromh\ </span>at the registration
phase. Currently, the capabilities are any of:
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">CDC_CLOSE_TRAY&amp; can close tray by software control</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_OPEN_TRAY&amp; can open tray</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_LOCK&amp; can lock and unlock the door</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_SELECT_SPEED&amp; can select speed, in units of $</span><span class="nv">\sim</span><span class="nb">$</span><span class="m">150</span><span class="nv">\,</span><span class="nb">kB</span><span class="o">/</span><span class="nb">s</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_SELECT_DISC&amp; drive is juke</span><span class="o">-</span><span class="nb">box</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_MULTI_SESSION&amp; can read sessions $&gt;</span><span class="nv">\rm</span><span class="m">1</span><span class="nb">$</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_MCN&amp; can read Media Catalog Number</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_MEDIA_CHANGED&amp; can report if disc has changed</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_PLAY_AUDIO&amp; can perform audio</span><span class="o">-</span><span class="nb">functions </span><span class="o">(</span><span class="nb">play, pause, etc</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_RESET&amp; hard reset device</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_IOCTLS&amp; driver has non</span><span class="o">-</span><span class="nb">standard ioctls</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDC_DRIVE_STATUS&amp; driver implements drive status</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">}</span>
<span class="s">$$</span>
The capability flag is declared <span class="s">$</span><span class="nb">const</span><span class="s">$</span>, to prevent drivers from
accidentally tampering with the contents. The capability fags actually
inform <span class="k">\cdromc\ </span>of what the driver can do. If the drive found
by the driver does not have the capability, is can be masked out by
the <span class="s">$</span><span class="nb">cdrom_device_info</span><span class="s">$</span> variable <span class="s">$</span><span class="nb">mask</span><span class="s">$</span>. For instance, the SCSI <span class="k">\cdrom\</span>
driver has implemented the code for loading and ejecting <span class="k">\cdrom</span>&#39;s, and
hence its corresponding flags in <span class="s">$</span><span class="nb">capability</span><span class="s">$</span> will be set. But a SCSI
<span class="k">\cdrom\ </span>drive might be a caddy system, which can&#39;t load the tray, and
hence for this drive the <span class="s">$</span><span class="nb">cdrom_device_info</span><span class="s">$</span> struct will have set
the <span class="s">$</span><span class="nb">CDC_CLOSE_TRAY</span><span class="s">$</span> bit in <span class="s">$</span><span class="nb">mask</span><span class="s">$</span>.

In the file <span class="k">\cdromc\ </span>you will encounter many constructions of the type
<span class="sb">$$</span><span class="nv">\it</span><span class="nb"></span>
<span class="nb">if</span><span class="nv">\ </span><span class="o">(</span><span class="nb">cdo</span><span class="nv">\rightarrow</span><span class="nb"> capability </span><span class="nv">\mathrel\&amp;</span><span class="nb"> </span><span class="nv">\mathord</span><span class="nb">{</span><span class="nv">\sim</span><span class="nb">} cdi</span><span class="nv">\rightarrow</span><span class="nb"> mask </span>
<span class="nb">   </span><span class="nv">\mathrel</span><span class="nb">{</span><span class="nv">\&amp;</span><span class="nb">} CDC_&lt;capability&gt;</span><span class="o">)</span><span class="nb"> </span><span class="nv">\ldots</span><span class="nb"></span>
<span class="s">$$</span>
There is no <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> to set the mask<span class="k">\dots</span> The reason is that
I think it is better to control the <span class="nb">{</span><span class="k">\em</span> behavior<span class="k">\/</span><span class="nb">}</span> rather than the
<span class="nb">{</span><span class="k">\em</span> capabilities<span class="nb">}</span>.

<span class="k">\subsection</span><span class="nb">{</span>Options<span class="nb">}</span>

A final flag register controls the <span class="nb">{</span><span class="k">\em</span> behavior<span class="k">\/</span><span class="nb">}</span> of the <span class="k">\cdrom\</span>
drives, in order to satisfy different users&#39; wishes, hopefully
independently of the ideas of the respective author who happened to
have made the drive&#39;s support available to the <span class="k">\linux\ </span>community. The
current behavior options are:
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">CDO_AUTO_CLOSE&amp; try to close tray upon device $open</span><span class="o">()</span><span class="nb">$</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDO_AUTO_EJECT&amp; try to open tray on last device $close</span><span class="o">()</span><span class="nb">$</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDO_USE_FFLAGS&amp; use $file_pointer</span><span class="nv">\rightarrow</span><span class="nb"> f_flags$ to indicate</span>
<span class="nb"> purpose for $open</span><span class="o">()</span><span class="nb">$</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDO_LOCK&amp; try to lock door if device is opened</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDO_CHECK_TYPE&amp; ensure disc type is data if opened for data</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">}</span>
<span class="s">$$</span>

The initial value of this register is <span class="s">$</span><span class="nb">CDO_AUTO_CLOSE </span><span class="nv">\mathrel</span><span class="nb">|</span>
<span class="nb">CDO_USE_FFLAGS </span><span class="nv">\mathrel</span><span class="nb">| CDO_LOCK</span><span class="s">$</span>, reflecting my own view on user
interface and software standards. Before you protest, there are two
new <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s implemented in <span class="k">\cdromc</span>, that allow you to control the
behavior by software. These are:
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">CDROM_SET_OPTIONS&amp; set options specified in $</span><span class="o">(</span><span class="nb">int</span><span class="o">)</span><span class="nv">\ </span><span class="nb">arg$</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">CDROM_CLEAR_OPTIONS&amp; clear options specified in $</span><span class="o">(</span><span class="nb">int</span><span class="o">)</span><span class="nv">\ </span><span class="nb">arg$</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">}</span>
<span class="s">$$</span>
One option needs some more explanation: <span class="s">$</span><span class="nb">CDO_USE_FFLAGS</span><span class="s">$</span>. In the next
newsection we explain what the need for this option is.

A software package <span class="nb">{</span><span class="k">\tt</span> setcd<span class="nb">}</span>, available from the Debian distribution
and <span class="nb">{</span><span class="k">\tt</span> sunsite.unc.edu<span class="nb">}</span>, allows user level control of these flags. 

<span class="k">\newsection</span><span class="nb">{</span>The need to know the purpose of opening the <span class="k">\cdrom\ </span>device<span class="nb">}</span>

Traditionally, Unix devices can be used in two different `modes&#39;,
either by reading/writing to the device file, or by issuing
controlling commands to the device, by the device&#39;s <span class="s">$</span><span class="nb">ioctl</span><span class="o">()</span><span class="s">$</span>
call. The problem with <span class="k">\cdrom\ </span>drives, is that they can be used for
two entirely different purposes. One is to mount removable
file systems, <span class="k">\cdrom</span> s, the other is to play audio CD&#39;s. Audio commands
are implemented entirely through <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s, presumably because the
first implementation (SUN?) has been such. In principle there is
nothing wrong with this, but a good control of the `CD player&#39; demands
that the device can <span class="nb">{</span><span class="k">\em</span> always<span class="k">\/</span><span class="nb">}</span> be opened in order to give the
<span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> commands, regardless of the state the drive is in. 

On the other hand, when used as a removable-media disc drive (what the
original purpose of <span class="k">\cdrom</span> s is) we would like to make sure that the
disc drive is ready for operation upon opening the device. In the old
scheme, some <span class="k">\cdrom\ </span>drivers don&#39;t do any integrity checking, resulting
in a number of i/o errors reported by the VFS to the kernel when an
attempt for mounting a <span class="k">\cdrom\ </span>on an empty drive occurs. This is not a
particularly elegant way to find out that there is no <span class="k">\cdrom\ </span>inserted;
it more-or-less looks like the old IBM-PC trying to read an empty floppy
drive for a couple of seconds, after which the system complains it
can&#39;t read from it. Nowadays we can <span class="nb">{</span><span class="k">\em</span> sense<span class="k">\/</span><span class="nb">}</span> the existence of a
removable medium in a drive, and we believe we should exploit that
fact. An integrity check on opening of the device, that verifies the
availability of a <span class="k">\cdrom\ </span>and its correct type (data), would be
desirable.

These two ways of using a <span class="k">\cdrom\ </span>drive, principally for data and
secondarily for playing audio discs, have different demands for the
behavior of the <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> call. Audio use simply wants to open the
device in order to get a file handle which is needed for issuing
<span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> commands, while data use wants to open for correct and
reliable data transfer. The only way user programs can indicate what
their <span class="nb">{</span><span class="k">\em</span> purpose<span class="k">\/</span><span class="nb">}</span> of opening the device is, is through the <span class="s">$</span><span class="nb">flags</span><span class="s">$</span>
parameter (see <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>open(2)<span class="nb">}}</span>). For <span class="k">\cdrom\ </span>devices, these flags aren&#39;t
implemented (some drivers implement checking for write-related flags,
but this is not strictly necessary if the device file has correct
permission flags). Most option flags simply don&#39;t make sense to
<span class="k">\cdrom\ </span>devices: <span class="s">$</span><span class="nb">O_CREAT</span><span class="s">$</span>, <span class="s">$</span><span class="nb">O_NOCTTY</span><span class="s">$</span>, <span class="s">$</span><span class="nb">O_TRUNC</span><span class="s">$</span>, <span class="s">$</span><span class="nb">O_APPEND</span><span class="s">$</span>, and
<span class="s">$</span><span class="nb">O_SYNC</span><span class="s">$</span> have no meaning to a <span class="k">\cdrom</span>. 

We therefore propose to use the flag <span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span> to indicate
that the device is opened just for issuing <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>
commands. Strictly, the meaning of <span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span> is that opening and
subsequent calls to the device don&#39;t cause the calling process to
wait. We could interpret this as ``don&#39;t wait until someone has
inserted some valid data-<span class="k">\cdrom</span>.&#39;&#39; Thus, our proposal of the
implementation for the <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> call for <span class="k">\cdrom</span> s is:
<span class="k">\begin</span><span class="nb">{</span>itemize<span class="nb">}</span>
<span class="k">\item</span> If no other flags are set than <span class="s">$</span><span class="nb">O_RDONLY</span><span class="s">$</span>, the device is opened
for data transfer, and the return value will be 0 only upon successful
initialization of the transfer. The call may even induce some actions
on the <span class="k">\cdrom</span>, such as closing the tray.  
<span class="k">\item</span> If the option flag <span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span> is set, opening will always be
successful, unless the whole device doesn&#39;t exist. The drive will take
no actions whatsoever. 
<span class="k">\end</span><span class="nb">{</span>itemize<span class="nb">}</span>

<span class="k">\subsection</span><span class="nb">{</span>And what about standards?<span class="nb">}</span>

You might hesitate to accept this proposal as it comes from the
<span class="k">\linux\ </span>community, and not from some standardizing institute. What
about SUN, SGI, HP and all those other Unix and hardware vendors?
Well, these companies are in the lucky position that they generally
control both the hardware and software of their supported products,
and are large enough to set their own standard. They do not have to
deal with a dozen or more different, competing hardware
configurations.<span class="k">\footnote</span><span class="nb">{</span>Incidentally, I think that SUN&#39;s approach to
mounting <span class="k">\cdrom</span> s is very good in origin: under Solaris a
volume-daemon automatically mounts a newly inserted <span class="k">\cdrom\ </span>under <span class="nb">{</span><span class="k">\tt</span>
<span class="nb">{</span>/cdrom/<span class="s">$</span><span class="nb">&lt;volume</span><span class="o">-</span><span class="nb">name&gt;</span><span class="s">$</span>/<span class="nb">}}</span>. In my opinion they should have pushed this
further and have <span class="nb">{</span><span class="k">\em</span> every<span class="k">\/</span><span class="nb">}</span> <span class="k">\cdrom\ </span>on the local area network be
mounted at the similar location, <span class="k">\ie</span>, no matter in which particular
machine you insert a <span class="k">\cdrom</span>, it will always appear at the same
position in the directory tree, on every system. When I wanted to
implement such a user-program for <span class="k">\linux</span>, I came across the
differences in behavior of the various drivers, and the need for an
<span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> informing about media changes.<span class="nb">}</span>

We believe that using <span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span> to indicate that a device is being opened
for <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> commands only can be easily introduced in the <span class="k">\linux\</span>
community. All the CD-player authors will have to be informed, we can
even send in our own patches to the programs. The use of <span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span>
has most likely no influence on the behavior of the CD-players on
other operating systems than <span class="k">\linux</span>. Finally, a user can always revert
to old behavior by a call to <span class="s">$</span><span class="nb">ioctl</span><span class="o">(</span><span class="nb">file_descriptor, CDROM_CLEAR_OPTIONS,</span>
<span class="nb">CDO_USE_FFLAGS</span><span class="o">)</span><span class="s">$</span>. 

<span class="k">\subsection</span><span class="nb">{</span>The preferred strategy of <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span><span class="nb">}</span>

The routines in <span class="k">\cdromc\ </span>are designed in such a way that run-time
configuration of the behavior of <span class="k">\cdrom\ </span>devices (of <span class="nb">{</span><span class="k">\em</span> any<span class="k">\/</span><span class="nb">}</span> type)
can be carried out, by the <span class="s">$</span><span class="nb">CDROM_SET</span><span class="o">/</span><span class="nb">CLEAR_OPTIONS</span><span class="s">$</span> <span class="s">$</span><span class="nb">ioctls</span><span class="s">$</span>. Thus, various
modes of operation can be set:
<span class="k">\begin</span><span class="nb">{</span>description<span class="nb">}</span>
<span class="k">\item</span><span class="na">[$CDO_AUTO_CLOSE \mathrel| CDO_USE_FFLAGS \mathrel| CDO_LOCK$]</span> This
is the default setting. (With <span class="s">$</span><span class="nb">CDO_CHECK_TYPE</span><span class="s">$</span> it will be better, in the
future.) If the device is not yet opened by any other process, and if
the device is being opened for data (<span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span> is not set) and the
tray is found to be open, an attempt to close the tray is made. Then,
it is verified that a disc is in the drive and, if <span class="s">$</span><span class="nb">CDO_CHECK_TYPE</span><span class="s">$</span> is
set, that it contains tracks of type `data mode 1.&#39; Only if all tests
are passed is the return value zero. The door is locked to prevent file
system corruption. If the drive is opened for audio (<span class="s">$</span><span class="nb">O_NONBLOCK</span><span class="s">$</span> is
set), no actions are taken and a value of 0 will be returned. 
<span class="k">\item</span><span class="na">[$CDO_AUTO_CLOSE \mathrel| CDO_AUTO_EJECT \mathrel| CDO_LOCK$]</span> This
mimics the behavior of the current sbpcd-driver. The option flags are
ignored, the tray is closed on the first open, if necessary. Similarly,
the tray is opened on the last release, <span class="k">\ie</span>, if a <span class="k">\cdrom\ </span>is unmounted,
it is automatically ejected, such that the user can replace it.
<span class="k">\end</span><span class="nb">{</span>description<span class="nb">}</span> 
We hope that these option can convince everybody (both driver
maintainers and user program developers) to adopt the new <span class="k">\cdrom\</span>
driver scheme and option flag interpretation.

<span class="k">\newsection</span><span class="nb">{</span>Description of routines in <span class="k">\cdromc</span><span class="nb">}</span>

Only a few routines in <span class="k">\cdromc\ </span>are exported to the drivers. In this
new section we will discuss these, as well as the functions that `take
over&#39; the <span class="k">\cdrom\ </span>interface to the kernel. The header file belonging
to <span class="k">\cdromc\ </span>is called <span class="k">\cdromh</span>. Formerly, some of the contents of this
file were placed in the file <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>ucdrom.h<span class="nb">}}</span>, but this file has now been
merged back into <span class="k">\cdromh</span>.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Struct</span><span class="nv">\ </span><span class="nb">file_operations</span><span class="nv">\ </span><span class="nb">cdrom_fops</span><span class="s">$</span><span class="nb">}</span>

The contents of this structure were described in section~<span class="k">\ref</span><span class="nb">{</span>cdrom.c<span class="nb">}</span>.
A pointer to this structure is assigned to the <span class="s">$</span><span class="nb">fops</span><span class="s">$</span> field
of the <span class="s">$</span><span class="nb">struct gendisk</span><span class="s">$</span>.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">register_cdrom</span><span class="o">(</span><span class="nb"> struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info</span><span class="nv">\ </span><span class="o">*</span><span class="nb"> cdi</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function is used in about the same way one registers <span class="s">$</span><span class="nb">cdrom_fops</span><span class="s">$</span>
with the kernel, the device operations and information structures,
as described in section~<span class="k">\ref</span><span class="nb">{</span>cdrom.c<span class="nb">}</span>, should be registered with the
<span class="k">\UCD</span>:
<span class="sb">$$</span><span class="nb"></span>
<span class="nb">register_cdrom</span><span class="o">(</span><span class="nv">\&amp;</span><span class="nb">&lt;device&gt;_info</span><span class="o">))</span><span class="nb">;</span>
<span class="s">$$</span>
This function returns zero upon success, and non-zero upon
failure. The structure <span class="s">$</span><span class="nb">&lt;device&gt;_info</span><span class="s">$</span> should have a pointer to the
driver&#39;s <span class="s">$</span><span class="nb">&lt;device&gt;_dops</span><span class="s">$</span>, as in 
<span class="sb">$$</span><span class="nb"></span>
<span class="nv">\vbox</span><span class="nb">{</span><span class="nv">\halign</span><span class="nb">{&amp;$#$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">struct</span><span class="nv">\ </span><span class="nb">&amp;cdrom_device_info</span><span class="nv">\ </span><span class="nb">&lt;device&gt;_info </span><span class="o">=</span><span class="nb"> </span><span class="nv">\{\cr</span><span class="nb"></span>
<span class="nb">&amp; &lt;device&gt;_dops;</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">&amp;</span><span class="nv">\ldots\cr</span><span class="nb"></span>
<span class="nv">\}\cr</span><span class="nb"></span>
<span class="nb">}}</span><span class="s">$$</span>
Note that a driver must have one static structure, <span class="s">$</span><span class="nb">&lt;device&gt;_dops</span><span class="s">$</span>, while
it may have as many structures <span class="s">$</span><span class="nb">&lt;device&gt;_info</span><span class="s">$</span> as there are minor devices
active. <span class="s">$</span><span class="nb">Register_cdrom</span><span class="o">()</span><span class="s">$</span> builds a linked list from these. 

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Void</span><span class="nv">\ </span><span class="nb">unregister_cdrom</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_device_info </span><span class="o">*</span><span class="nb"> cdi</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

Unregistering device <span class="s">$</span><span class="nb">cdi</span><span class="s">$</span> with minor number <span class="s">$</span><span class="nb">MINOR</span><span class="o">(</span><span class="nb">cdi</span><span class="nv">\to</span><span class="nb"> dev</span><span class="o">)</span><span class="s">$</span> removes
the minor device from the list. If it was the last registered minor for
the low-level driver, this disconnects the registered device-operation
routines from the <span class="k">\cdrom\ </span>interface. This function returns zero upon
success, and non-zero upon failure.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">cdrom_open</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">inode </span><span class="o">*</span><span class="nb"> ip, struct</span><span class="nv">\ </span><span class="nb">file </span><span class="o">*</span><span class="nb"> fp</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function is not called directly by the low-level drivers, it is
listed in the standard <span class="s">$</span><span class="nb">cdrom_fops</span><span class="s">$</span>. If the VFS opens a file, this
function becomes active. A strategy is implemented in this routine,
taking care of all capabilities and options that are set in the
<span class="s">$</span><span class="nb">cdrom_device_ops</span><span class="s">$</span> connected to the device. Then, the program flow is
transferred to the device<span class="nb">_</span>dependent <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> call.

<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Void</span><span class="nv">\ </span><span class="nb">cdrom_release</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">inode </span><span class="o">*</span><span class="nb">ip, struct</span><span class="nv">\ </span><span class="nb">file</span>
<span class="o">*</span><span class="nb">fp</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>

This function implements the reverse-logic of <span class="s">$</span><span class="nb">cdrom_open</span><span class="o">()</span><span class="s">$</span>, and then
calls the device-dependent <span class="s">$</span><span class="nb">release</span><span class="o">()</span><span class="s">$</span> routine. When the use-count has
reached 0, the allocated buffers are flushed by calls to <span class="s">$</span><span class="nb">sync_dev</span><span class="o">(</span><span class="nb">dev</span><span class="o">)</span><span class="s">$</span>
and <span class="s">$</span><span class="nb">invalidate_buffers</span><span class="o">(</span><span class="nb">dev</span><span class="o">)</span><span class="s">$</span>.


<span class="k">\subsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Int</span><span class="nv">\ </span><span class="nb">cdrom_ioctl</span><span class="o">(</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">inode </span><span class="o">*</span><span class="nb">ip, struct</span><span class="nv">\ </span><span class="nb">file </span><span class="o">*</span><span class="nb">fp,</span>
<span class="nb">unsigned</span><span class="nv">\ </span><span class="nb">int</span><span class="nv">\ </span><span class="nb">cmd, unsigned</span><span class="nv">\ </span><span class="nb">long</span><span class="nv">\ </span><span class="nb">arg</span><span class="o">)</span><span class="s">$</span><span class="nb">}</span>
<span class="k">\label</span><span class="nb">{</span>cdrom-ioctl<span class="nb">}</span>

This function handles all the standard <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> requests for <span class="k">\cdrom\</span>
devices in a uniform way. The different calls fall into three
categories: <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s that can be directly implemented by device
operations, ones that are routed through the call <span class="s">$</span><span class="nb">audio_ioctl</span><span class="o">()</span><span class="s">$</span>, and
the remaining ones, that are presumable device-dependent. Generally, a
negative return value indicates an error.

<span class="k">\subsubsection</span><span class="nb">{</span>Directly implemented <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s<span class="nb">}</span>
<span class="k">\label</span><span class="nb">{</span>ioctl-direct<span class="nb">}</span>

The following `old&#39; <span class="k">\cdrom</span>-<span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s are implemented by directly
calling device-operations in <span class="s">$</span><span class="nb">cdrom_device_ops</span><span class="s">$</span>, if implemented and
not masked:
<span class="k">\begin</span><span class="nb">{</span>description<span class="nb">}</span>
<span class="k">\item</span><span class="na">[CDROMMULTISESSION]</span> Requests the last session on a <span class="k">\cdrom</span>.
<span class="k">\item</span><span class="na">[CDROMEJECT]</span> Open tray. 
<span class="k">\item</span><span class="na">[CDROMCLOSETRAY]</span> Close tray.
<span class="k">\item</span><span class="na">[CDROMEJECT_SW]</span> If <span class="s">$</span><span class="nb">arg</span><span class="nv">\not</span><span class="o">=</span><span class="m">0</span><span class="s">$</span>, set behavior to auto-close (close
tray on first open) and auto-eject (eject on last release), otherwise
set behavior to non-moving on <span class="s">$</span><span class="nb">open</span><span class="o">()</span><span class="s">$</span> and <span class="s">$</span><span class="nb">release</span><span class="o">()</span><span class="s">$</span> calls.
<span class="k">\item</span><span class="na">[CDROM_GET_MCN]</span> Get the Media Catalog Number from a CD.
<span class="k">\end</span><span class="nb">{</span>description<span class="nb">}</span>

<span class="k">\subsubsection</span><span class="nb">{</span><span class="s">$</span><span class="nb">Ioctl</span><span class="s">$</span>s routed through <span class="s">$</span><span class="nb">audio_ioctl</span><span class="o">()</span><span class="s">$</span><span class="nb">}</span>
<span class="k">\label</span><span class="nb">{</span>ioctl-audio<span class="nb">}</span>

The following set of <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s are all implemented through a call to
the <span class="s">$</span><span class="nb">cdrom_fops</span><span class="s">$</span> function <span class="s">$</span><span class="nb">audio_ioctl</span><span class="o">()</span><span class="s">$</span>. Memory checks and
allocation are performed in <span class="s">$</span><span class="nb">cdrom_ioctl</span><span class="o">()</span><span class="s">$</span>, and also sanitization of
address format (<span class="s">$</span><span class="nb">CDROM_LBA</span><span class="s">$</span>/<span class="s">$</span><span class="nb">CDROM_MSF</span><span class="s">$</span>) is done.
<span class="k">\begin</span><span class="nb">{</span>description<span class="nb">}</span>
<span class="k">\item</span><span class="na">[CDROMSUBCHNL]</span> Get sub-channel data in argument <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type <span class="s">$</span><span class="nb">struct</span><span class="err">\</span><span class="nb"></span>
<span class="nb">cdrom_subchnl </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROMREADTOCHDR]</span> Read Table of Contents header, in <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type
<span class="s">$</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_tochdr </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>. 
<span class="k">\item</span><span class="na">[CDROMREADTOCENTRY]</span> Read a Table of Contents entry in <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> and
specified by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type <span class="s">$</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_tocentry </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROMPLAYMSF]</span> Play audio fragment specified in Minute, Second,
Frame format, delimited by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type <span class="s">$</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb">cdrom_msf </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROMPLAYTRKIND]</span> Play audio fragment in track-index format
delimited by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type <span class="s">$</span><span class="nb">struct</span><span class="nv">\ \penalty</span><span class="o">-</span><span class="m">1000</span><span class="nb"> cdrom_ti </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROMVOLCTRL]</span> Set volume specified by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type <span class="s">$</span><span class="nb">struct</span><span class="err">\</span><span class="nb"></span>
<span class="nb">cdrom_volctrl </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROMVOLREAD]</span> Read volume into by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> of type <span class="s">$</span><span class="nb">struct</span><span class="err">\</span><span class="nb"></span>
<span class="nb">cdrom_volctrl </span><span class="o">*</span><span class="nb">{}</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROMSTART]</span> Spin up disc.
<span class="k">\item</span><span class="na">[CDROMSTOP]</span> Stop playback of audio fragment.
<span class="k">\item</span><span class="na">[CDROMPAUSE]</span> Pause playback of audio fragment.
<span class="k">\item</span><span class="na">[CDROMRESUME]</span> Resume playing.
<span class="k">\end</span><span class="nb">{</span>description<span class="nb">}</span>

<span class="k">\subsubsection</span><span class="nb">{</span>New <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s in <span class="k">\cdromc</span><span class="nb">}</span>

The following <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s have been introduced to allow user programs to
control the behavior of individual <span class="k">\cdrom\ </span>devices. New <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>
commands can be identified by the underscores in their names.
<span class="k">\begin</span><span class="nb">{</span>description<span class="nb">}</span>
<span class="k">\item</span><span class="na">[CDROM_SET_OPTIONS]</span> Set options specified by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span>. Returns the
option flag register after modification. Use  <span class="s">$</span><span class="nb">arg </span><span class="o">=</span><span class="nb"> </span><span class="nv">\rm</span><span class="m">0</span><span class="s">$</span> for reading
the current flags.
<span class="k">\item</span><span class="na">[CDROM_CLEAR_OPTIONS]</span> Clear options specified by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span>. Returns
  the option flag register after modification.
<span class="k">\item</span><span class="na">[CDROM_SELECT_SPEED]</span> Select head-rate speed of disc specified as
  by <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> in units of standard cdrom speed (176<span class="k">\,</span>kB/sec raw data or
  150<span class="k">\,</span>kB/sec file system data). The value 0 means `auto-select&#39;, <span class="k">\ie</span>,
  play audio discs at real time and data discs at maximum speed. The value
  <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> is checked against the maximum head rate of the drive found in the
  <span class="s">$</span><span class="nb">cdrom_dops</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROM_SELECT_DISC]</span> Select disc numbered <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> from a juke-box.
  First disc is numbered 0. The number <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> is checked against the
  maximum number of discs in the juke-box found in the <span class="s">$</span><span class="nb">cdrom_dops</span><span class="s">$</span>.
<span class="k">\item</span><span class="na">[CDROM_MEDIA_CHANGED]</span> Returns 1 if a disc has been changed since
  the last call. Note that calls to <span class="s">$</span><span class="nb">cdrom_media_changed</span><span class="s">$</span> by the VFS
  are treated by an independent queue, so both mechanisms will detect
  a media change once. For juke-boxes, an extra argument <span class="s">$</span><span class="nb">arg</span><span class="s">$</span>
  specifies the slot for which the information is given. The special
  value <span class="s">$</span><span class="nb">CDSL_CURRENT</span><span class="s">$</span> requests that information about the currently
  selected slot be returned.
<span class="k">\item</span><span class="na">[CDROM_DRIVE_STATUS]</span> Returns the status of the drive by a call to
  <span class="s">$</span><span class="nb">drive_status</span><span class="o">()</span><span class="s">$</span>. Return values are defined in section~<span class="k">\ref</span><span class="nb">{</span>drive
   status<span class="nb">}</span>. Note that this call doesn&#39;t return information on the
  current playing activity of the drive; this can be polled through an
  <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> call to <span class="s">$</span><span class="nb">CDROMSUBCHNL</span><span class="s">$</span>. For juke-boxes, an extra argument
  <span class="s">$</span><span class="nb">arg</span><span class="s">$</span> specifies the slot for which (possibly limited) information is
  given. The special value <span class="s">$</span><span class="nb">CDSL_CURRENT</span><span class="s">$</span> requests that information
  about the currently selected slot be returned.
<span class="k">\item</span><span class="na">[CDROM_DISC_STATUS]</span> Returns the type of the disc currently in the
  drive.  It should be viewed as a complement to <span class="s">$</span><span class="nb">CDROM_DRIVE_STATUS</span><span class="s">$</span>.
  This <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> can provide <span class="k">\emph</span> <span class="nb">{</span>some<span class="nb">}</span> information about the current
  disc that is inserted in the drive.  This functionality used to be
  implemented in the low level drivers, but is now carried out
  entirely in <span class="k">\UCD</span>.
  
  The history of development of the CD&#39;s use as a carrier medium for
  various digital information has lead to many different disc types.
  This <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> is useful only in the case that CDs have <span class="k">\emph</span> <span class="nb">{</span>only
    one<span class="nb">}</span> type of data on them.  While this is often the case, it is
  also very common for CDs to have some tracks with data, and some
  tracks with audio.  Because this is an existing interface, rather
  than fixing this interface by changing the assumptions it was made
  under, thereby breaking all user applications that use this
  function, the <span class="k">\UCD\ </span>implements this <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> as follows: If the CD in
  question has audio tracks on it, and it has absolutely no CD-I, XA,
  or data tracks on it, it will be reported as <span class="s">$</span><span class="nb">CDS_AUDIO</span><span class="s">$</span>.  If it has
  both audio and data tracks, it will return <span class="s">$</span><span class="nb">CDS_MIXED</span><span class="s">$</span>.  If there
  are no audio tracks on the disc, and if the CD in question has any
  CD-I tracks on it, it will be reported as <span class="s">$</span><span class="nb">CDS_XA_</span><span class="m">2</span><span class="nb">_</span><span class="m">2</span><span class="s">$</span>.  Failing
  that, if the CD in question has any XA tracks on it, it will be
  reported as <span class="s">$</span><span class="nb">CDS_XA_</span><span class="m">2</span><span class="nb">_</span><span class="m">1</span><span class="s">$</span>.  Finally, if the CD in question has any
  data tracks on it, it will be reported as a data CD (<span class="s">$</span><span class="nb">CDS_DATA_</span><span class="m">1</span><span class="s">$</span>).

  This <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> can return:
  <span class="sb">$$</span><span class="nb"></span>
<span class="nb">  </span><span class="nv">\halign</span><span class="nb">{$#$</span><span class="nv">\ \hfil</span><span class="nb">&amp;$</span><span class="o">/*</span><span class="nb">$ </span><span class="nv">\rm</span><span class="nb"># $</span><span class="o">*/</span><span class="nb">$</span><span class="nv">\hfil\cr</span><span class="nb"></span>
<span class="nb">    CDS_NO_INFO&amp; no information available</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    CDS_NO_DISC&amp; no disc is inserted, or tray is opened</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    CDS_AUDIO&amp; Audio disc </span><span class="o">(</span><span class="m">2352</span><span class="nb"> audio bytes</span><span class="o">/</span><span class="nb">frame</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    CDS_DATA_</span><span class="m">1</span><span class="nb">&amp; data disc, mode </span><span class="m">1</span><span class="nb"> </span><span class="o">(</span><span class="m">2048</span><span class="nb"> user bytes</span><span class="o">/</span><span class="nb">frame</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    CDS_XA_</span><span class="m">2</span><span class="nb">_</span><span class="m">1</span><span class="nb">&amp; mixed data </span><span class="o">(</span><span class="nb">XA</span><span class="o">)</span><span class="nb">, mode </span><span class="m">2</span><span class="nb">, form </span><span class="m">1</span><span class="nb"> </span><span class="o">(</span><span class="m">2048</span><span class="nb"> user bytes</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    CDS_XA_</span><span class="m">2</span><span class="nb">_</span><span class="m">2</span><span class="nb">&amp; mixed data </span><span class="o">(</span><span class="nb">XA</span><span class="o">)</span><span class="nb">, mode </span><span class="m">2</span><span class="nb">, form </span><span class="m">1</span><span class="nb"> </span><span class="o">(</span><span class="m">2324</span><span class="nb">  user bytes</span><span class="o">)</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    CDS_MIXED&amp; mixed audio</span><span class="o">/</span><span class="nb">data disc</span><span class="nv">\cr</span><span class="nb"></span>
<span class="nb">    }</span>
<span class="nb">  </span><span class="s">$$</span>
  For some information concerning frame layout of the various disc
  types, see a recent version of <span class="k">\cdromh</span>.

<span class="k">\item</span><span class="na">[CDROM_CHANGER_NSLOTS]</span> Returns the number of slots in a
  juke-box. 
<span class="k">\item</span><span class="na">[CDROMRESET]</span> Reset the drive. 
<span class="k">\item</span><span class="na">[CDROM_GET_CAPABILITY]</span> Returns the <span class="s">$</span><span class="nb">capability</span><span class="s">$</span> flags for the
  drive. Refer to section <span class="k">\ref</span><span class="nb">{</span>capability<span class="nb">}</span> for more information on
  these flags.
<span class="k">\item</span><span class="na">[CDROM_LOCKDOOR]</span> Locks the door of the drive. <span class="s">$</span><span class="nb">arg </span><span class="o">==</span><span class="nb"> </span><span class="nv">\rm</span><span class="m">0</span><span class="s">$</span>
  unlocks the door, any other value locks it.
<span class="k">\item</span><span class="na">[CDROM_DEBUG]</span> Turns on debugging info. Only root is allowed
  to do this. Same semantics as CDROM<span class="nb">_</span>LOCKDOOR.
<span class="k">\end</span><span class="nb">{</span>description<span class="nb">}</span>

<span class="k">\subsubsection</span><span class="nb">{</span>Device dependent <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s<span class="nb">}</span>

Finally, all other <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s are passed to the function <span class="s">$</span><span class="nb">dev_ioctl</span><span class="o">()</span><span class="s">$</span>,
if implemented. No memory allocation or verification is carried out. 

<span class="k">\newsection</span><span class="nb">{</span>How to update your driver<span class="nb">}</span>

<span class="k">\begin</span><span class="nb">{</span>enumerate<span class="nb">}</span>
<span class="k">\item</span> Make a backup of your current driver. 
<span class="k">\item</span> Get hold of the files <span class="k">\cdromc\ </span>and <span class="k">\cdromh</span>, they should be in
  the directory tree that came with this documentation.
<span class="k">\item</span> Make sure you include <span class="k">\cdromh</span>.
<span class="k">\item</span> Change the 3rd argument of <span class="s">$</span><span class="nb">register_blkdev</span><span class="s">$</span> from
<span class="s">$</span><span class="nv">\&amp;</span><span class="nb">&lt;your</span><span class="o">-</span><span class="nb">drive&gt;_fops</span><span class="s">$</span> to <span class="s">$</span><span class="nv">\&amp;</span><span class="nb">cdrom_fops</span><span class="s">$</span>. 
<span class="k">\item</span> Just after that line, add the following to register with the <span class="k">\UCD</span>:
  <span class="sb">$$</span><span class="nb">register_cdrom</span><span class="o">(</span><span class="nv">\&amp;</span><span class="nb">&lt;your</span><span class="o">-</span><span class="nb">drive&gt;_info</span><span class="o">)</span><span class="nb">;</span><span class="s">$$</span>
  Similarly, add a call to <span class="s">$</span><span class="nb">unregister_cdrom</span><span class="o">()</span><span class="s">$</span> at the appropriate place.
<span class="k">\item</span> Copy an example of the device-operations <span class="s">$</span><span class="nb">struct</span><span class="s">$</span> to your
  source, <span class="k">\eg</span>, from <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>cm206.c<span class="nb">}}</span> <span class="s">$</span><span class="nb">cm</span><span class="m">206</span><span class="nb">_dops</span><span class="s">$</span>, and change all
  entries to names corresponding to your driver, or names you just
  happen to like. If your driver doesn&#39;t support a certain function,
  make the entry <span class="s">$</span><span class="nb">NULL</span><span class="s">$</span>. At the entry <span class="s">$</span><span class="nb">capability</span><span class="s">$</span> you should list all
  capabilities your driver currently supports. If your driver
  has a capability that is not listed, please send me a message.
<span class="k">\item</span> Copy the <span class="s">$</span><span class="nb">cdrom_device_info</span><span class="s">$</span> declaration from the same example
  driver, and modify the entries according to your needs. If your
  driver dynamically determines the capabilities of the hardware, this
  structure should also be declared dynamically. 
<span class="k">\item</span> Implement all functions in your <span class="s">$</span><span class="nb">&lt;device&gt;_dops</span><span class="s">$</span> structure,
  according to prototypes listed in <span class="k">\cdromh</span>, and specifications given
  in section~<span class="k">\ref</span><span class="nb">{</span>cdrom.c<span class="nb">}</span>. Most likely you have already implemented
  the code in a large part, and you will almost certainly need to adapt the
  prototype and return values.
<span class="k">\item</span> Rename your <span class="s">$</span><span class="nb">&lt;device&gt;_ioctl</span><span class="o">()</span><span class="s">$</span> function to <span class="s">$</span><span class="nb">audio_ioctl</span><span class="s">$</span> and
  change the prototype a little. Remove entries listed in the first
  part in section~<span class="k">\ref</span><span class="nb">{</span>cdrom-ioctl<span class="nb">}</span>, if your code was OK, these are
  just calls to the routines you adapted in the previous step.
<span class="k">\item</span> You may remove all remaining memory checking code in the
  <span class="s">$</span><span class="nb">audio_ioctl</span><span class="o">()</span><span class="s">$</span> function that deals with audio commands (these are
  listed in the second part of section~<span class="k">\ref</span><span class="nb">{</span>cdrom-ioctl<span class="nb">}</span>). There is no
  need for memory allocation either, so most <span class="s">$</span><span class="nb">case</span><span class="s">$</span>s in the <span class="s">$</span><span class="nb">switch</span><span class="s">$</span>
  statement look similar to:
  <span class="sb">$$</span><span class="nb"></span>
<span class="nb">  case</span><span class="nv">\ </span><span class="nb">CDROMREADTOCENTRY</span><span class="nv">\colon</span><span class="nb"> get_toc_entry</span><span class="nv">\bigl</span><span class="o">((</span><span class="nb">struct</span><span class="nv">\ </span><span class="nb"></span>
<span class="nb">  cdrom_tocentry </span><span class="o">*</span><span class="nb">{}</span><span class="o">)</span><span class="nv">\ </span><span class="nb">arg</span><span class="nv">\bigr</span><span class="o">)</span><span class="nb">;</span>
<span class="nb">  </span><span class="s">$$</span>
<span class="k">\item</span> All remaining <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span> cases must be moved to a separate
  function, <span class="s">$</span><span class="nb">&lt;device&gt;_ioctl</span><span class="s">$</span>, the device-dependent <span class="s">$</span><span class="nb">ioctl</span><span class="s">$</span>s. Note that
  memory checking and allocation must be kept in this code!
<span class="k">\item</span> Change the prototypes of <span class="s">$</span><span class="nb">&lt;device&gt;_open</span><span class="o">()</span><span class="s">$</span> and
  <span class="s">$</span><span class="nb">&lt;device&gt;_release</span><span class="o">()</span><span class="s">$</span>, and remove any strategic code (<span class="k">\ie</span>, tray
  movement, door locking, etc.).
<span class="k">\item</span> Try to recompile the drivers. We advise you to use modules, both
  for <span class="nb">{</span><span class="k">\tt</span> <span class="nb">{</span>cdrom.o<span class="nb">}}</span> and your driver, as debugging is much easier this
  way.
<span class="k">\end</span><span class="nb">{</span>enumerate<span class="nb">}</span> 

<span class="k">\newsection</span><span class="nb">{</span>Thanks<span class="nb">}</span>

Thanks to all the people involved.  First, Erik Andersen, who has
taken over the torch in maintaining <span class="k">\cdromc\ </span>and integrating much
<span class="k">\cdrom</span>-related code in the 2.1-kernel.  Thanks to Scott Snyder and
Gerd Knorr, who were the first to implement this interface for SCSI
and IDE-CD drivers and added many ideas for extension of the data
structures relative to kernel~2.0.  Further thanks to Heiko Ei<span class="nb">{</span><span class="k">\sz</span><span class="nb">}</span>feldt,
Thomas Quinot, Jon Tombs, Ken Pizzini, Eberhard M<span class="k">\&quot;</span>onkeberg and Andrew
Kroll, the <span class="k">\linux\ \cdrom\ </span>device driver developers who were kind
enough to give suggestions and criticisms during the writing. Finally
of course, I want to thank Linus Torvalds for making this possible in
the first place.

<span class="k">\vfill</span>
<span class="s">$</span><span class="nb"> </span><span class="nv">\version\ </span><span class="s">$</span>
<span class="k">\eject</span>
<span class="k">\end</span><span class="nb">{</span>document<span class="nb">}</span>
</pre></div>
</code></pre></td></tr></table>
</div> <!-- class=content -->
<div id="lfcollabprojects-footer">
  <div class="gray-diagonal">
    <div class="footer-inner">
      <p>
        &copy; 2015
        <a href="https://opnfv.org/">Open Platform for NFV Project, Inc</a>., a
        Linux Foundation Collaborative Project. All Rights Reserved.
      </p>
      <p>
        Open Platform for NFV and OPNFV are trademarks of the Open Platform for
        NFV Project, Inc.
      </p>
      <p>
        Linux Foundation is a registered trademark of The Linux Foundation.
        Linux is a registered
        <a
          href="http://www.linuxfoundation.org/programs/legal/trademark"
          title="Linux Mark Institute"
          >trademark</a
        >
        of Linus Torvalds.
      </p>
      <p>
        Please see our
        <a href="https://opnfv.org/about/bylaws-and-policies/terms-use"
          >terms of use</a
        >,
        <a href="https://opnfv.org/about/bylaws-and-policies/trademarks"
          >trademark policy</a
        >, and
        <a href="https://opnfv.org/about/bylaws-and-policies/privacy-policy"
          >privacy policy</a
        >.
      </p>
    </div>
  </div>
</div>
</div> <!-- id=cgit -->
</body>
</html>
