tag:blogger.com,1999:blog-40920205027315216602024-03-06T00:27:09.925-08:00csw.dawncsw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.comBlogger36125tag:blogger.com,1999:blog-4092020502731521660.post-25681342288913895742020-02-22T23:23:00.004-08:002020-02-29T17:50:18.469-08:00使用 Gin / Laravel 建立 Line Bot<br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">下載即用,快拿去。</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">雙版本:</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">Gin ( Golang )</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">Laravel ( PHP )</span><br />
<br style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;" />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">快速建立 屬於自已的 Line Bot 簡易 購物機器人</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">( 使用 Gin / Laravel + MySQL )</span><br />
<br style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;" />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">1. 支持 Docker 運行 (也支持 本機直接執行)。</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">2. 馬上下載,馬上可用,只需設定好你的 Line Bot 相關設定。</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">3. 匯入我提供的資料庫資料。</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">4. 一支簡單的 Line 簡易購物 Bot 就完成了。</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">5. Enjoy。</span><br />
<br style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;" />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">開放原始碼:</span><br />
<a href="https://github.com/wangchenshu/gin-group-buy" rel="nofollow" style="background-color: white; color: #6611cc; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; pointer-events: none; white-space: pre-wrap;" target="_blank">https://github.com/wangchenshu/gin-group-buy</a><br />
<a href="https://github.com/wangchenshu/laravel-group-buy" rel="nofollow" style="background-color: white; color: #6611cc; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; pointer-events: none; white-space: pre-wrap;" target="_blank">https://github.com/wangchenshu/laravel-group-buy</a><br />
<br style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;" />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">拿去用,真的別客氣。</span><br />
<br style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;" />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">成品 Demo 如下:</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">咕嚕buy</span><br />
<br style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;" />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">LINE:</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">加入好友 ID: @</span><span style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;">808wnwnn</span><br />
<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">加入好友傳送門 測試: </span><a href="https://line.me/R/ti/p/%40778dwszx" rel="nofollow" style="background-color: white; color: #6611cc; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; pointer-events: none; white-space: pre-wrap;" target="_blank">https://line.me/R/ti/p/%40</a><span style="background-color: white; color: #202124; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-variant-ligatures: none; letter-spacing: 0.1px; white-space: pre-wrap;">808wnwnn</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwtkLTDigC_NzzX-1s1CZxBaRc5lwfaLvbgoMNh8-x31ZKugCOHCPNgBnEgFeu8-i4xYvbQ155alpjBk-cvFw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxmQyecGh7JgqM0t5tMZ4_qvNzel5Wn9QnFmO5WbwqcagQeEZkJ-qWLdLxEScfowGlf9JUOl9No-3KoImGRwQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-14112560797580186912020-01-04T05:57:00.001-08:002020-01-04T05:57:09.494-08:00我的 Go reflect 筆記<br />
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Menlo, Monaco, "Courier New", monospace; font-size: 14px; line-height: 21px; white-space: pre;">
<div>
<span style="color: #569cd6;">package</span> main</div>
<br /><div>
<span style="color: #569cd6;">import</span> (</div>
<div>
<span style="color: #ce9178;">"fmt"</span></div>
<div>
<span style="color: #ce9178;">"reflect"</span></div>
<div>
)</div>
<br /><div>
<span style="color: #569cd6;">type</span> <span style="color: #4ec9b0;">S1</span> <span style="color: #569cd6;">struct</span> {</div>
<div>
Name <span style="color: #4ec9b0;">string</span></div>
<div>
Age <span style="color: #4ec9b0;">int</span></div>
<div>
}</div>
<br /><div>
<span style="color: #569cd6;">type</span> <span style="color: #4ec9b0;">S2</span> <span style="color: #569cd6;">struct</span> {</div>
<div>
Name <span style="color: #4ec9b0;">string</span></div>
<div>
Info <span style="color: #4ec9b0;">string</span></div>
<div>
}</div>
<br /><div>
<span style="color: #569cd6;">type</span> <span style="color: #4ec9b0;">S3</span> <span style="color: #569cd6;">struct</span> {</div>
<div>
U <span style="color: #4ec9b0;">string</span></div>
<div>
V <span style="color: #4ec9b0;">string</span></div>
<div>
}</div>
<br /><div>
<span style="color: #569cd6;">type</span> <span style="color: #4ec9b0;">S4</span> <span style="color: #569cd6;">struct</span> {</div>
<div>
K <span style="color: #4ec9b0;">string</span></div>
<div>
V <span style="color: #4ec9b0;">string</span></div>
<div>
}</div>
<br /><div>
<span style="color: #569cd6;">func</span> <span style="color: #dcdcaa;">main</span>() {</div>
<div>
<span style="color: #9cdcfe;">s1</span> := S1{</div>
<div>
Name: <span style="color: #ce9178;">"s1: oooo"</span>,</div>
<div>
Age: <span style="color: #b5cea8;">10</span>,</div>
<div>
}</div>
<br /><div>
<span style="color: #9cdcfe;">s2</span> := S2{</div>
<div>
Name: <span style="color: #ce9178;">"s2: test"</span>,</div>
<div>
Info: <span style="color: #ce9178;">"s2: qqq"</span>,</div>
<div>
}</div>
<br /><div>
<span style="color: #9cdcfe;">s3</span> := S3{</div>
<div>
U: <span style="color: #ce9178;">"s3: 1"</span>,</div>
<div>
V: <span style="color: #ce9178;">"s3: A"</span>,</div>
<div>
}</div>
<br /><div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"before change: "</span>)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s1)</div>
<div>
<span style="color: #dcdcaa;">testReflect</span>(&s1)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"after change: "</span>)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s1)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"======"</span>)</div>
<br /><div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"before change: "</span>)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s2)</div>
<div>
<span style="color: #dcdcaa;">testReflect</span>(&s2)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"after change: "</span>)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s2)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"======"</span>)</div>
<br /><div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"before change: "</span>)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s3)</div>
<div>
<span style="color: #9cdcfe;">rType</span> := reflect.<span style="color: #dcdcaa;">TypeOf</span>(s3)</div>
<div>
<span style="color: #9cdcfe;">rValue</span> := reflect.<span style="color: #dcdcaa;">ValueOf</span>(&s3)</div>
<br /><div>
<span style="color: #c586c0;">for</span> <span style="color: #9cdcfe;">i</span> := <span style="color: #b5cea8;">0</span>; i < rType.<span style="color: #dcdcaa;">NumField</span>(); i++ {</div>
<div>
rValue.<span style="color: #dcdcaa;">Elem</span>().<span style="color: #dcdcaa;">Field</span>(i).<span style="color: #dcdcaa;">SetString</span>(fmt.<span style="color: #dcdcaa;">Sprintf</span>(<span style="color: #ce9178;">"s3: %d"</span>, i))</div>
<div>
}</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"after change: "</span>)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s3)</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(<span style="color: #ce9178;">"======"</span>)</div>
<br /><div>
<span style="color: #9cdcfe;">s4</span> := <span style="color: #dcdcaa;">testReflect</span>(S4{</div>
<div>
K: <span style="color: #ce9178;">"s4: a000"</span>,</div>
<div>
V: <span style="color: #ce9178;">"s4: p777"</span>,</div>
<div>
})</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s4)</div>
<br /><div>
<span style="color: #9cdcfe;">s4Ptr</span> := <span style="color: #dcdcaa;">testReflect</span>(&S4{</div>
<div>
K: <span style="color: #ce9178;">"q111"</span>,</div>
<div>
V: <span style="color: #ce9178;">"q222"</span>,</div>
<div>
})</div>
<div>
fmt.<span style="color: #dcdcaa;">Println</span>(s4Ptr)</div>
<div>
}</div>
<br /><div>
<span style="color: #569cd6;">func</span> <span style="color: #dcdcaa;">testReflect</span>(i <span style="color: #569cd6;">interface</span>{}) <span style="color: #569cd6;">interface</span>{} {</div>
<div>
<span style="color: #9cdcfe;">rValueOf</span> := reflect.<span style="color: #dcdcaa;">ValueOf</span>(i)</div>
<div>
<span style="color: #9cdcfe;">ret</span> := i</div>
<br /><div>
<span style="color: #c586c0;">switch</span> i.(type) {</div>
<div>
<span style="color: #c586c0;">case</span> *S1:</div>
<div>
<span style="color: #9cdcfe;">ret</span> := rValueOf.<span style="color: #dcdcaa;">Interface</span>().(*S1)</div>
<div>
<span style="color: #9cdcfe;">ret.Name</span> = <span style="color: #ce9178;">"*s1: rrrr"</span></div>
<div>
<span style="color: #9cdcfe;">ret.Age</span> = <span style="color: #b5cea8;">19</span></div>
<div>
<span style="color: #c586c0;">case</span> *S2:</div>
<div>
<span style="color: #9cdcfe;">ret</span> := rValueOf.<span style="color: #dcdcaa;">Interface</span>().(*S2)</div>
<div>
<span style="color: #9cdcfe;">ret.Name</span> = <span style="color: #ce9178;">"*s2: 222"</span></div>
<div>
<span style="color: #9cdcfe;">ret.Info</span> = <span style="color: #ce9178;">"*s2: good"</span></div>
<div>
<span style="color: #c586c0;">case</span> S3:</div>
<div>
<span style="color: #9cdcfe;">s3</span> := reflect.<span style="color: #dcdcaa;">New</span>(reflect.<span style="color: #dcdcaa;">TypeOf</span>(i))</div>
<div>
<span style="color: #9cdcfe;">newS3</span> := s3.<span style="color: #dcdcaa;">Elem</span>().<span style="color: #dcdcaa;">Interface</span>().(S3)</div>
<div>
<span style="color: #9cdcfe;">newS3.U</span> = <span style="color: #ce9178;">"s3: test"</span></div>
<div>
<span style="color: #9cdcfe;">newS3.V</span> = <span style="color: #ce9178;">"s3: 1234"</span></div>
<div>
<span style="color: #c586c0;">return</span> newS3</div>
<div>
<span style="color: #c586c0;">case</span> S4:</div>
<div>
<span style="color: #9cdcfe;">rValue</span> := reflect.<span style="color: #dcdcaa;">ValueOf</span>(&i)</div>
<div>
<span style="color: #9cdcfe;">s4</span> := rValue.<span style="color: #dcdcaa;">Elem</span>().<span style="color: #dcdcaa;">Interface</span>().(S4)</div>
<div>
<span style="color: #9cdcfe;">s4.K</span> = <span style="color: #ce9178;">"s4: 0"</span></div>
<div>
<span style="color: #9cdcfe;">s4.V</span> = <span style="color: #ce9178;">"s4: 1"</span></div>
<div>
<span style="color: #c586c0;">return</span> s4</div>
<div>
<span style="color: #c586c0;">case</span> *S4:</div>
<div>
<span style="color: #9cdcfe;">rValue</span> := reflect.<span style="color: #dcdcaa;">ValueOf</span>(i)</div>
<div>
<span style="color: #c586c0;">for</span> <span style="color: #9cdcfe;">i</span> := <span style="color: #b5cea8;">0</span>; i < rValue.<span style="color: #dcdcaa;">Elem</span>().<span style="color: #dcdcaa;">NumField</span>(); i++ {</div>
<div>
rValue.<span style="color: #dcdcaa;">Elem</span>().<span style="color: #dcdcaa;">Field</span>(i).<span style="color: #dcdcaa;">SetString</span>(fmt.<span style="color: #dcdcaa;">Sprintf</span>(<span style="color: #ce9178;">"*s4: %d"</span>, i))</div>
<div>
}</div>
<div>
<span style="color: #c586c0;">return</span> rValue</div>
<div>
}</div>
<br /><div>
<span style="color: #c586c0;">return</span> ret</div>
<div>
}</div>
</div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-47830353606786493772019-12-29T00:46:00.001-08:002020-02-29T17:52:14.728-08:00好語 Go - 一個使用 Golang 寫的 Line Bot<br />
原始碼: <a href="https://github.com/wangchenshu/gin-eco">https://github.com/wangchenshu/gin-eco</a><br />
<br />
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Menlo, Monaco, "Courier New", monospace; font-size: 14px; line-height: 21px; white-space: pre;">
<div>
<span style="color: #569cd6; font-weight: bold;"># 禪念 好語 Go</span></div>
<div>
<span style="color: #6a9955;">></span> 好語 Go Line Bot 2.1,</div>
<div>
<span style="color: #6a9955;">></span> 為了給大家更好的用戶體驗,</div>
<div>
<span style="color: #6a9955;">></span> 持續改善回應的穩定度,</div>
<div>
<span style="color: #6a9955;">></span> 邀請大家一起來使用,</div>
<div>
<span style="color: #6a9955;">></span> 無間斷提供好語給各位。</div>
<div>
<span style="color: #6a9955;">></span></div>
<div>
<span style="color: #6a9955;">></span> 希望大家多多支持禪念,</div>
<div>
<span style="color: #6a9955;">></span> 並把好語散播給更多的人,</div>
<div>
<span style="color: #6a9955;">></span> 禪念感謝大家。</div>
<br />
<div>
<span style="color: #569cd6; font-weight: bold;">## 好語 Go 2.1 版</span></div>
<div>
<span style="color: #569cd6; font-weight: bold;">### 提供以下四種語:</span></div>
<div>
<span style="color: #6796e6;">*</span> 好語</div>
<div>
<span style="color: #6796e6;">*</span> 自在語</div>
<div>
<span style="color: #6796e6;">*</span> 靜思語</div>
<div>
<span style="color: #6796e6;">*</span> 勵志語</div>
<br />
<div>
<span style="color: #569cd6; font-weight: bold;">## 歡迎關注</span></div>
<div>
<span style="color: #569cd6; font-weight: bold;">### FB</span></div>
<div>
<span style="color: #6796e6;">*</span> FB 請搜尋: 禪念</div>
<div>
<span style="color: #6796e6;">*</span> [<span style="color: #ce9178;">禪念粉絲頁</span>](<span style="text-decoration-line: underline;">https://www.facebook.com/%E7%A6%AA%E5%BF%B5-1062013710643908/</span>)</div>
<div>
<span style="color: #6796e6;">*</span> [<span style="color: #ce9178;">FB Messenger</span>](<span style="text-decoration-line: underline;">http://m.me/1062013710643908</span>)</div>
<br />
<div>
<span style="color: #569cd6; font-weight: bold;">### LINE</span></div>
<div>
<span style="color: #6796e6;">*</span> 加入好友 ID: @<span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">748eeivc</span></div>
<div>
<span style="color: #6796e6;">*</span> [<span style="color: #ce9178;">加入好友傳送門</span>](<span style="text-decoration-line: underline;">https://line.me/R/ti/p/%40</span><span style="background-color: white; color: #202124; font-family: "roboto" , "arial" , sans-serif; font-size: 16px; letter-spacing: 0.1px; white-space: pre-wrap;">748eeivc</span>)</div>
</div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-69230464980569818132019-11-30T06:14:00.001-08:002019-12-03T06:26:44.851-08:00Gin + Gorm + Mysql + JWT + Chatfuel<br />
<div style="background-color: white; color: #1d2129; font-family: Helvetica, Arial, sans-serif; font-size: 15px; margin-bottom: 6px;">
小弟 初版 Golang 後端 API</div>
<div style="background-color: white; margin-bottom: 6px; margin-top: 6px;">
<div style="color: #1d2129; font-family: helvetica, arial, sans-serif; font-size: 15px;">
Gin + Gorm + Mysql + JWT + Chatfuel</div>
<div style="color: #1d2129; font-family: helvetica, arial, sans-serif; font-size: 15px;">
純後端 API(含 Chatfuel)</div>
<div style="color: #1d2129; font-family: helvetica, arial, sans-serif; font-size: 15px;">
內含 mysql db: my_projcet.sql (記得改成本地端連線帳號密碼)</div>
<span class="text_exposed_show" style="display: inline;"><span style="color: #1d2129; font-family: helvetica, arial, sans-serif;"><span style="font-size: 15px;">此案請搭配 </span></span></span><a href="https://github.com/wangchenshu/angular8-my-project" style="font-family: helvetica, arial, sans-serif; font-size: 15px;">angular8-my-project</a> <span style="color: #1d2129; font-family: helvetica, arial, sans-serif; font-size: 15px;">一起服用。</span><br />
<span class="text_exposed_show" style="display: inline;"><span style="color: #1d2129; font-family: helvetica, arial, sans-serif;"><span style="font-size: 15px;">支持 JWT (Json Web Token)(改進中)</span></span><br /><span style="color: #1d2129; font-family: helvetica, arial, sans-serif;"><span style="font-size: 15px;">原始碼在此:</span></span><br /><a data-ft="{"tn":"-U"}" data-lynx-mode="asynclazy" data-lynx-uri="https://l.facebook.com/l.php?u=https%3A%2F%2Fgithub.com%2Fwangchenshu%2Fmy-gin-github%3Ffbclid%3DIwAR0xZMmrn-XGBVdyenEcqT1wC36ewPW-VQUbn8-qybqVXUJ2gnRX1MGw0rg&h=AT3ctqbZlXWTrh4Bdd9bzkCSGI8CerJybEA0tpgl2mZBU2mOiNTTQ-5cqt-VorjyPjFCkgg6aYIePhwKIPn1g52mwZWC9Kvz4MNmzQjnU5qE504G2R_ufRkQIIRpX8yJonMYRarhzazg_1R8ldRv4CNDeA" href="https://github.com/wangchenshu/my-gin-github?fbclid=IwAR0xZMmrn-XGBVdyenEcqT1wC36ewPW-VQUbn8-qybqVXUJ2gnRX1MGw0rg" rel="noopener nofollow" style="color: #385898; cursor: pointer; font-family: inherit; font-size: 15px;" target="_blank">https://github.com/wangchenshu/my-gin-github</a></span></div>
<div style="background-color: white; color: #1d2129; font-family: Helvetica, Arial, sans-serif; font-size: 15px; margin-bottom: 6px; margin-top: 6px;">
<br /></div>
<div style="background-color: white; color: #1d2129; font-family: Helvetica, Arial, sans-serif; font-size: 15px; margin-bottom: 6px; margin-top: 6px;">
所有 API 接口:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp5a7dz-9f7KjlO49hplzcYWbWD_fOPuQjvlegrRlUxUif-nn-M6VxjVeyWN4BwUH5htAHrYusitQtdUmCA7OybDTCv2-HdqTkq2tDWrbmbE0nBA1LDqbW5yS_MZ4JcHzdxezDnfP0iy4/s1600/all_api.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp5a7dz-9f7KjlO49hplzcYWbWD_fOPuQjvlegrRlUxUif-nn-M6VxjVeyWN4BwUH5htAHrYusitQtdUmCA7OybDTCv2-HdqTkq2tDWrbmbE0nBA1LDqbW5yS_MZ4JcHzdxezDnfP0iy4/s400/all_api.png" width="400" /></a></div>
<div style="background-color: white; color: #1d2129; font-family: Helvetica, Arial, sans-serif; font-size: 15px; margin-bottom: 6px; margin-top: 6px;">
<br /></div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-64788157678707056512019-08-31T02:32:00.003-07:002019-08-31T02:42:25.532-07:00Install Gin (Go)<br />
1. 如果還沒安裝 go 環境的,請先裝安好喔。<br />
或是參考我這篇: <a href="https://csw-dawn.blogspot.com/2019/08/install-go-on-linux.html">https://csw-dawn.blogspot.com/2019/08/install-go-on-linux.html</a><br />
<br />
2. 安裝 gin<br />
$ <span style="background-color: #f6f8fa; color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 13.6px;">go get -u github.com/gin-gonic/gin</span><br />
<span style="background-color: #f6f8fa; color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 13.6px;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYikQd8R9bqYw-mzoWmNyNYcWysjJK51_GUJOn5ci5YoRf9cUmErVwrX7bjcjx61th5JcxGmV3s07gZ-K_EPERj_gPKSbYOcCjcCD5xX3HU9JIDOgK91hWSiJ8xVhJBzjle_XsIKxubBU/s1600/9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="307" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYikQd8R9bqYw-mzoWmNyNYcWysjJK51_GUJOn5ci5YoRf9cUmErVwrX7bjcjx61th5JcxGmV3s07gZ-K_EPERj_gPKSbYOcCjcCD5xX3HU9JIDOgK91hWSiJ8xVhJBzjle_XsIKxubBU/s640/9.png" width="640" /></a></div>
<span style="background-color: #f6f8fa; color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 13.6px;"><br /></span>
<br />
3. 開一個檔案 命名 example.go 並且存檔。<br />
$ emacs -nw example.go<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-size: 13.6px; line-height: 1.45; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">package</span> main
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">import</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/gin-gonic/gin<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">main</span>() {
<span class="pl-smi" style="box-sizing: border-box;">r</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> gin.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Default</span>()
r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">GET</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>/ping<span class="pl-pds" style="box-sizing: border-box;">"</span></span>, <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">func</span>(c *gin.<span class="pl-smi" style="box-sizing: border-box;">Context</span>) {
c.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">JSON</span>(<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">200</span>, gin.<span class="pl-smi" style="box-sizing: border-box;">H</span>{
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>message<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>pong<span class="pl-pds" style="box-sizing: border-box;">"</span></span>,
})
})
r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Run</span>() <span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> listen and serve on 0.0.0.0:8080</span>
}</pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbN8zKhf7pMBK5w4myRGsfkZ4LCr27cvn942fZzK_vwWh186w0E6JyNqPhL8anQbnO4tyjR6Hkt98q3NBkv6wYKcxmZxF1kGGFra8hH3YG-NKoV3uyCaoO3GQEIjxD8fA-z8uPGct36EE/s1600/10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbN8zKhf7pMBK5w4myRGsfkZ4LCr27cvn942fZzK_vwWh186w0E6JyNqPhL8anQbnO4tyjR6Hkt98q3NBkv6wYKcxmZxF1kGGFra8hH3YG-NKoV3uyCaoO3GQEIjxD8fA-z8uPGct36EE/s640/10.png" width="640" /></a></div>
<br />
4. 起動<br />
$ go run example.go<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjEZXCQmqIFTI3097lHiM5uFz2LaI_LHUNXYyWvzWo1amCvIW4tqh9H9nL3S1eWVKj-bheQOU0L_J3SwjBRn374ztLTZK4l729Mdz_gPgvMtK1TpUFdMipdHkky3M7kSQtT4JZMXWGkNw/s1600/11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjEZXCQmqIFTI3097lHiM5uFz2LaI_LHUNXYyWvzWo1amCvIW4tqh9H9nL3S1eWVKj-bheQOU0L_J3SwjBRn374ztLTZK4l729Mdz_gPgvMtK1TpUFdMipdHkky3M7kSQtT4JZMXWGkNw/s640/11.png" width="640" /></a></div>
<br />
5. $ curl http://127.0.0.1:8080/ping<br />
<br />
6. 更多參考可上: <a href="https://github.com/gin-gonic/gin">https://github.com/gin-gonic/gin</a><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-88955128167230040282019-08-31T01:45:00.001-07:002019-08-31T01:59:27.552-07:00Install go on linux<br />
1. 到 <a href="https://golang.org/">https://golang.org/</a> 點擊 Download Go 下載 對應的版本<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW1ybdJCdyjDMoDmFZxGTSXMLSmMHOPqYegVFjSFGEG9wFt1DAjfqPZZ3KlLUxGeKWSe547HrIu9aaF9TWlWI0Lu05lTfTzjfnSXt2Gro7lPDzRy97lB61WWAOO5vsKq4Ctwf4vMUnrBE/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="307" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW1ybdJCdyjDMoDmFZxGTSXMLSmMHOPqYegVFjSFGEG9wFt1DAjfqPZZ3KlLUxGeKWSe547HrIu9aaF9TWlWI0Lu05lTfTzjfnSXt2Gro7lPDzRy97lB61WWAOO5vsKq4Ctwf4vMUnrBE/s640/1.png" width="640" /></a></div>
<br />
<br />
2. 找到對應的版本<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbEkRSSKI5-BM52Xj4aTqJ9cnHWQ1XZxqghBv3Op6C_GTPUwxUxesyiIgf7eGxV8QCNQr8HNN7xn5J0rPXyJYaKb3gC3JCMuZ_mnZHuUAZ_oHVS36Kl-THCKTiGVeCHo8lSzI116HtQys/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbEkRSSKI5-BM52Xj4aTqJ9cnHWQ1XZxqghBv3Op6C_GTPUwxUxesyiIgf7eGxV8QCNQr8HNN7xn5J0rPXyJYaKb3gC3JCMuZ_mnZHuUAZ_oHVS36Kl-THCKTiGVeCHo8lSzI116HtQys/s640/2.png" width="640" /></a></div>
<br />
<br />
3. 下載<br />
$ wget https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi21kcTlraCsqd19GUKJ_JZnbD4k1a1OFKm_OiRdpo2alYThNttoE5gnV7MVWoDIH5AfNJ6mM_6R-NwiXlvf3jp1ZoJNjw8rddDZ3UxlfdblSj7rk8KJRKOfODv6zAOVGOOrFri1aSYTzU/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi21kcTlraCsqd19GUKJ_JZnbD4k1a1OFKm_OiRdpo2alYThNttoE5gnV7MVWoDIH5AfNJ6mM_6R-NwiXlvf3jp1ZoJNjw8rddDZ3UxlfdblSj7rk8KJRKOfODv6zAOVGOOrFri1aSYTzU/s640/3.png" width="640" /></a></div>
<br />
<br />
4. 安裝到指定目錄<br />
$ tar -C /usr/local -xzvf go1.12.9.linux-amd64.tar.gz<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizWub7fMYffNqRhUZSkO8v01NyvK7M2mXvBVaabpJBZCTByHhKiCXlMo9nK5cAVKRLpH0Rz2WmRRiNEy6x0XDBdfxfP5aeus4DDB7c33_uYAJeFaGVEWuDLpY2L9VnXIU2SpqPkMjpwX8/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizWub7fMYffNqRhUZSkO8v01NyvK7M2mXvBVaabpJBZCTByHhKiCXlMo9nK5cAVKRLpH0Rz2WmRRiNEy6x0XDBdfxfP5aeus4DDB7c33_uYAJeFaGVEWuDLpY2L9VnXIU2SpqPkMjpwX8/s640/4.png" width="640" /></a></div>
<br />
5. 測試是否安裝成功<br />
$ go version<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgicpt2pWlAaJMXk0vLs98drwo9S3itL6N4YpfYgZGFzUDIvGENy2FwcvMeRkG-ApKLAZ6nROk0QUOnyKNG0ms8S3NMEDdQ8idClxonxdOsyTOWsz-fupwFBM74mMIFOShiN0nMKzQ2qDU/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgicpt2pWlAaJMXk0vLs98drwo9S3itL6N4YpfYgZGFzUDIvGENy2FwcvMeRkG-ApKLAZ6nROk0QUOnyKNG0ms8S3NMEDdQ8idClxonxdOsyTOWsz-fupwFBM74mMIFOShiN0nMKzQ2qDU/s640/5.png" width="640" /></a></div>
<br />
<br />
6. 設定環境變數 GOPATH 和 PATH<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU88cgDnH9DOD-sfUG_V5Cis4E4dcwayhQSHdNMP1RI2zlVxnl56iLrjmIupMyL0T7mM6iy1UhKaIY_jsTvauXMukgDLJWiy2J5ZeRw24u5OjmZfKTnBHsZsyfzKejaFxxWEi_vEu_xrw/s1600/6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU88cgDnH9DOD-sfUG_V5Cis4E4dcwayhQSHdNMP1RI2zlVxnl56iLrjmIupMyL0T7mM6iy1UhKaIY_jsTvauXMukgDLJWiy2J5ZeRw24u5OjmZfKTnBHsZsyfzKejaFxxWEi_vEu_xrw/s640/6.png" width="640" /></a></div>
<br />
<br />
7. 寫第一支程式來 對世界說 hello world<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTiqmRO3jpYP4_K4ZWy98ES9NIz2waqkLJ1jS-S6Xz5IfFbgAFuAnQCK19Q_sBSiNaccNbh9KXNJ5YuAIwXTcXfQln0fhrrF0qAHjyOkidLk6Un_PK3Fcs_gi3-QDiutSsosL4Rv9eRik/s1600/7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTiqmRO3jpYP4_K4ZWy98ES9NIz2waqkLJ1jS-S6Xz5IfFbgAFuAnQCK19Q_sBSiNaccNbh9KXNJ5YuAIwXTcXfQln0fhrrF0qAHjyOkidLk6Un_PK3Fcs_gi3-QDiutSsosL4Rv9eRik/s640/7.png" width="640" /></a></div>
<br />
8. Go Go Gocsw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-91355349070701178852018-06-26T03:44:00.003-07:002019-08-31T01:55:35.711-07:00Install Beego (Golang)<b>1. Download and install</b><br />
<div>
$ go get github.com/astaxie/beego</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Wbq-h9ypxaMxkStmbPraRFd3lttdtdeee28kMhd4I7_93KVXRMr33SLT7qhI0frnTgHDEQ4ydsi2OKk9pg91nLa_dKqTrIhBgwhLUsW7D2vxobBifheKQatC0CrZLWSxR_abopbmuXo/s1600/install-beego-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Wbq-h9ypxaMxkStmbPraRFd3lttdtdeee28kMhd4I7_93KVXRMr33SLT7qhI0frnTgHDEQ4ydsi2OKk9pg91nLa_dKqTrIhBgwhLUsW7D2vxobBifheKQatC0CrZLWSxR_abopbmuXo/s640/install-beego-1.png" width="640" /></a></div>
<br />
<div>
<b>2. Create file hello.go</b></div>
<div>
<div>
$ emcas -nw hello.go</div>
<div>
package main</div>
<div>
<br /></div>
<div>
import "github.com/astaxie/beego"</div>
<div>
<br /></div>
<div>
func main() {</div>
<div>
beego.Run()</div>
<div>
}</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPDZPI9Q06sH3F7lWWflGSZmk_jWIU3M_sgb4QWr5KACzjUem8msm__SMS5aBtadK5eqbiyq1rnNVWW0y9QRprN1Y7H1azutgJacufAMRs9uOhds7K4pcNalSeElwnRx8BeFcNzdOHkHo/s1600/install-beego-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPDZPI9Q06sH3F7lWWflGSZmk_jWIU3M_sgb4QWr5KACzjUem8msm__SMS5aBtadK5eqbiyq1rnNVWW0y9QRprN1Y7H1azutgJacufAMRs9uOhds7K4pcNalSeElwnRx8BeFcNzdOHkHo/s640/install-beego-2.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKirSSpwuAaHEoI-WcC3Re_8qny6yXipq-TO2Ozd-bb3kMc4OkpoRPQd73Qq-hI1Uc21nLkBz2PMwQJgWUQgrOQki3kd8GAf7rkgYM0_fy5LpPtiSXfXrgxRsYCWdR-Jabp79m_pxhwwQ/s1600/install-beego-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKirSSpwuAaHEoI-WcC3Re_8qny6yXipq-TO2Ozd-bb3kMc4OkpoRPQd73Qq-hI1Uc21nLkBz2PMwQJgWUQgrOQki3kd8GAf7rkgYM0_fy5LpPtiSXfXrgxRsYCWdR-Jabp79m_pxhwwQ/s640/install-beego-3.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<b>3. Build and run</b></div>
<div>
<div>
$ go build hello.go</div>
<div>
$ ./hello</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfEsBGbk7mZbXvu_kcTY2XNPO4d7yqIALnIetShUT_v5wV7EthTPGpgnFUW4WZmc_DrDkop4wAJR0uqVCtupEdPORIHqz0QD5vVhiUsPNbYx5mDb7HgVOfF0muYhIqXeMXfzmsT3o0Pfk/s1600/install-beego-4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfEsBGbk7mZbXvu_kcTY2XNPO4d7yqIALnIetShUT_v5wV7EthTPGpgnFUW4WZmc_DrDkop4wAJR0uqVCtupEdPORIHqz0QD5vVhiUsPNbYx5mDb7HgVOfF0muYhIqXeMXfzmsT3o0Pfk/s640/install-beego-4.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<b>4. Installing bee tool</b></div>
<div>
$ go get github.com/beego/bee</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiutW2cx1DkbzDctOLlEcymlgX9Jkz1D-Kd2OjSjo36Sl1nbUDSvl1lotwSlv_dOBlnj-FMmbvO0Mz4dO2wnFDRdq6qR23YNJ9F6uA4wmyd_d7tue8WODpYSJh8Cip7BkcRc0nBFAHOSoc/s1600/install-beego-5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiutW2cx1DkbzDctOLlEcymlgX9Jkz1D-Kd2OjSjo36Sl1nbUDSvl1lotwSlv_dOBlnj-FMmbvO0Mz4dO2wnFDRdq6qR23YNJ9F6uA4wmyd_d7tue8WODpYSJh8Cip7BkcRc0nBFAHOSoc/s640/install-beego-5.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<b>5. Bee tool commands</b></div>
<div>
$ bee</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguRBRZb4N1IbOi18ILhVxC_VT9BqSMJ5LiVI6xct-_xQ74NIiY4-oTJvQabTQJ1HhlFPrQigaaDgZMOds4FelPI77IxJscY1YQHAWez2FmLVvAUO2Moux4dfGOMR4jkNqO8E-khuurKrQ/s1600/install-beego-6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguRBRZb4N1IbOi18ILhVxC_VT9BqSMJ5LiVI6xct-_xQ74NIiY4-oTJvQabTQJ1HhlFPrQigaaDgZMOds4FelPI77IxJscY1YQHAWez2FmLVvAUO2Moux4dfGOMR4jkNqO8E-khuurKrQ/s640/install-beego-6.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMC61DOjg2AtsJu6rVAhTOftkCPHU6qh7LPbReG5FHsQXTFrIY0iBBk4lvrQ20luplP2mdHE2QvlHgMAJxGbGc7IlYCmXHgfBgyJjk1fMlxKRG35_XtIV8XbeQGcOwo6yKDrAh0T8QECk/s1600/install-beego-7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMC61DOjg2AtsJu6rVAhTOftkCPHU6qh7LPbReG5FHsQXTFrIY0iBBk4lvrQ20luplP2mdHE2QvlHgMAJxGbGc7IlYCmXHgfBgyJjk1fMlxKRG35_XtIV8XbeQGcOwo6yKDrAh0T8QECk/s640/install-beego-7.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<b>6. Create new project</b></div>
<div>
$ bee new myproject</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMT4iuC8jdSTgMifa-xMz1NbtIHfuANyLGXkEuUkbJt_4wAx0My3ArvVr9ttCrpusk5vfOcjrNEvROk9-9_OsmE3TdCZbPcT3WxjhGrsYfU0Ij2atOhC8R1sTsbyYK56b4oH2SL0AAICs/s1600/install-beego-8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMT4iuC8jdSTgMifa-xMz1NbtIHfuANyLGXkEuUkbJt_4wAx0My3ArvVr9ttCrpusk5vfOcjrNEvROk9-9_OsmE3TdCZbPcT3WxjhGrsYfU0Ij2atOhC8R1sTsbyYK56b4oH2SL0AAICs/s640/install-beego-8.png" width="640" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcblxdop6OqpH0moqoQhM2E7O04u06XuXMZthcnU04Fbzh3JmqKwbG-xOHcMGwvtAkmZ-a75TdsjNf4LUVI92ewO66UeMV5r4hk_vnLDLxKzxfwIU0ZdfREPSnXeTK81xvdvZCPsLtGrE/s1600/install-beego-9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcblxdop6OqpH0moqoQhM2E7O04u06XuXMZthcnU04Fbzh3JmqKwbG-xOHcMGwvtAkmZ-a75TdsjNf4LUVI92ewO66UeMV5r4hk_vnLDLxKzxfwIU0ZdfREPSnXeTK81xvdvZCPsLtGrE/s640/install-beego-9.png" width="640" /></a></div>
<div>
<b><br /></b></div>
<div>
<b>7. Bee run</b></div>
<div>
$ bee run</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicfBOgEEN-3WE1h577-zE1ZTGm59s-wQYY-pU2tYv2lzKwtVl1rZfsmwnb3pmJYDaMnIg9Ur1zV_P0pGK6dZtlw_FWKyWraeQrbrv3mNe1tGNTIoUgEAfjyMcrAKb3key1usKZqKrV3wc/s1600/install-beego-10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicfBOgEEN-3WE1h577-zE1ZTGm59s-wQYY-pU2tYv2lzKwtVl1rZfsmwnb3pmJYDaMnIg9Ur1zV_P0pGK6dZtlw_FWKyWraeQrbrv3mNe1tGNTIoUgEAfjyMcrAKb3key1usKZqKrV3wc/s640/install-beego-10.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghJz0ZBlAJCm6pqvgXTzXwm_iNAscN3-T4LmspGpNNvTIjzGh_k4qWP803lSjihuZyGmMShflmslYOSWqNbtH2_Pazlkf95Kobnev9xhQx8zSzVW_56AqxfMAG5rD57FtdgY6qk1ZdwnM/s1600/install-beego-11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="1440" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghJz0ZBlAJCm6pqvgXTzXwm_iNAscN3-T4LmspGpNNvTIjzGh_k4qWP803lSjihuZyGmMShflmslYOSWqNbtH2_Pazlkf95Kobnev9xhQx8zSzVW_56AqxfMAG5rD57FtdgY6qk1ZdwnM/s640/install-beego-11.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-7633858904758734272017-05-19T00:59:00.002-07:002019-08-31T02:14:37.032-07:00常用 docker 指令分享<h2>
github: <a href="https://github.com/wangchenshu/docker-script">https://github.com/wangchenshu/docker-script</a></h2>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-76582783737975759172017-04-25T19:09:00.000-07:002017-07-31T05:21:56.498-07:00不用會寫程式 也能有自已的粉絲頁客服聊天機器人喔 雖然教學已經很多了 XD1. 先建立一個粉絲專頁 https://www.facebook.com/pages/create/?ref_type=bookmark<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw2vI5zd_tfhQBs5fryXCOkiD09ZkkNoC0Su5GhssgQ3nqqSmNOThfltIcavg1ddXqKMFJTpaG4pLpBR1LJpXKLp0hcam3KhAr0HoqyQBx0M64Il0WvSnKK2cpsjGdE0gRHImkXO4O5gE/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.11.27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw2vI5zd_tfhQBs5fryXCOkiD09ZkkNoC0Su5GhssgQ3nqqSmNOThfltIcavg1ddXqKMFJTpaG4pLpBR1LJpXKLp0hcam3KhAr0HoqyQBx0M64Il0WvSnKK2cpsjGdE0gRHImkXO4O5gE/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.11.27.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEucsyUxauHEQQuKRTLnR47aONoxPDq0E5DFBAZJCwpaEJjZBQFNOXBvvnn6ye3EbsNCISbTMai57oX-F1tRSX8DXwsmCkBjfhgDfOe0VNmLGKRVTy0a7CEUobeIwmAmXYjjXeashFKFk/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.12.31.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEucsyUxauHEQQuKRTLnR47aONoxPDq0E5DFBAZJCwpaEJjZBQFNOXBvvnn6ye3EbsNCISbTMai57oX-F1tRSX8DXwsmCkBjfhgDfOe0VNmLGKRVTy0a7CEUobeIwmAmXYjjXeashFKFk/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.12.31.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
輸入完成後,點立即開始</div>
<br />
2. 放照片和封面照<br />
<br />
3. 到 https://developers.facebook.com 這裡去註冊成開發者帳號<br />
<br />
4. 新增應用程式<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicCp-wm3iYdoJsi73HVrMWgF8jnXwiCT-p8ALdDWLZI57OK8r3KiqanKClKgM1v_gRnYTNffRqL-AhffSJGzB3FAY0ngNkVuw18nxpSyVmA2fqMwSk4muGpOP66Fhev6C87mhWp_tcpGA/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.10.06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicCp-wm3iYdoJsi73HVrMWgF8jnXwiCT-p8ALdDWLZI57OK8r3KiqanKClKgM1v_gRnYTNffRqL-AhffSJGzB3FAY0ngNkVuw18nxpSyVmA2fqMwSk4muGpOP66Fhev6C87mhWp_tcpGA/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.10.06.png" width="193" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3CgWdwHoIgMwDDbkpEWfkTV0Hb1UkgFrzCUC9nWYP7Y4T_9_q9V9gRiaJBCF0tisiwwU4wt-54yDpkyIpHlqSW4FFxIoGiFQ7oA3Xwru4BgaQOERzHTod9VKvKG8MESJeVon0Yfi6_OA/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.18.06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3CgWdwHoIgMwDDbkpEWfkTV0Hb1UkgFrzCUC9nWYP7Y4T_9_q9V9gRiaJBCF0tisiwwU4wt-54yDpkyIpHlqSW4FFxIoGiFQ7oA3Xwru4BgaQOERzHTod9VKvKG8MESJeVon0Yfi6_OA/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.18.06.png" width="320" /></a></div>
<br />
<br />
<br />
<br />
5. 新增產品<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-gUUy4wCfwReX1DN5-UaVG-6yyYrEQ9nqBQwmFFR6zoIzhsS5OrklK4-In-WURUj-Jm6Mgx9UoClP9LKmpYeGOxX5cSqHDbSpz9bWu58BOWziBcdMaRqTZQTDf7cbhTmgWoPwQ3dypQM/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.35.43.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-gUUy4wCfwReX1DN5-UaVG-6yyYrEQ9nqBQwmFFR6zoIzhsS5OrklK4-In-WURUj-Jm6Mgx9UoClP9LKmpYeGOxX5cSqHDbSpz9bWu58BOWziBcdMaRqTZQTDf7cbhTmgWoPwQ3dypQM/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.35.43.png" width="137" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
選Messenger 並開始使用</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5YpAr-xpVLlwPQnzNOGmtrpFn2_uHAbzCWeh0lpjcf_MhFTj_PvZVLYQ3Nu3ip2n68g1ZciidBU9Es-Nfu53On0uHjsF6LFc0q-ey6Y72gxRwye8Sw3d1NIz6O8JN-fzrXZ-Re5Svgr4/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.36.42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5YpAr-xpVLlwPQnzNOGmtrpFn2_uHAbzCWeh0lpjcf_MhFTj_PvZVLYQ3Nu3ip2n68g1ZciidBU9Es-Nfu53On0uHjsF6LFc0q-ey6Y72gxRwye8Sw3d1NIz6O8JN-fzrXZ-Re5Svgr4/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.36.42.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY5QawDaghb3cFhwOuQTC-i5lux-sXdA3ZXkP5p4g4QNjFMKS5Xi0kuLNqGx_N0wI23A6ov2t1C3YVZwSGIfCs7ujjVrcfxVoEkWjbSB29IKQ3BZq2eU3_dGqu5Tv7apZ44FJilkEiKno/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.37.48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY5QawDaghb3cFhwOuQTC-i5lux-sXdA3ZXkP5p4g4QNjFMKS5Xi0kuLNqGx_N0wI23A6ov2t1C3YVZwSGIfCs7ujjVrcfxVoEkWjbSB29IKQ3BZq2eU3_dGqu5Tv7apZ44FJilkEiKno/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.37.48.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
選擇粉絲頁</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkFoYogd4SdK6vS9njWenE9BNsuq0WNwYxHnipiSAnI5H1tYjCTlTrAF21EPQqXOxo-3E7HuWjPepYy_F3Jt15LiKD6zYVgpTQeUIlFmSjX48cSGE6_PD4ypD4hBnxdKS1dszncACrCdE/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.38.00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkFoYogd4SdK6vS9njWenE9BNsuq0WNwYxHnipiSAnI5H1tYjCTlTrAF21EPQqXOxo-3E7HuWjPepYy_F3Jt15LiKD6zYVgpTQeUIlFmSjX48cSGE6_PD4ypD4hBnxdKS1dszncACrCdE/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.38.00.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdll3zWneZpFtdZkdTJFz6tsHuMUG-1eR0yJiYIld8rtXmEXHli7HhEQyyeS4_u_JwYSE0BroIiE_o4kNOMwmUyBzFq0kot3uMMH-ueV9MXprhFQM48yUF3c68uIqEgf4b2Q9FxDNCnUI/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.38.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="149" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdll3zWneZpFtdZkdTJFz6tsHuMUG-1eR0yJiYIld8rtXmEXHli7HhEQyyeS4_u_JwYSE0BroIiE_o4kNOMwmUyBzFq0kot3uMMH-ueV9MXprhFQM48yUF3c68uIqEgf4b2Q9FxDNCnUI/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.38.09.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRNsAB-LlncbOYNSdz4oq093IDLsL8FbHrZblnXHt0HgExsaxjJlmnxtxvBKu5ZBF9nN8BYdd8_VvsiZ3kp0DrqmcB2_PMXdjQCRnFnzuaDYomC8FhlCuoKJKOB8-mi_XUqcU7IbqgbHE/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.38.00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRNsAB-LlncbOYNSdz4oq093IDLsL8FbHrZblnXHt0HgExsaxjJlmnxtxvBKu5ZBF9nN8BYdd8_VvsiZ3kp0DrqmcB2_PMXdjQCRnFnzuaDYomC8FhlCuoKJKOB8-mi_XUqcU7IbqgbHE/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.38.00.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
都確定, 就好了</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
6. 點到設定->新增平台,選網站<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigHhf5KfYbj4jYwVykMoQyFbKYnYcSZJQslbJwitcs0hFM0G14Y8K7wiGyNdqvSd_W3212K1JZf1wNf7Acg2jEc8lAySJHvRurIkpBCcVfh7I6QlXvuZmk-5_6pJFXytcRcfBPSnmzwvA/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.23.12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigHhf5KfYbj4jYwVykMoQyFbKYnYcSZJQslbJwitcs0hFM0G14Y8K7wiGyNdqvSd_W3212K1JZf1wNf7Acg2jEc8lAySJHvRurIkpBCcVfh7I6QlXvuZmk-5_6pJFXytcRcfBPSnmzwvA/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.23.12.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7p74dhgpKYDcsZ6EM5L7XmZuXo2-lFwHMgjuANH4Ae2CS9RcSnVR8i5Gym_UELrEklcntwCEQolQg3K8UqlH2AdIxnsyy-hxE2DDaoOCAHEZXPGaRKAAeoZoGCGVz8DY_gLf3UnuHwWA/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.26.45.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7p74dhgpKYDcsZ6EM5L7XmZuXo2-lFwHMgjuANH4Ae2CS9RcSnVR8i5Gym_UELrEklcntwCEQolQg3K8UqlH2AdIxnsyy-hxE2DDaoOCAHEZXPGaRKAAeoZoGCGVz8DY_gLf3UnuHwWA/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.26.45.png" width="320" /></a></div>
<br />
<br />
網站網址 http://api.chatfuel.com<br />
應用程式網域 api.chatfuel.com<br />
隱私政策網址 https://chatfuel.com/privacypolicy.html<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirXAjrQMKjZsTLwANDaWFtIrpbm1QLCk_3xBQxqLknpCRYZ5RbBJOGJUbE2PMVM5ZEMkGk5h7PlI3ONGT78UMgeqBy8SI_vX7gliZb34EFyBPLkT3sHKFZslLupcfPWyxr5OgGQv_pyPE/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.50.31.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirXAjrQMKjZsTLwANDaWFtIrpbm1QLCk_3xBQxqLknpCRYZ5RbBJOGJUbE2PMVM5ZEMkGk5h7PlI3ONGT78UMgeqBy8SI_vX7gliZb34EFyBPLkT3sHKFZslLupcfPWyxr5OgGQv_pyPE/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.50.31.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
7. 到應用程式審查</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXStGLbJzzUboe6FVh7JEZ9xR_erJZGrEKqz3jaXHsBspZ4HlHYGgdZEct1geAv9mG7Mt8lr1PiqpGd8fmvPg3lnplE_1FC7CtdpHrarxpIbp0fgHA7PC66k8KNCA3DKGlKYMxak2-Lhs/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%258810.05.10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXStGLbJzzUboe6FVh7JEZ9xR_erJZGrEKqz3jaXHsBspZ4HlHYGgdZEct1geAv9mG7Mt8lr1PiqpGd8fmvPg3lnplE_1FC7CtdpHrarxpIbp0fgHA7PC66k8KNCA3DKGlKYMxak2-Lhs/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%258810.05.10.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqOfvZkqC-PYIRIxhk5JnrM0sN0tr1VFC0A13XDyBK1OhzLhUAbElZGM1vCzRfXh2fZ9YUfZ40kolBz5YvHnFXyJ9tp8I2NVR5USYpFI1dOn8a5W6FO9QvtddEJ1oANpoCH5xJLxMikWY/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%258810.05.19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqOfvZkqC-PYIRIxhk5JnrM0sN0tr1VFC0A13XDyBK1OhzLhUAbElZGM1vCzRfXh2fZ9YUfZ40kolBz5YvHnFXyJ9tp8I2NVR5USYpFI1dOn8a5W6FO9QvtddEJ1oANpoCH5xJLxMikWY/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%258810.05.19.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnWg4QjyIpTRcc7jCSp7B8mJ2CMV3utZF0BkUnPhaJclLhuByZfbD7YgFHQydvAWan-RcM6d-GtXz1-TNUSj58ClRp6ogpyRkmwXBDbtMRv0Fcl41roZOXSK_JsRzmyZ-3HUxdU7c1kJ8/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%258810.05.26.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnWg4QjyIpTRcc7jCSp7B8mJ2CMV3utZF0BkUnPhaJclLhuByZfbD7YgFHQydvAWan-RcM6d-GtXz1-TNUSj58ClRp6ogpyRkmwXBDbtMRv0Fcl41roZOXSK_JsRzmyZ-3HUxdU7c1kJ8/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%258810.05.26.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
水喔,發佈了,YA!</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="" style="clear: both; text-align: left;">
8. 然後到Chatfuel dashboard,去 Create a blank chatbot</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggVfm1n2bZBAs78JAh6uImIvuqxTvJArYGLgRZA5E7kKT6f5byokuc2cPm3NxQv8jYqsiVNiddzWN0ae93OQDaXt156O2p9cMJ3SQLV5hug-Vf5oUGxZutcQqQ288NXawnQP5v8mk7F94/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.44.46.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="47" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggVfm1n2bZBAs78JAh6uImIvuqxTvJArYGLgRZA5E7kKT6f5byokuc2cPm3NxQv8jYqsiVNiddzWN0ae93OQDaXt156O2p9cMJ3SQLV5hug-Vf5oUGxZutcQqQ288NXawnQP5v8mk7F94/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.44.46.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Rename 一下</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheLn5bmJOabZGq2W3kfLOkuRPed7ETWrEtxR6cawrGfDBo5GBYaDsZhKuNC7IKZ8dZMO9Ny8HqYc1WgEP80aDuno5uvDxtyAZtelYsD_eHFfCV9J4fHiTSvz2743jlG0AsrTyK1aBra0w/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.45.54.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheLn5bmJOabZGq2W3kfLOkuRPed7ETWrEtxR6cawrGfDBo5GBYaDsZhKuNC7IKZ8dZMO9Ny8HqYc1WgEP80aDuno5uvDxtyAZtelYsD_eHFfCV9J4fHiTSvz2743jlG0AsrTyK1aBra0w/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.45.54.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
9. Connect to facebook</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCZRm9sqZJPXXseiGfIDs3NAVOlP-BhS6sNlvl1vAW3t99Vt7Oc7P-PnYZZjVTJb2PVMMotfVCJVYoum-CbxF2MVCi6dCCZsXr-s-oIWsAan_CFoN5DW16R9f_wMfBzR_d-I4MDnkQedU/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.46.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCZRm9sqZJPXXseiGfIDs3NAVOlP-BhS6sNlvl1vAW3t99Vt7Oc7P-PnYZZjVTJb2PVMMotfVCJVYoum-CbxF2MVCi6dCCZsXr-s-oIWsAan_CFoN5DW16R9f_wMfBzR_d-I4MDnkQedU/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.46.09.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiraSAtxw6-xfUwGQpG9VIhAIi6w_C9_B48IzuirToIq5b4zeul3_RZVR6YfM9DDd_yZaDmRodYLjf2pcs0U4bvehJvnDdvud8odz4ToVxm2NGGcBGogphcWdiDhnlnsPCpG9wpbeaQ78Q/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.46.18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="27" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiraSAtxw6-xfUwGQpG9VIhAIi6w_C9_B48IzuirToIq5b4zeul3_RZVR6YfM9DDd_yZaDmRodYLjf2pcs0U4bvehJvnDdvud8odz4ToVxm2NGGcBGogphcWdiDhnlnsPCpG9wpbeaQ78Q/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.46.18.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqQG-Ss0Xo79RrX4zULZ48LmVAyzQlb-oLiOOK0m45e2cxgITUA_HyqtvJ-YOX-CUsZ2UFe4OtEYug5eFlQJJzHhvGPCkVjEwQDLmlz2p67PVie5Oe5oreL-j5IjRvTx5bV0RhzWzE9SQ/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.46.29.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="63" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqQG-Ss0Xo79RrX4zULZ48LmVAyzQlb-oLiOOK0m45e2cxgITUA_HyqtvJ-YOX-CUsZ2UFe4OtEYug5eFlQJJzHhvGPCkVjEwQDLmlz2p67PVie5Oe5oreL-j5IjRvTx5bV0RhzWzE9SQ/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.46.29.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
good, nice work</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
10. 一切設定好,當然少不了測試啦啦啦啦</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKxgo1aReL5HVzvm5FdC-GD6Iuua_YFG0tskkX0-_ltW9SnInCqWTi_p8xwiUCl7NM5IOnCNSPdF6DH8I8WA1KbTMCLA5sGn07M9JxdI9gDNIEXNKoA2hn-gzEx0N4bazZVtyORFRlNXQ/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.57.20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKxgo1aReL5HVzvm5FdC-GD6Iuua_YFG0tskkX0-_ltW9SnInCqWTi_p8xwiUCl7NM5IOnCNSPdF6DH8I8WA1KbTMCLA5sGn07M9JxdI9gDNIEXNKoA2hn-gzEx0N4bazZVtyORFRlNXQ/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258A%25E5%258D%25889.57.20.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
11. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiafQvOYFfWtBUkSVEnNJHlGwiMkK5SeXF2M_L09wFLqMi6o_Z3XY_pooUu1LjrlIcQ9q0qrpnq4wOOV5zIyf4xLz0gNgu-Qtepbe9k0hXzgGXwH_ndNdNf1RZoVW2HDEDNb20jRnZ8IMU/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.39.12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiafQvOYFfWtBUkSVEnNJHlGwiMkK5SeXF2M_L09wFLqMi6o_Z3XY_pooUu1LjrlIcQ9q0qrpnq4wOOV5zIyf4xLz0gNgu-Qtepbe9k0hXzgGXwH_ndNdNf1RZoVW2HDEDNb20jRnZ8IMU/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.39.12.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
加一下 Rule</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
12. 準 備發佈
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2y4D45gqCqvgVZgDRrFGokfjKrPRK3lZazXP6-GDqpFcZf6A_eJ1dA7Kdgsnyjomd2HC-D2re5EIk3zNER7QItYv-EA81Le9_9bZ8Pmr0nZl9Zx5oyXgpmizVi11AVBkgTdA4DrioiQo/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.26.19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2y4D45gqCqvgVZgDRrFGokfjKrPRK3lZazXP6-GDqpFcZf6A_eJ1dA7Kdgsnyjomd2HC-D2re5EIk3zNER7QItYv-EA81Le9_9bZ8Pmr0nZl9Zx5oyXgpmizVi11AVBkgTdA4DrioiQo/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.26.19.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
點 擊<span style="background-color: white; color: #4b4f56; font-family: "helvetica neue" , "helvetica" , "arial" , "lucida grande" , sans-serif; font-size: 15px; font-weight: bold;">pages_messaging 右邊的 新增到提交內容</span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="background-color: white; color: #4b4f56; font-family: "helvetica neue" , "helvetica" , "arial" , "lucida grande" , sans-serif; font-size: 15px; font-weight: bold;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="background-color: white; color: #4b4f56; font-family: "helvetica neue" , "helvetica" , "arial" , "lucida grande" , sans-serif; font-size: 15px; font-weight: bold;">13. </span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnIDdg202pmObX58eNXx9_BEOJ0DlffNX2lIvFVjSjuYt7dJ3fxrGygXWxbffGxmVXiXA9oeoL7VN2n2PmEXgfsdfAdsZKcfsYO6LB9B3yZrgIcDK-fCBZy1oDgGqKZEpOd4fzRiLDZ_8/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.26.48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnIDdg202pmObX58eNXx9_BEOJ0DlffNX2lIvFVjSjuYt7dJ3fxrGygXWxbffGxmVXiXA9oeoL7VN2n2PmEXgfsdfAdsZKcfsYO6LB9B3yZrgIcDK-fCBZy1oDgGqKZEpOd4fzRiLDZ_8/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.26.48.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: #4b4f56; font-family: "helvetica neue" , "helvetica" , "arial" , "lucida grande" , sans-serif;"><span style="font-size: 15px;"><b><br /></b></span></span><span style="background-color: white; color: #4b4f56; font-family: "helvetica neue" , "helvetica" , "arial" , "lucida grande" , sans-serif; font-size: 15px; font-weight: bold;"></span></div>
<div class="separator" style="clear: both; text-align: center;">
點擊 編輯備註事項</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
14. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEji62AXzTn6HQP5B2b4Mm3TYbBsYcknB_1VgQM7unHsrjDBQTBxBL2inWdEMd7wg01ZVvEY1Ta6SYIhywmh71foeVVEHifSpjdoHtJApHv0uo2LzA0vT8OT69N2qfCjXcqNWMRSHjRbiWs/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.26.56.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEji62AXzTn6HQP5B2b4Mm3TYbBsYcknB_1VgQM7unHsrjDBQTBxBL2inWdEMd7wg01ZVvEY1Ta6SYIhywmh71foeVVEHifSpjdoHtJApHv0uo2LzA0vT8OT69N2qfCjXcqNWMRSHjRbiWs/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.26.56.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
選擇 粉絲頁</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
15. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO9Qlh2ad2-BzhpnHFKqLOIEJRZ9-QmwQMdr8Im2EpT8nlLQsYAVMp39HshkqkC5lP-xRffDnbDK1KdVvz9ia2wKCen7dsiW7PcXvD_-xTnjQfrEePfNSoHJg3cDfmUg7o5qH46yc1xCE/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.27.39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO9Qlh2ad2-BzhpnHFKqLOIEJRZ9-QmwQMdr8Im2EpT8nlLQsYAVMp39HshkqkC5lP-xRffDnbDK1KdVvz9ia2wKCen7dsiW7PcXvD_-xTnjQfrEePfNSoHJg3cDfmUg7o5qH46yc1xCE/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.27.39.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
輸入AI Rule</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
16. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNalhQquCsDOVaY2q6MM7xD0d4gqzGs27WyU5-4cq9vmM1YY-BqczpWgsvxaSFENyDZ1cEjlJrVwdLe3CVf44_8o7_Syl-kU1v4wfQ4hu1V7p4OC880thm60alVmedwf1Yn0sssJkh-E/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.27.54.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNalhQquCsDOVaY2q6MM7xD0d4gqzGs27WyU5-4cq9vmM1YY-BqczpWgsvxaSFENyDZ1cEjlJrVwdLe3CVf44_8o7_Syl-kU1v4wfQ4hu1V7p4OC880thm60alVmedwf1Yn0sssJkh-E/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.27.54.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
儲存</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
17. </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSggPyHxlR9Rs7km8Z5DPRa_Sq5xPq5npubqVOQTx8QeOLTsMapX5IpGpVo-SagGGTbszkl_PisC4COdKBWljQRuZg3IBdIqmr0hi4DimIpws6PcvUU-lChiSnGzFtiLmwCsGoFE6gcK8/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.28.06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSggPyHxlR9Rs7km8Z5DPRa_Sq5xPq5npubqVOQTx8QeOLTsMapX5IpGpVo-SagGGTbszkl_PisC4COdKBWljQRuZg3IBdIqmr0hi4DimIpws6PcvUU-lChiSnGzFtiLmwCsGoFE6gcK8/s320/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2017-04-26+%25E4%25B8%258B%25E5%258D%258810.28.06.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
提交進行審查</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
18. 搞定,收工,下去領便當吃 XD</div>
<br />csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-48973335263281354752015-08-29T21:30:00.002-07:002015-08-29T22:37:40.615-07:00dnw install on ubuntu 14.04 LTS<br />
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Download dnw:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ wget https://dnw-linux.googlecode.com/files/dnw-linux-v1.01.tar.gz
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Install kernel source:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo apt-get install linux-source-`uname -r`
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Install kernel headers:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo apt-get install linux-headers-`uname -r`
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Install kernel headers for development:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo apt-get install linux-libc-dev
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo apt-get install kernel-package libncurses5-dev fakeroot
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Makefile (in ~/dnw-linux/src/driver)
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
--------------------
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
KDIR="/usr/src/linux-headers-3.16.0-30-generic"
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
PWD=$(shell pwd)
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
VV=
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
obj-m := secbulk.o
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
secbulk-m := secbulk.o
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
all:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$(MAKE) -C ${KDIR} M=${PWD} V=${VV} modules
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
clean:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$(MAKE) -C ${KDIR} M=${PWD} clean
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<div>
--------------------
</div>
<div>
<br /></div>
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ cd ~/
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ mkdir dnw-linux
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ mv dnw-linux-v1.01.tar.gz dnw-linux
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ cd dnw-linux/
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ tar zxvf dnw-linux-v1.01.tar.gz
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ cd ~/dnw-linux/src/driver
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ lsusb<br />
Bus 001 Device 009: ID 04e8:1234 Samsung Electronics Co., Ltd /* <— here */
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Bus 001 Device 003: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ emacs secbulk.c
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
…...
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
static struct usb_device_id secbulk_table[]= {
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
{ USB_DEVICE(0x5345, 0x1234) }, /* FS2410 */
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
{ USB_DEVICE(0x04e8, 0x1234) }, /* EZ6410 */
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
{ USB_DEVICE(0x04e8, 0x1234) }, /* <— here */
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
};
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
…...
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ make
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
make -C "/opt/linux-source-3.13.0" M=/home/moto/dnw-linux/src/driver V= modules
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
make[1]: Entering directory `/opt/linux-source-3.13.0'
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
WARNING: Symbol version dump /opt/linux-source-3.13.0/Module.symvers
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
is missing; modules will have no dependencies and modversions.
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
CC [M] /home/moto/dnw-linux/src/driver/secbulk.o
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
In file included from /home/moto/dnw-linux/src/driver/secbulk.c:1:0:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
/home/moto/dnw-linux/src/driver/secbulk.c: In function ‘secbulk_write’:
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
include/linux/kernel.h:672:17: warning: comparison of distinct pointer types lacks a cast [enabled by default]
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
(void) (&_min1 == &_min2); \
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
^
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
/home/moto/dnw-linux/src/driver/secbulk.c:60:14: note: in expansion of macro ‘min’
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
to_write = min(len, BULKOUT_BUFFER_SIZE);
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
^
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Building modules, stage 2.
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
MODPOST 1 modules
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
CC /home/moto/dnw-linux/src/driver/secbulk.mod.o
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
LD [M] /home/moto/dnw-linux/src/driver/secbulk.ko
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
make[1]: Leaving directory `/opt/linux-source-3.13.0'
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo cp secbulk.ko /lib/modules/3.16.0-30-generic/kernel
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo depmod -A
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Load module
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo modprobe secbulk
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Auto loading while booting
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ sudo emacs /etc/modules
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
Add secbulk
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
<br /></div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ cd ~/dnw-linux/src/dnw
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
$ make
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
gcc -g -o dnw dnw.c<br />
<br />
Client:<br />
SMDK6410 # dnw<br />
OTG cable Connected!<br />
Now, Waiting for DNW to transmit data<br />
<br />
HOST:<br />
$ touch 123<br />
$ sudo ./dnw 123<br />
load address: 0x57E00000<br />
Writing data...<br />
100% 0x0000000A bytes (0 K)<br />
speed: 0.001907M/S</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
</div>
<div style="font-family: 'Helvetica Neue'; font-size: 14px;">
搞定收功~ XD </div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-31603178321727378612014-12-28T00:46:00.002-08:002014-12-28T00:49:27.212-08:00Install Node.js on ubuntu 14.04<div>
1. sudo apt-get update</div>
<div>
2. sudo apt-get install gcc</div>
<div>
3. sudo apt-get install make</div>
<div>
4. sudo apt-get install g++</div>
<div>
5. sudo apt-get install libssl-dev</div>
<div>
6. wget <a href="http://nodejs.org/dist/v0.10.35/node-v0.10.35.tar.gz">http://nodejs.org/dist/v0.10.35/node-v0.10.35.tar.gz</a></div>
<div>
7. mv node-v0.10.35.tar.gz /usr/local/</div>
<div>
8. cd /usr/local</div>
<div>
9. tar zxvf node-v0.10.35.tar.gz</div>
<div>
10. cd node-v0.10.35</div>
<div>
11. ./configure</div>
<div>
12. make</div>
<div>
13. sudo make install<br />
14. vim helloworld.js<br />
console.log('Hello World! Node.js');<br />
15. node helloworld.js<br />
Hello World! Node.js<br />
16. enjoy!</div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-81810801868296547532014-02-28T06:01:00.000-08:002014-03-09T05:17:50.075-07:00Ubuntu Install Tomcat (src)<br />
<br />
1. Install JDK<br />
reference here:<br />
http://csw-dawn.blogspot.tw/2014/02/ubuntu-java-jdk.html<br />
2. Download tomcat7<br />
https://tomcat.apache.org/download-70.cgi<br />
3. $ tar zxvf apache-tomcat-7.0.52.tar.gz<br />
4. $ sudo cp -r apache-tomcat-7.0.52 /usr/local/tomcat7<br />
5. $ cd /usr/local/tomcat7/lib<br />
6. $ sudo cp servlet-api.jar jsp-api.jar el-api.jar /usr/lib/jdk/jdk1.7.0_51/jre/lib/ext/<br />
7. Install mysql-connector-java<br />
$ sudo cp mysql-connector-java-5.1.22-bin.jar /usr/local/tomcat7/lib/<br />
8. $ sudo vim /etc/rc.local<br />
Add : sudo sh /usr/local/tomcat7/bin/startup.shcsw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-12002532335595817812014-02-20T21:12:00.001-08:002014-02-20T21:13:01.051-08:00Java 使用 Apache POI1. Download page<br />
http://poi.apache.org/download.html<br />
to download <a href="http://www.apache.org/dyn/closer.cgi/poi/release/bin/poi-bin-3.10-FINAL-20140208.tar.gz" style="background-color: white; color: blue; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: small;">poi-bin-3.10-FINAL-20140208.tar.gz</a><br />
2. 解壓縮<br />
3. 打開 Eclipse<br />
在 Project 上按右鍵<br />
Properties->Java Build Path->Libraries->Add JARs<br />
選擇 poi-3.10-FINAL-20140208.jar 檔加入<br />
4. 開始使用<br />
<br />csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-24869873036237977322014-02-20T03:48:00.000-08:002014-03-09T05:18:44.316-07:00Ubuntu Install Tomcat1. Install Tomcat<br /> $ sudo apt-get install tomcat7<br />2. Check Status<br /> $ sudo /etc/init.d/tomcat7 status<br /> * Tomcat servlet engine is running with pid 13249<br />3. Install mysql-connector-java<br /> $ sudo cp mysql-connector-java-5.1.22-bin.jar /usr/share/tomcat7/lib/<br />4. Restart Tomcat<br /> $ sudo /etc/init.d/tomcat7 restart<br /> * Stopping Tomcat servlet engine tomcat7 [ OK ] <br /> * Starting Tomcat servlet engine tomcat7 [ OK ] <br />5. Test<br /> $ cd /var/lib/tomcat7/webapps/ROOT<br /> $ sudo vim test1.jsp<br /> test1.jsp:<br /> <%<br /> out.println("Hello World!");<br /> %><br />6. Open browser<br /> http://<your_server_ip_address>:8080/test1.jsp<br /> will show<br /> Hello World!<br />7. cd /usr/share/tomcat7/lib<br />8. $ sudo cp servlet-api.jar jsp-api.jar el-api.jar /usr/lib/jdk/jdk1.7.0_51/jre/lib/ext/csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-67263465580193918722014-02-19T05:03:00.003-08:002014-03-09T05:52:32.586-07:00Ubuntu 安裝 Java JDK1. 先到 http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html<br />
下載 jdk<br />
2. 解壓縮<br />
$ tar zxvf jdk-7u51-linux-i586.tar.gz<br />
3. 建立jdk目錄<br />
$ sudo mkdir /usr/lib/jdk<br />
4. Copy jdk 到 /usr/lib 目錄下<br />
$ sudo cp -r jdk1.7.0_51 /usr/lib/jdk<br />
5. 設定環境變數<br />
$ sudo vim /etc/profile<br />
加上以下內容:<br />
export JAVA_HOME=/usr/lib/jdk/jdk1.7.0_51<br />
export JRE_HOME=/usr/lib/jdk/jdk1.7.0_51/jre<br />
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin<br />
export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar<br />
6. 置換系統默認 jdk<br />
$ sudo update-alternatives --install /usr/bin/java java /usr/lib/jdk/jdk1.7.0_51/bin/java 300<br />
$ sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jdk/jdk1.7.0_51/bin/javac 300<br />
$ sudo update-alternatives --config java<br />
$ sudo update-alternatives --config javac<br />
7. 確認安裝<br />
$ java -version<br />
java version "1.7.0_51"<br />
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)<br />
Java HotSpot(TM) Client VM (build 24.51-b03, mixed mode)<br />
<div>
8. 完成</div>
csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-838020033175603222012-08-17T00:51:00.003-07:002014-03-09T05:56:10.673-07:00ubuntu 12.04 install apache/phpmyadmin<br />
1. sudo apt-get install apache2<br />
2. sudo apt-get install php5 libapache2-mod-php5<br />
3. sudo apt-get install mysql-server<br />
4. sudo apt-get install libapache2-mod-auth-mysql php5-mysql phpmyadmin<br />
5. cd /var/www<br />
6. sudo ln -s /usr/share/phpmyadmin .<br />
7. sudo /etc/init.d/apache2 restart<br />
open web browser http://127.0.0.1/phpmyadmincsw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-72368672767341794382012-08-16T23:24:00.002-07:002012-08-16T23:24:39.103-07:00samba mount on linuxmount -t cifs -o username="username",password="password" //192.168.1.x/src /distcsw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-36338428432780974862012-08-16T23:20:00.000-07:002012-08-16T23:20:11.387-07:00start vmware vmx on linuxsu -l root -c "/usr/bin/vmrun -T ws start /opt/vmware/xxx.vmx nogui"csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-47731771283697385672012-08-16T22:41:00.002-07:002012-08-16T22:45:57.190-07:00安裝 qemu on ubuntu 12.04(包含執行 ARM 指令集的 QEMU emulator)安裝:<br />
1. 安裝gcc-4.6<br />
2. apt-get install libsdl1.2debian libsdl1.2-dev zlib1g-dev<br />
3. download qemu-1.1.1-1.tar.bz2<br />
4. mv qemu-1.1.1-1.tar.bz2 /usr/local<br />
5. cd /usr/local<br />
6. tar jxvf qemu-1.1.1-1.tar.bz2<br />
7. cd qemu-1.1.1<br />
8. ./configure --cc=/usr/bin/gcc-4.6 --host-cc=/usr/bin/gcc-4.6 --target-list=arm-softmmu<br />
<br />
測試:<br />
./arm-softmmu/qemu-system-arm -kernel /home/walter/arm-test/zImage.integrator -initrd /home/walter/arm-test/arm_root.img -nographic -append "console=ttyAMA0"
<br />
<br />
<br />csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-24001064878672624612012-01-06T00:40:00.000-08:002012-01-06T00:40:05.099-08:00基礎 Linux Device Driver 驅動程式#11 (procfs-read only)procfs 指的是位於 /proc 的虛擬檔案系統(實體在 RAM內), 內含 kernel 與各驅動程式的設定選項。<br />
/proc 內的大多數檔案都是唯讀的,像 /proc/cpuinfo , /proc/meminfo 等等...<br />
但也有些是可讓使用者設定的。 像 /proc/sys/kernel/printk 就是了。<br />
<br />
如果是要建立唯讀的 procfs,是呼叫 create_proc_read_entry。<br />
定義在 include/linux/proc_fs.h<br />
<br />
struct proc_dir_entry *create_proc_read_entry(const char *name,<br />
mode_t mode, struct proc_dir_entry *base,<br />
read_proc_t *read_proc, void * data)<br />
<br />
name: 在 /proc 之內的檔案名稱<br />
mode: 權限(可 NULL)<br />
base: 上層目錄(可 NULL)<br />
read_proc: 讀取處理函式<br />
data: 私有資料(可 NULL)<br />
<br />
read_proc 引數要傳入讀取時呼叫的處理函式指標。<br />
這個函式的 prototype 已 typedef 為 read_proc_t, 如下所示:<br />
typedef int (read_proc_t)(char *page, char **start, off_t off,<br />
int count, int *eof, void *data);<br />
<br />
page: Kernel 配置的記憶體空間<br />
start: 驅動程式寫入資料的開始位址指標(由驅動程式回傳)<br />
off: 驅動程式傳回資料的偏移量<br />
count: User space 一次讀回的量<br />
eof: 通知已達資料終點(由驅動程式回傳)<br />
data: create_proc_read_entry() 設定的私有資料<br />
<br />
page 引數是 kernel 分配的記憶體,所以驅動程式可以直接寫入,<br />
但只分配了一個 page 的大小(PAGE_SIZE),所以寫入資料起過 PAGE_SIZE 就會破壞記憶體內容。<br />
<br />
驅動程式在卸載的時候,要呼叫 remove_proc_entry() 清除 procfs 的內容。<br />
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);<br />
<br />
好吧, 就來試一下吧。<br />
<br />
test_proc.c 原始碼如下:<br />
/*****************************************************************************/<br />
#include <linux/init.h><br />
#include <linux/module.h><br />
#include <linux/proc_fs.h><br />
<br />
#define PROC_NAME "test_proc_info"<br />
#define BUF_SIZE 10<br />
static char buf[BUF_SIZE] = {<br />
'a', 'b', 'c', 'd', 'e',<br />
'f', 'g', 'h', 'i', 'j'};<br />
<br />
static int test_proc_read(char *page, char **start, off_t off,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int count, int *eof, void *data)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int len = BUF_SIZE;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (len > PAGE_SIZE)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ENOBUFS;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>len = sprintf(page, "%s\n", buf);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return len;<br />
}<br />
<br />
static int test_proc_init(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct proc_dir_entry *entry;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Procfs init...\n");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>entry = create_proc_read_entry(PROC_NAME,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> S_IRUGO | S_IWUGO,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> NULL,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> test_proc_read,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> NULL);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (entry == NULL) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ret = -ENOMEM;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto out;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
out:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return ret;<br />
}<br />
<br />
static void test_proc_exit(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>remove_proc_entry(PROC_NAME, NULL);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Procfs exit.\n");<br />
}<br />
<br />
module_init(test_proc_init);<br />
module_exit(test_proc_exit);<br />
<br />
MODULE_LICENSE("GPL");<br />
MODULE_AUTHOR("Wang Chen Shu");<br />
MODULE_DESCRIPTION("This is test_proc_read module.");<br />
<br />
/*****************************************************************************/<br />
<br />
Makefile 如下:<br />
/*****************************************************************************/<br />
<br />
KDIR="/opt/linux-source-2.6.38"<br />
PWD=$(shell pwd)<br />
<br />
obj-m := test_proc.o<br />
<br />
all:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} modules<br />
clean:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} clean<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
/*****************************************************************************/<br />
<br />
開始測試, go........<br />
<br />
# ls<br />
Makefile test_proc.c<br />
# make<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/test_proc_read modules<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CC [M] /opt/test_driver/my_driver/test_proc_read/test_proc.o<br />
Building modules, stage 2.<br />
MODPOST 1 modules<br />
CC /opt/test_driver/my_driver/test_proc_read/test_proc.mod.o<br />
LD [M] /opt/test_driver/my_driver/test_proc_read/test_proc.ko<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
# insmod ./test_proc.ko<br />
Procfs init...<br />
# ls -l /proc/test_proc_info<br />
-rw-rw-rw- 1 root root 0 2012-01-06 16:35 /proc/test_proc_info<br />
# cat /proc/test_proc_info<br />
abcdefghij<br />
# rmmod test_proc<br />
Procfs exit.<br />
# ls -l /proc/test_proc_info<br />
ls: 無法存取 /proc/test_proc_info: 沒有此一檔案或目錄<br />
<br />
你看看,你看看,是不是這麼一回事呢?<br />
哈^^<br />
<br />
procfs - read write 待續......<br />
<br />
註記及聲明:<br />
本教學,是參考Linux Device Driver Programming驅動程式設計由平田豐著的這本書。csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-33693283845749974602012-01-05T22:06:00.001-08:002012-01-05T22:06:52.493-08:00基礎 Linux Device Driver 驅動程式#10 (select/poll)相信各位都有在Linux上寫程式的經驗,<br />
當您程式裡呼叫 open 時,Linux 預設會以 blocking mode的方式開啟,<br />
block 是指當 process 為了等待某件事的發生,而進入 sleep 狀態的情形。<br />
<br />
像 read 就是其中一種,當沒資料讀取時,process 就會被 block。<br />
write 也是一樣,在寫入資料時,寫入對象還無法處理資料時,一樣會 block。<br />
<br />
對某些程式來說,如果 read 系統呼叫被 block 的話,有時就會有設計上的問題,<br />
所以為了避免這種問題發生,Linux 就準備了以下方式。<br />
<br />
1. Non-blocking 模式<br />
<br />
啟用 non-blocking 模式後,不管是 read 還是 write 就不會被 block住。但會傳回 errno 錯誤碼,<br />
這時就必須自已再做讀寫的動作。<br />
想使用 non-blocking 模式的話,可在 open() 開檔時指定 O_NONBLOCK。<br />
<br />
2. 同時執行多個同步 I/O 工作<br />
同時執行多個同步 I/O 工作 指的是使用 select 系統呼叫的做法。<br />
select 系統呼叫本身會被 block, 但可指定 timeout。<br />
<br />
使用 select() 的時候,有幾個常用的函式巨集,可參考 man 2 select。<br />
<br />
int select(int nfds, fd_set *readfds, fd_set *writefds,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> fd_set *exceptfds, struct timeval *timeout);<br />
<br />
void FD_CLR(int fd, fd_set *set);<br />
int FD_ISSET(int fd, fd_set *set);<br />
void FD_SET(int fd, fd_set *set);<br />
void FD_ZERO(fd_set *set);<br />
<br />
還有一個和 select()很類似的 poll()系統呼叫,以基本功能來說,select()與poll()都一樣,<br />
但指定的 file handler的方式不一樣,且指定多個 file handler 的時候,poll()走訪所有<br />
file handler的速度比較快。 可參考 man 2 poll。<br />
int poll(struct pollfd *fds, nfds_t nfds, int timeout);<br />
<br />
應用程式想同時執行多個同步 I/O 工作時,可使用的系統呼叫有好幾個,<br />
但在驅動程式,只需要準備一個函式即可。<br />
不管 user process 用了哪個系統呼叫,kernel 都只會呼叫驅動程式提供的這個函式。<br />
<br />
Character 類型的裝置想支援同時執行多個同步 I/O 工作的話,只要在驅動程式準備 poll方法即可。<br />
poll方法會收到 file_operations 結構。<br />
unsigned int (*poll) (struct file *, struct poll_table_struct *);<br />
<br />
poll方法會在kernel 處理 select 與 poll 之類的系統呼叫時用到。它必須的執行工作如下:<br />
1. 在 wait queue 豋記。<br />
2. 傳回目前可以操作的狀態。<br />
<br />
在呼叫同時執行多個同步 I/O 工作的系統呼叫時,block 直到狀態變化的動作,指的是在 kernel裡面 sleep。<br />
如果要 sleep的話,要先準備 wait queue(wait_queue_head_t),這個由驅動程式負責提供。<br />
豋記 wait queue 的工作可透過 poll_wait()完成,它定義在 include/linux/poll.h<br />
<br />
void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);<br />
<br />
在呼叫同時執行多個同步 I/O 工作的系統呼叫時,解除 block 的時機,是驅動程式透過傳給 poll_wait()<br />
的 wait queue 被喚醒的時候。Kernel 在被 wait queue 喚醒之後,會再次呼叫驅動程式的 poll()<br />
確認是否成為等待中的狀態(可寫入或可讀出),如果是的話,FD_ISSET 巨集就會成立。<br />
想判斷是不是這種狀態的話,還是需要驅動程式提供資訊才行,這個資訊就是透過poll()方法的傳回值來表示。<br />
傳回值要透過 include/linux/poll.h 定義的巨集 OR 起來表示,下面是常用到的組合。<br />
<br />
POLLIN|POLLRDNORM 可讀取<br />
POLLOUT|POLLWRNORM 可寫入<br />
POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM 可讀寫<br />
POLLERR 發生錯誤<br />
POLLHUP 裝置離線(EOF)<br />
<br />
說了那麼多,還倒不如寫個程式比較好了解。<br />
<br />
剛試了一下,果然新舊版核心還是有差,幾個問題,稍為提出來討論一下:<br />
1. 要用 kmalloc 及 kfree 的話,要 include <linux/slab.h><br />
註:其實在上一個示範程式就已有這問題了。<br />
請參考: 基礎 Linux Device Driver 驅動程式#9 (IOCTL)<br />
2. void init_MUTEX (struct semaphore *sem); /* 新版 kernel 已不適用 */<br />
改用<br />
void sema_init (struct semaphore *sem, int val);<br />
<br />
test_select.c 原始碼如下:<br />
/*****************************************************************************/<br />
#include <linux/init.h><br />
#include <linux/module.h><br />
#include <linux/types.h><br />
#include <linux/kernel.h><br />
#include <linux/fs.h><br />
#include <linux/cdev.h><br />
#include <linux/device.h><br />
#include <linux/slab.h><br />
#include <linux/poll.h><br />
#include <linux/sched.h><br />
#include <asm/uaccess.h><br />
<br />
#define DRIVER_NAME "test_select"<br />
<br />
static unsigned int test_select_major = 0;<br />
static unsigned int num_of_dev = 1;<br />
static struct cdev test_select_cdev;<br />
static unsigned int timeout_value = 10;<br />
<br />
struct test_select_data {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct timer_list timeout;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>spinlock_t lock;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>wait_queue_head_t read_wait;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int timeout_done;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct semaphore sem;<br />
};<br />
<br />
unsigned int test_select_poll(struct file *filp, poll_table *wait)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_select_data *data = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned int mask = POLLOUT|POLLWRNORM;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Call test_select_poll.\n");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (data == NULL)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -EBADFD;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>down(&data->sem);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>poll_wait(filp, &data->read_wait, wait);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (data->timeout_done == 1) { /* readable */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>mask |= POLLIN|POLLRDNORM;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>up(&data->sem);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s returned (mask 0x%x)\n", __func__, mask);<br />
}<br />
<br />
static void test_select_timeout(unsigned long arg)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_select_data *data = (struct test_select_data*)arg;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned long flags;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Call test_select_timeout.\n");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>spin_lock_irqsave(&data->lock, flags);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->timeout_done = 1;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>wake_up_interruptible(&data->read_wait);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>spin_unlock_irqrestore(&data->lock, flags);<br />
}<br />
<br />
ssize_t test_select_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -EFAULT;<br />
}<br />
<br />
ssize_t test_select_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_select_data *data = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int i;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int retval;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (down_interruptible(&data->sem))<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ERESTARTSYS;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (data->timeout_done == 0) { /* no read */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>up(&data->sem);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (filp->f_flags & O_NONBLOCK) /* non-blocking mode */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -EAGAIN;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>do {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = wait_event_interruptible_timeout(<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->read_wait,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->timeout_done == 1,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>1*HZ);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (retval == -ERESTARTSYS)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ERESTARTSYS;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>} while (retval == 0); /* timeout elapsed */<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (down_interruptible(&data->sem))<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ERESTARTSYS;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>val = 0xff;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>for (i = 0; i < count; i++) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (copy_to_user(&buf[i], &val, 1)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = -EFAULT;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto out;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = count;<br />
<br />
out:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->timeout_done = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>/* restart timer */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>mod_timer(&data->timeout, jiffies + timeout_value*HZ);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>up(&data->sem);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return retval;<br />
}<br />
<br />
static int test_select_close(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_select_data *data = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Call test_select_close.\n");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (data) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>del_timer_sync(&data->timeout);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>kfree(data);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int test_select_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_select_data *data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Call test_select_open.\n");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data = kmalloc(sizeof(struct test_select_data), GFP_KERNEL);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (data == NULL)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ENOMEM;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>/* initialize members */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>spin_lock_init(&data->lock);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>init_waitqueue_head(&data->read_wait);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>// init_MUTEX(&data->sem); /* 新版 kernel 已不適用 */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>sema_init(&data->sem, 1); /* 改用 sema_init */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>init_timer(&data->timeout);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->timeout.function = test_select_timeout;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->timeout.data = (unsigned long)data;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->private_data = data;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>/* start timer */<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data->timeout_done = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>mod_timer(&data->timeout, jiffies + timeout_value*HZ);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
struct file_operations fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.owner = THIS_MODULE,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = test_select_open,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = test_select_close,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.read = test_select_read,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.write = test_select_write,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.poll = test_select_poll,<br />
};<br />
<br />
static int test_select_init(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(test_select_major, 0);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int alloc_ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int cdev_ret = 0;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>test_select_major = MAJOR(dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_init(&test_select_cdev, &fops);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_ret = cdev_add(&test_select_cdev, dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver(major: %d) installed.\n", DRIVER_NAME, test_select_major);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
error:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&test_select_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -1;<br />
}<br />
<br />
static void test_select_exit(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(test_select_major, 0);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&test_select_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver removed\n", DRIVER_NAME);<br />
}<br />
<br />
module_init(test_select_init);<br />
module_exit(test_select_exit);<br />
<br />
MODULE_LICENSE("GPL");<br />
MODULE_AUTHOR("Wang Chen Shu");<br />
MODULE_DESCRIPTION("This is test_select module.");<br />
<br />
/*****************************************************************************/<br />
<br />
Makefile 如下:<br />
/*****************************************************************************/<br />
KDIR="/opt/linux-source-2.6.38"<br />
PWD=$(shell pwd)<br />
<br />
obj-m := test_select.o<br />
<br />
all:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} modules<br />
clean:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} clean<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
/*****************************************************************************/<br />
<br />
test.c 如下:<br />
/*****************************************************************************/<br />
#include <stdio.h><br />
#include <fcntl.h><br />
#include <errno.h><br />
<br />
#define DEVFILE "/dev/test_select0"<br />
<br />
int main()<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int fd;<br />
fd_set rfds;<br />
struct timeval tv;<br />
int retval;<br />
unsigned char buf;<br />
ssize_t sz;<br />
int i;<br />
<br />
fd = open(DEVFILE, O_RDWR);<br />
if (fd == -1) {<br />
perror("open");<br />
return -1;<br />
}<br />
<br />
do {<br />
FD_ZERO(&rfds);<br />
FD_SET(fd, &rfds);<br />
tv.tv_sec = 5;<br />
tv.tv_usec = 0;<br />
<br />
printf("select() ...\n");<br />
retval = select(fd + 1, &rfds, NULL, NULL, &tv);<br />
if (retval == -1) {<br />
perror("select");<br />
break;<br />
}<br />
<br />
if (retval) {<br />
break;<br />
}<br />
} while (retval == 0); /* timeout elapsed */<br />
<br />
if (FD_ISSET(fd, &rfds)) {<br />
printf("read() ...\n");<br />
sz = read(fd, &buf, 1);<br />
printf("read() %d\n", sz);<br />
printf("%02x ", buf);<br />
printf("\n");<br />
}<br />
<br />
close(fd);<br />
<br />
return 0;<br />
<br />
}<br />
<br />
/*****************************************************************************/<br />
<br />
執行結果如下:<br />
<br />
# ls<br />
Makefile test_code test_select.c<br />
# make<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/test_select modules<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CC [M] /opt/test_driver/my_driver/test_select/test_select.o<br />
/opt/test_driver/my_driver/test_select/test_select.c: In function ‘test_select_poll’:<br />
/opt/test_driver/my_driver/test_select/test_select.c:44:1: warning: control reaches end of non-void function<br />
Building modules, stage 2.<br />
MODPOST 1 modules<br />
CC /opt/test_driver/my_driver/test_select/test_select.mod.o<br />
LD [M] /opt/test_driver/my_driver/test_select/test_select.ko<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
# ls<br />
Makefile Module.symvers test_select.c test_select.mod.c test_select.o<br />
modules.order test_code test_select.ko test_select.mod.o<br />
# cd test_code/<br />
# ls<br />
test.c<br />
# gcc test.c -o test<br />
# ls<br />
test test.c<br />
# cd ..<br />
# insmod ./test_select.ko<br />
test_select driver(major: 250) installed.<br />
# mknod /dev/test_select0 c 250 0<br />
# ./test_code/test<br />
select() ...<br />
read() ...<br />
... 經過 10秒 ...<br />
read() 1<br />
ff<br />
# dmesg | tail<br />
... 以上略過 ...<br />
Call test_select_open.<br />
Call test_select_poll.<br />
test_select_poll returned (mask 0x104)<br />
Call test_select_timeout.<br />
Call test_select_close.<br />
<br />
# rm -rf test_code/test<br />
# rm /dev/test_select0<br />
# rmmod test_select<br />
# make clean<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/test_select clean<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CLEAN /opt/test_driver/my_driver/test_select/.tmp_versions<br />
CLEAN /opt/test_driver/my_driver/test_select/Module.symvers<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
<br />
OK, 一切就是如此的順利,世界就是如此的美好 ^^<br />
<br />
<br />
註記及聲明:<br />
本教學,是參考Linux Device Driver Programming驅動程式設計由平田豐著的這本書。csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-39041498773033314962012-01-03T22:48:00.000-08:002012-01-03T22:53:40.008-08:00基礎 Linux Device Driver 驅動程式#9 (IOCTL)IOCTL 是一種系統呼叫介面,user process 呼叫 ioctl() 即可對驅動程式送出系統呼叫,<br />
如此會呼叫驅動程式的 IOCTL 處理函式,也可跟驅動程式交換資料。<br />
交換資料的格式,可由驅動程式開發者自由決定。<br />
<br />
IOCTL 方法的 prototype如下:<br />
int (*ioctl)(struct inode *inode, struct file *filp,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned int cmd, unsigned long arg);<br />
<br />
inode: 是開啟裝置檔的相關資訊。<br />
filp: 可取出驅動程式的私有資料。<br />
cmd: 是 IOCTL 的指令,且不可省略,驅動程式可由它得知 user process 想做什麼。<br />
arg: 是 ioctl()可變引數(...)的參數,內含 user process的指標,但驅動程式不得<br />
直接讀寫這個指標,必須透過copy_from_user() 及 copy_to_user() 讀寫資料。<br />
<br />
但,各位可能要注意一個小地方囉,我目前用的 linux kernel 是 2.6.38,<br />
ioctl 這個 handler 在 2.3.36的核心版本已不用這個名稱了,<br />
改用以下兩個:<br />
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);<br />
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);<br />
<br />
所以要注意喔,如果各位也是和我用一樣新核心的話,就....你知道的。<br />
我示範的 code 也會用 unlocked_ioctl 這個 handler。<br />
<br />
IOCTL 指令的格式是以巨集定義的。驅動程式與user process 的程式共用一個標頭檔。<br />
四個巨集分別如下:<br />
_IO(): 無引數的 IOCTL。<br />
_IOR(): 從驅動程式讀取資料。<br />
_IOW(): 把資料寫給驅動程式。<br />
_IOWR(): 與驅動程式讀寫資料。<br />
<br />
定義在 include/asm-generic/ioctl.h<br />
<br />
/* used to create numbers */<br />
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)<br />
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))<br />
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))<br />
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))<br />
<br />
驅動程式可使用 _IO_SIZE 巨集得知傳給 ioctl() 可變引數的結構大小。<br />
也是定義在 include/asm-generic/ioctl.h<br />
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)<br />
<br />
在讀寫 user space 的指標時,可以呼叫 access_ok() 判斷指標可否讀讀寫。<br />
定義在 include/asm-generic/uaccess.h<br />
#define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size))<br />
<br />
當然有些時候,會只限定root才能使用 ioctl,一般使用者不能使用,可用 int capable(int cap);<br />
<br />
再來寫個 code 跑一下吧^^<br />
但在這之前,我們先看一下我們要 include 的標頭檔,如下:<br />
<br />
test_ioctl.h<br />
/*****************************************************************************/<br />
<br />
#ifndef _IOCTL_TEST_H<br />
#define _IOCTL_TEST_H<br />
<br />
#include <linux/ioctl.h><br />
<br />
struct ioctl_arg {<br />
unsigned int reg;<br />
unsigned int val;<br />
};<br />
<br />
/* 這裡要找一個沒用到的號碼,請參考 Documentation/ioctl/ioctl-number.txt */<br />
#define IOC_MAGIC '\x66'<br />
<br />
/* 您要的動作 */<br />
#define IOCTL_VALSET _IOW(IOC_MAGIC, 0, struct ioctl_arg)<br />
#define IOCTL_VALGET _IOR(IOC_MAGIC, 1, struct ioctl_arg)<br />
#define IOCTL_VALGET_NUM _IOR(IOC_MAGIC, 2, int)<br />
#define IOCTL_VALSET_NUM _IOW(IOC_MAGIC, 3, int)<br />
<br />
#define IOCTL_VAL_MAXNR 3<br />
<br />
#endif<br />
<br />
/*****************************************************************************/<br />
<br />
test_ioctl.c 原始碼如下:<br />
/*****************************************************************************/<br />
<br />
#include <linux/init.h><br />
#include <linux/module.h><br />
#include <linux/fs.h><br />
#include <linux/cdev.h><br />
#include <linux/slab.h><br />
#include <asm/uaccess.h><br />
#include "test_ioctl.h"<br />
<br />
#define DRIVER_NAME "test_ioctl"<br />
static unsigned int test_ioctl_major = 0;<br />
static unsigned int num_of_dev = 1;<br />
static struct cdev test_ioctl_cdev;<br />
static int ioctl_num = 0;<br />
<br />
struct test_ioctl_data {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>rwlock_t lock;<br />
};<br />
<br />
static long test_ioctl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_ioctl_data *ioctl_data = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int retval;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct ioctl_arg data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>memset(&data, 0, sizeof(data));<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (cmd) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>case IOCTL_VALSET:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>/*<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!capable(CAP_SYS_ADMIN)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = -EPERM;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto done;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd))) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = -EFAULT;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto done;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>*/<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (copy_from_user(&data, (int __user *)arg, sizeof(data))) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = -EFAULT;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto done;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "IOCTL set val:%x .\n", data.val);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>write_lock(&ioctl_data->lock);<br />
ioctl_data->val = data.val;<br />
write_unlock(&ioctl_data->lock);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>case IOCTL_VALGET:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>/*<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd))) {<br />
retval = -EFAULT;<br />
goto done;<br />
}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>*/<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read_lock(&ioctl_data->lock);<br />
val = ioctl_data->val;<br />
read_unlock(&ioctl_data->lock);<br />
data.val = val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (copy_to_user((int __user *)arg, &data, sizeof(data)) ) {<br />
retval = -EFAULT;<br />
goto done;<br />
}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>case IOCTL_VALGET_NUM:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = __put_user(ioctl_num, (int __user *)arg);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>case IOCTL_VALSET_NUM:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>/*<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!capable(CAP_SYS_ADMIN))<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -EPERM;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>*/<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ioctl_num = arg;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>default:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = -ENOTTY;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
done:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return retval;<br />
}<br />
<br />
ssize_t test_ioctl_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_ioctl_data *ioctl_data = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int retval;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int i = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read_lock(&ioctl_data->lock);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>val = ioctl_data->val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read_unlock(&ioctl_data->lock);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>for (;i < count ;i++) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (copy_to_user(&buf[i], &val, 1)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = -EFAULT;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto out;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>retval = count;<br />
<br />
out:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return retval;<br />
}<br />
<br />
static int test_ioctl_close(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s call.\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (filp->private_data) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>kfree(filp->private_data);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->private_data = NULL;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int test_ioctl_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct test_ioctl_data *ioctl_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s call.\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ioctl_data = kmalloc(sizeof(struct test_ioctl_data), GFP_KERNEL);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (ioctl_data == NULL)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ENOMEM;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>rwlock_init(&ioctl_data->lock);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ioctl_data->val = 0xFF;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->private_data = ioctl_data;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
struct file_operations fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.owner = THIS_MODULE,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = test_ioctl_open,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = test_ioctl_close,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.read = test_ioctl_read,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.unlocked_ioctl = test_ioctl_ioctl,<br />
};<br />
<br />
static int test_ioctl_init(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(test_ioctl_major, 0);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int alloc_ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int cdev_ret = 0;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>test_ioctl_major = MAJOR(dev);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_init(&test_ioctl_cdev, &fops);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_ret = cdev_add(&test_ioctl_cdev, dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver(major: %d) installed.\n", DRIVER_NAME, test_ioctl_major);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
error:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&test_ioctl_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -1;<br />
}<br />
<br />
static void test_ioctl_exit(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(test_ioctl_major, 0);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&test_ioctl_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver removed.\n", DRIVER_NAME);<br />
}<br />
<br />
module_init(test_ioctl_init);<br />
module_exit(test_ioctl_exit);<br />
<br />
MODULE_LICENSE("GPL");<br />
MODULE_AUTHOR("Wang Chen Shu");<br />
MODULE_DESCRIPTION("This is test_ioctl module.");<br />
<br />
/*****************************************************************************/<br />
<br />
那當然還少不了測試程式囉。<br />
<br />
test.c 如下:<br />
/*****************************************************************************/<br />
<br />
#include <stdio.h><br />
#include <string.h><br />
#include <errno.h><br />
#include <fcntl.h><br />
#include <sys/ioctl.h><br />
#include "../test_ioctl.h"<br />
<br />
#define DEVFILE "/dev/t1"<br />
<br />
int main(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct ioctl_arg cmd;<br />
int fd;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>long ret;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int num = 0;<br />
<br />
fd = open(DEVFILE, O_RDWR);<br />
if (fd == -1)<br />
perror("open");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>memset(&cmd, 0, sizeof(cmd));<br />
ret = ioctl(fd, IOCTL_VALGET, &cmd);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (ret == -1) {<br />
printf("errno %d\n", errno);<br />
perror("ioctl");<br />
}<br />
printf("val %x\n", cmd.val);<br />
<br />
cmd.val = 0xCC;<br />
ret = ioctl(fd, IOCTL_VALSET, &cmd);<br />
if (ret == -1) {<br />
printf("errno %d\n", errno);<br />
perror("ioctl");<br />
}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ret = ioctl(fd, IOCTL_VALGET, &cmd);<br />
<br />
if (ret == -1) {<br />
printf("errno %d\n", errno);<br />
perror("ioctl");<br />
}<br />
printf("val %x\n", cmd.val);<br />
<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>num = 100;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ret = ioctl(fd, IOCTL_VALSET_NUM, num);<br />
if (ret == -1) {<br />
printf("errno %d\n", errno);<br />
perror("ioctl");<br />
}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ret = ioctl(fd, IOCTL_VALGET_NUM, &num);<br />
<br />
if (ret == -1) {<br />
printf("errno %d\n", errno);<br />
perror("ioctl");<br />
}<br />
printf("num %d\n", num);<br />
<br />
if (close(fd) != 0)<br />
perror("close");<br />
<br />
return 0;<br />
}<br />
<br />
/*****************************************************************************/<br />
<br />
Makefile 如下:<br />
/*****************************************************************************/<br />
<br />
KDIR="/opt/linux-source-2.6.38"<br />
PWD=$(shell pwd)<br />
<br />
obj-m := test_ioctl.o<br />
<br />
all:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} modules<br />
clean:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} clean<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
/*****************************************************************************/<br />
<br />
開始測試囉^^<br />
# ls<br />
Makefile test_code test_ioctl.c test_ioctl.h<br />
# make<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/test_ioctl modules<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CC [M] /opt/test_driver/my_driver/test_ioctl/test_ioctl.o<br />
/opt/test_driver/my_driver/test_ioctl/test_ioctl.c: In function ‘test_ioctl_ioctl’:<br />
/opt/test_driver/my_driver/test_ioctl/test_ioctl.c:23:6: warning: ‘retval’ may be used uninitialized in this function<br />
Building modules, stage 2.<br />
MODPOST 1 modules<br />
CC /opt/test_driver/my_driver/test_ioctl/test_ioctl.mod.o<br />
LD [M] /opt/test_driver/my_driver/test_ioctl/test_ioctl.ko<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
# insmod ./test_ioctl.ko<br />
test_ioctl driver(major: 248) installed.<br />
# cd test_code/<br />
# gcc test.c -o test<br />
# cd ..<br />
# mknod /dev/t1 c 248 0<br />
# ./test_code/test<br />
val ff<br />
val cc<br />
num 100<br />
# dmesg | tail<br />
... /* 這裡略過 */<br />
test_ioctl_open call.<br />
IOCTL set val:cc .<br />
test_ioctl_close call.<br />
# rm /dev/t1<br />
# rmmod test_ioctl<br />
<br />
# make clean<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/test_ioctl clean<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CLEAN /opt/test_driver/my_driver/test_ioctl/.tmp_versions<br />
CLEAN /opt/test_driver/my_driver/test_ioctl/Module.symvers<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
<br />
<br />
完成 ^^<br />
<br />
<br />
註記及聲明:<br />
本教學,是參考Linux Device Driver Programming驅動程式設計由平田豐著的這本書。<br />
<div><br />
</div>csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com11tag:blogger.com,1999:blog-4092020502731521660.post-48972450801751737402012-01-02T01:22:00.000-08:002012-01-02T01:31:27.231-08:00基礎 Linux Device Driver 驅動程式#8 (character device driver基礎_chrdev_sys)前面介紹了那麼多的範例,但您有發現嗎?<br />
所有範例程式的裝置檔,都必須要手動建立,難道不能自動建立嗎?<br />
有,就是 udev,那您會說, udev 是什麼?<br />
簡單,上wiki去查一下就有啦。<br />
它是 Linux kernel 2.6系列的裝置管理器。<br />
更詳細的說明,去wiki看囉,這裡就不多說了。<br />
<br />
您也可以去看您的udevd是否有在運行。<br />
# ps aux | grep udevd<br />
root 315 0.0 0.0 2880 1132 ? S<s 09:35 0:00 udevd --daemon<br />
這就是啦。<br />
<br />
當驅動程式載入時,udevd daemon會偵測到這個事件,而後去檢查/sys目錄,<br />
如果驅動程式建立了dev檔案的話,檔案裡會含有major及minor number,如此 udevd就能以它<br />
建立裝置檔囉。<br />
<br />
想讓驅動程式支援 udev 的話,必須豋錄驅動程式的 class 並在 /sys/class目錄下建立驅動程式資訊。<br />
<br />
豋記class時是用 class_creat()這個kernel 函式。<br />
它的prototype如下:<br />
struct class *class_create(struct module *owner, const char *name);<br />
owner: 還記得嗎? 就是 THIS_MODULE 啊<br />
name: 就放 DRIVER_NAME 即可。<br />
<br />
刪除豋記的 class是用 class_destroy()<br />
void class_destroy (struct class *cls);<br />
<br />
接著要建立 /sys/class/class 名稱/裝置名稱 這個檔案,用的是 device_create()<br />
struct device *device_create(struct class *cls, struct device *parent,<br />
dev_t devt, void *drvdata,<br />
const char *fmt, ...)<br />
<br />
cls: 傳入由class_creat() 傳回的 class。<br />
parent: 是指定上層 class的時候使用的,傳入 NULL也行。<br />
devt: 是dev檔顯示的major/minor number,也可用 MKDEV巨集指定。<br />
drvdate: 是添加到裝置的資料,傳入 NULL也行。<br />
fmt: 裝置檔的名稱。<br />
2.6 要舊的核心,是用class_device_create()<br />
<br />
如要刪除豋記的裝置,可用 device_destroy()<br />
void device_destroy (struct class *class, dev_t devt);<br />
2.6 要舊的核心,是用class_device_destroy()<br />
<br />
大致上了解了之後,再來就是快樂的coding 時間囉^^<br />
不好意思啊,又要等我一下啦。<br />
<br />
時間一分一秒的過去............<br />
好了,<br />
<br />
chrdev_sys.c 程式碼如下:<br />
<br />
/*****************************************************************************/<br />
<br />
#include <linux/init.h><br />
#include <linux/module.h><br />
#include <linux/fs.h><br />
#include <linux/cdev.h><br />
#include <asm/uaccess.h><br />
#include <linux/device.h><br />
<br />
#define DRIVER_NAME "chrdev_sys"<br />
static unsigned int chrdev_sys_major = 0;<br />
static unsigned int num_of_dev = 1;<br />
static struct cdev chrdev_sys_cdev;<br />
static struct class *chrdev_sys_class = NULL;<br />
<br />
static int chrdev_sys_close(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Call chrdev_sys_close.\n");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int chrdev_sys_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "Call chrdev_sys_open.\n");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
struct file_operations fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.owner = THIS_MODULE,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = chrdev_sys_open,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = chrdev_sys_close,<br />
};<br />
<br />
static int chrdev_sys_init(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(chrdev_sys_major, 0);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int alloc_ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int cdev_ret = 0;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>chrdev_sys_major = MAJOR(dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_init(&chrdev_sys_cdev, &fops);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_ret = cdev_add(&chrdev_sys_cdev, dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>chrdev_sys_class = class_create(THIS_MODULE, DRIVER_NAME);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (IS_ERR(chrdev_sys_class))<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>device_create(chrdev_sys_class,<br />
NULL,<br />
MKDEV(chrdev_sys_major, 0),<br />
NULL,<br />
"ch_sys0");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver(major number %d) installed.\n", DRIVER_NAME, chrdev_sys_major);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
error:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&chrdev_sys_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -1;<br />
}<br />
<br />
<br />
static void chrdev_sys_exit(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(chrdev_sys_major, 0);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>device_destroy(chrdev_sys_class, dev);<br />
class_destroy(chrdev_sys_class);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&chrdev_sys_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver removed.\n", DRIVER_NAME);<br />
}<br />
<br />
module_init(chrdev_sys_init);<br />
module_exit(chrdev_sys_exit);<br />
<br />
MODULE_LICENSE("GPL");<br />
MODULE_AUTHOR("Wang Chen Shu");<br />
MODULE_DESCRIPTION("This is chrdev_sys module.");<br />
<br />
/*****************************************************************************/<br />
<br />
Makefile 如下:<br />
/*****************************************************************************/<br />
<br />
KDIR="/opt/linux-source-2.6.38"<br />
PWD=$(shell pwd)<br />
<br />
obj-m := chrdev_sys.o<br />
<br />
all:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} modules<br />
clean:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} clean<br />
<br />
/*****************************************************************************/<br />
<br />
run 一下囉^^<br />
<br />
# ls<br />
chrdev_sys.c Makefile<br />
# make<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/chrdev_sys modules<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CC [M] /opt/test_driver/my_driver/chrdev_sys/chrdev_sys.o<br />
Building modules, stage 2.<br />
MODPOST 1 modules<br />
CC /opt/test_driver/my_driver/chrdev_sys/chrdev_sys.mod.o<br />
LD [M] /opt/test_driver/my_driver/chrdev_sys/chrdev_sys.ko<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
# insmod ./chrdev_sys.ko<br />
chrdev_sys driver(major number 250) installed.<br />
<br />
看一下 /dev/底下是否已有產生了呢?<br />
<br />
# ls -l /dev/ch_sys0<br />
crw------- 1 root root 250, 0 2012-01-02 17:16 /dev/ch_sys0<br />
沒錯吧,哈哈^^<br />
移除看看囉。<br />
# rmmod chrdev_sys<br />
chrdev_sys driver removed.<br />
# ls -l /dev/ch_sys0<br />
ls: 無法存取 /dev/ch_sys0: 沒有此一檔案或目錄<br />
看到了嗎,不見了。<br />
好玩吧......<br />
<br />
<br />
註記及聲明:<br />
本教學,是參考Linux Device Driver Programming驅動程式設計由平田豐著的這本書。<br />
<div><br />
</div>csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-75738563650510980332012-01-01T04:55:00.000-08:002012-01-01T17:47:30.526-08:00基礎 Linux Device Driver 驅動程式#7 (character device driver基礎_minor number)有時候,如果有多個裝置,但想要做出不同的行為,那怎麼辦呢?<br />
之前有介紹過 minor 吧。<br />
minor number得由驅動程式自已去管理,如果想要不同的 minor提供不同的功能的話,<br />
可以在當開啟裝置時,做minor的判斷。<br />
但,如何做呢?不用擔心,接下來,我將會為各位示範實作的方法。<br />
又是來寫code的時候啦,等我囉^^<br />
時間又在一點一滴的流逝....<br />
......................<br />
不好意思,老婆大人在催了,<br />
如有不足的話,我會再check。<br />
<br />
chrdev_minor.c 原始碼如下:<br />
/*****************************************************************************/<br />
<br />
#include <linux/init.h><br />
#include <linux/module.h><br />
#include <linux/kernel.h><br />
#include <linux/types.h><br />
#include <linux/fs.h><br />
#include <linux/cdev.h><br />
#include <linux/sched.h><br />
#include <linux/slab.h><br />
#include <asm/uaccess.h><br />
<br />
#define DRIVER_NAME "chrdev_minor"<br />
static unsigned int chrdev_minor_major = 0;<br />
static unsigned int num_of_dev = 2;<br />
static struct cdev chrdev_minor_cdev;<br />
<br />
ssize_t one_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s called\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
ssize_t one_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s called\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int one_close(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "This is %s (minor=%d)\n", __func__, iminor(inode));<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int one_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "This is %s (minor=%d)\n", __func__, iminor(inode));<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
struct file_operations one_fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = one_open,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = one_close,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.read = one_read,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.write = one_write,<br />
};<br />
<br />
ssize_t zero_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s called\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
ssize_t zero_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s called\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int zero_close(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "This is %s (minor=%d)\n", __func__, iminor(inode));<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int zero_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "This is %s (minor=%d)\n", __func__, iminor(inode));<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
struct file_operations zero_fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = zero_open,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = zero_close,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.read = zero_read,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.write = zero_write,<br />
};<br />
<br />
static int chrdev_minor_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (iminor(inode)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>case 0:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->f_op = &zero_fops;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>case 1:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->f_op = &one_fops;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>default:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ENXIO;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (filp->f_op && filp->f_op->open)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return filp->f_op->open(inode, filp);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
<br />
struct file_operations fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.owner = THIS_MODULE,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = chrdev_minor_open,<br />
};<br />
<br />
static int chrdev_minor_init(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(chrdev_minor_major, 0);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int alloc_ret = 0;<br />
int cdev_ret = 0;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret)<br />
goto error;<br />
chrdev_minor_major = MAJOR(dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_init(&chrdev_minor_cdev, &fops);<br />
cdev_ret = cdev_add(&chrdev_minor_cdev, dev, num_of_dev);<br />
if (cdev_ret)<br />
goto error;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver(major number %d) installed.\n", DRIVER_NAME, chrdev_minor_major);<br />
return 0;<br />
error:<br />
if (cdev_ret == 0)<br />
cdev_del(&chrdev_minor_cdev);<br />
if (alloc_ret == 0)<br />
unregister_chrdev_region(dev, num_of_dev);<br />
return -1;<br />
<br />
}<br />
<br />
static void chrdev_minor_exit(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(chrdev_minor_major, 0);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&chrdev_minor_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver removed.\n", DRIVER_NAME);<br />
}<br />
<br />
module_init(chrdev_minor_init);<br />
module_exit(chrdev_minor_exit);<br />
<br />
MODULE_LICENSE("GPL");<br />
MODULE_AUTHOR("Wang Chen Shu");<br />
MODULE_DESCRIPTION("This is chrdev_minor module.");<br />
<br />
/*****************************************************************************/<br />
<br />
Makefile 如下:<br />
/*****************************************************************************/<br />
<br />
KDIR="/opt/linux-source-2.6.38"<br />
PWD=$(shell pwd)<br />
<br />
obj-m := chrdev_minor.o<br />
<br />
all:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} modules<br />
clean:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} clean<br />
<br />
/*****************************************************************************/<br />
# ls<br />
chrdev_minor.c Makefile<br />
# make<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/chrdev_minor modules<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CC [M] /opt/test_driver/my_driver/chrdev_minor/chrdev_minor.o<br />
/opt/test_driver/my_driver/chrdev_minor/chrdev_minor.c:44:2: warning: initialization from incompatible pointer type<br />
/opt/test_driver/my_driver/chrdev_minor/chrdev_minor.c:75:2: warning: initialization from incompatible pointer type<br />
Building modules, stage 2.<br />
MODPOST 1 modules<br />
CC /opt/test_driver/my_driver/chrdev_minor/chrdev_minor.mod.o<br />
LD [M] /opt/test_driver/my_driver/chrdev_minor/chrdev_minor.ko<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
# ls<br />
chrdev_minor.c chrdev_minor.mod.c chrdev_minor.o modules.order<br />
chrdev_minor.ko chrdev_minor.mod.o Makefile Module.symvers<br />
# insmod ./chrdev_minor.ko<br />
chrdev_minor driver(major number 250) installed.<br />
# mknod /dev/ch_m1 c 250 0<br />
# mknod /dev/ch_m2 c 250 1<br />
# ls -l /dev/ch_m*<br />
crw-r--r-- 1 root root 250, 0 2012-01-01 20:38 /dev/ch_m1<br />
crw-r--r-- 1 root root 250, 1 2012-01-01 20:38 /dev/ch_m2<br />
# cat /dev/ch_m1<br />
# dmesg | tail<br />
.......... /* 以上略過 */<br />
This is zero_open (minor=0)<br />
zero_read called<br />
This is zero_close (minor=0)<br />
<br />
# cat /dev/ch_m2<br />
# dmesg | tail<br />
.......... /* 以上略過 */<br />
This is one_open (minor=1)<br />
one_read called<br />
This is one_close (minor=1)<br />
<br />
各位,真不好意思囉,接下來的教學,未完待續.....csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0tag:blogger.com,1999:blog-4092020502731521660.post-17455340634332083062012-01-01T01:45:00.000-08:002012-01-03T19:05:29.273-08:00基礎 Linux Device Driver 驅動程式#6 (character device driver基礎_讀寫)既然各位對最基本的驅動程式已有概念了,<br />
那當然我們得再去一步的探討囉。<br />
<br />
在上一個驅動程式,我們實作了open及release,<br />
但,實際上只有這些handler了嗎?<br />
當然不只,還有以下實作:<br />
是定義在 include/include/linux/fs.h 裡。<br />
struct file_operations {<br />
struct module *owner;<br />
loff_t (*llseek) (struct file *, loff_t, int);<br />
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);<br />
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);<br />
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);<br />
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);<br />
int (*readdir) (struct file *, void *, filldir_t);<br />
unsigned int (*poll) (struct file *, struct poll_table_struct *);<br />
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);<br />
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);<br />
int (*mmap) (struct file *, struct vm_area_struct *);<br />
int (*open) (struct inode *, struct file *);<br />
int (*flush) (struct file *, fl_owner_t id);<br />
int (*release) (struct inode *, struct file *);<br />
int (*fsync) (struct file *, int datasync);<br />
int (*aio_fsync) (struct kiocb *, int datasync);<br />
int (*fasync) (int, struct file *, int);<br />
int (*lock) (struct file *, int, struct file_lock *);<br />
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);<br />
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);<br />
int (*check_flags)(int);<br />
int (*flock) (struct file *, int, struct file_lock *);<br />
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);<br />
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);<br />
int (*setlease)(struct file *, long, struct file_lock **);<br />
long (*fallocate)(struct file *file, int mode, loff_t offset,<br />
loff_t len);<br />
};<br />
<br />
但隨著之後的範例會愈來愈多,非常建議各位有獨立的機器或者跑虛擬機比較保險喔^^<br />
回到主題,既然有這麼多的 handler的實作,但並不是完全都用得到,那其它沒用到的函式呢?<br />
最基本的驅動程式,都會實作open與release(close),其他沒實作的handler就會被定義成NULL。<br />
<br />
像open 這個handler,也就是user process的程式在操作裝置檔做的開啟動作,<br />
結束當然就是release囉。<br />
而其中的 inode 引數,是一個內含inode資訊的結構指標,有幾個成員我們會用到的,<br />
<br />
bdev_t i_rdev Major/Minor Number<br />
void *i_private 驅動程式私有指標<br />
<br />
既然如此,我們就可以透過 i_rdev這個成員去取得 major及minor number了。<br />
怎麼做呢? Linux已提供了以下方法提供實作:<br />
unsigned int iminor(const struct inode *inode);<br />
unsigned int imajor(const struct inode *inode);<br />
<br />
i_private 成員則是驅動程式可以自由使用的指標,不設定也沒關係。<br />
<br />
file 也是很大的一個結構,以下是常用的幾個成員:<br />
struct file_operations *fops 系統呼叫 handlers<br />
unsigned int f_flags open函式第二個引數傳入的旗標<br />
void *private_data 驅動程式私有資料指標<br />
<br />
通常 fops 不需修改,但有時假設需要對不同裝置提供不同的處理的話,就可自已更新fops的成員。<br />
open handler傳回值 0為成功,非0為失敗。<br />
<br />
在上篇教學,我們只示範了open與release這兩個 handler,再來,我們將實作read及write 這兩個handler。<br />
<br />
ssize_t *read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);<br />
read handler 是指 當user process的程式想要向驅動程式讀取資料時用的。<br />
file 這個結構指標是指向開啟裝置檔 kernel建立的file 結構,和open收到的指標是同一個。<br />
因此,當open handler設給 filp->private成員的指標,在read handler也能拿來用。<br />
<br />
buf引數是 user process呼叫read()時指定的緩衝區指標,但驅動程式不能直接取用buf指標,<br />
必須透過 copy_to_user 這個kernel提供的函式將資料複製過去。<br />
<br />
count引數是 user process呼叫read()時提供的緩衝區空間。<br />
f_pos引數是offset。<br />
<br />
read handler傳回值 0為什麼都沒做,正為寫入緩衝區的byte數,負為發生錯誤。<br />
<br />
ssize_t *write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);<br />
write handler和read handler差不多,主要差在,write handler是當user process要傳資料給驅動時用到的,<br />
所以 buf引數就必須用 copy_from_user 這個kernel提供的函式將資料從緩衝區讀入。<br />
<br />
read handler傳回值 0為什麼都沒做,正為從緩衝區讀入的byte數,負為發生錯誤。<br />
<br />
相信各位已對read 與write這兩個 handler有了初步的了解,就來試一下囉^^<br />
給我點時間,寫一下code喔。<br />
時間一點一滴的流失.....<br />
....................<br />
好囉,sorry, 久等了,那我們就來run一下囉^^<br />
<br />
chrdev_rw.c 原始碼如下:<br />
/*****************************************************************************/<br />
<br />
#include <linux/init.h><br />
#include <linux/module.h><br />
#include <linux/kernel.h><br />
#include <linux/types.h><br />
#include <linux/fs.h><br />
#include <linux/cdev.h><br />
#include <linux/sched.h><br />
#include <linux/slab.h><br />
#include <asm/uaccess.h><br />
<br />
#define DRIVER_NAME "chrdev_rw"<br />
<br />
static unsigned int num_of_dev = 1;<br />
static unsigned int chrdev_rw_major = 0;<br />
static struct cdev chrdev_rw_cdev;<br />
<br />
struct chrdev_rw_data {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>rwlock_t lock;<br />
};<br />
<br />
static int chrdev_rw_open(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct chrdev_rw_data *data_p;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data_p = (struct chrdev_rw_data *)kmalloc(sizeof(struct chrdev_rw_data), GFP_KERNEL);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (data_p == NULL) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "malloc error!!!\n");<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -ENOMEM;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
data_p->val = 0xff;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>rwlock_init(&data_p->lock);<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->private_data = data_p;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
static int chrdev_rw_close(struct inode *inode, struct file *filp)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (filp->private_data) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>kfree(filp->private_data);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>filp->private_data = NULL;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
return 0;<br />
}<br />
<br />
ssize_t chrdev_rw_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct chrdev_rw_data *data_p = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int val_ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int i;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read_lock(&data_p->lock);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>val = data_p->val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read_unlock(&data_p->lock);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>for (i = 0; i < count; i++) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (copy_to_user(&buf[i], &val, 1)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>val_ret = -EFAULT;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto out;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>val_ret = count;<br />
out:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return val_ret;<br />
}<br />
<br />
ssize_t chrdev_rw_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>struct chrdev_rw_data *data_p = filp->private_data;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int val_ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s\n", __func__);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (count >= 1) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (copy_from_user(&val, &buf[0], 1)) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>val_ret = -EFAULT;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto out;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>write_lock(&data_p->lock);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>data_p->val = val;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>write_unlock(&data_p->lock);<br />
<br />
out:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return val_ret;<br />
}<br />
<br />
struct file_operations fops = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.owner = THIS_MODULE,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.open = chrdev_rw_open,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = chrdev_rw_close,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.read = chrdev_rw_read,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>.write = chrdev_rw_write,<br />
};<br />
<br />
static int chrdev_rw_init(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(chrdev_rw_major, 0);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int alloc_ret = 0;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int cdev_ret = 0;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>chrdev_rw_major = MAJOR(dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_init(&chrdev_rw_cdev, &fops);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_ret = cdev_add(&chrdev_rw_cdev, dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>goto error;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver(major number %d) installed.\n", DRIVER_NAME, chrdev_rw_major);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
error:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (cdev_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&chrdev_rw_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (alloc_ret == 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return -1;<br />
}<br />
<br />
static void chrdev_rw_exit(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>dev_t dev = MKDEV(chrdev_rw_major, 0);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>cdev_del(&chrdev_rw_cdev);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unregister_chrdev_region(dev, num_of_dev);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printk(KERN_ALERT "%s driver removed.\n", DRIVER_NAME);<br />
}<br />
<br />
module_init(chrdev_rw_init);<br />
module_exit(chrdev_rw_exit);<br />
<br />
MODULE_LICENSE("GPL");<br />
MODULE_AUTHOR("Wang Chen Shu");<br />
MODULE_DESCRIPTION("This is chrdev_rw module.");<br />
<br />
/*****************************************************************************/<br />
<br />
Makefile 如下:<br />
/*****************************************************************************/<br />
<br />
KDIR="/opt/linux-source-2.6.38"<br />
PWD=$(shell pwd)<br />
<br />
obj-m := chrdev_rw.o<br />
<br />
all:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} modules<br />
clean:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(MAKE) -C ${KDIR} M=${PWD} clean<br />
<br />
/*****************************************************************************/<br />
<br />
有驅動程式原始碼和Makefile,當然也少不了測試程式囉,如下:<br />
<br />
test_rw.c<br />
/*****************************************************************************/<br />
<br />
#include <stdio.h><br />
#include <errno.h><br />
#include <fcntl.h><br />
<br />
#define DEV_FILE "/dev/ch_rw"<br />
<br />
int main(void)<br />
{<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>int fd;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char buf;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ssize_t ret;<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>fd = open(DEV_FILE, O_RDWR);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (fd == -1)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>perror("open");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read(fd, &buf, 1);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("Before write, char is %x\n", buf);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>buf = 0xCC;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>ret = write(fd, &buf, 1);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (ret <= 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>perror("write");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>read(fd, &buf, 1);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("After write, char is %x\n", buf);<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if (close(fd) != 0)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>perror("close");<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;<br />
}<br />
<br />
/*****************************************************************************/<br />
那我們就來run一下囉。<br />
<br />
# ls<br />
chrdev_rw.c Makefile test_code<br />
# make<br />
make -C "/opt/linux-source-2.6.38" M=/opt/test_driver/my_driver/chrdev_rw modules<br />
make[1]: Entering directory `/opt/linux-source-2.6.38'<br />
CC [M] /opt/test_driver/my_driver/chrdev_rw/chrdev_rw.o<br />
Building modules, stage 2.<br />
MODPOST 1 modules<br />
CC /opt/test_driver/my_driver/chrdev_rw/chrdev_rw.mod.o<br />
LD [M] /opt/test_driver/my_driver/chrdev_rw/chrdev_rw.ko<br />
make[1]: Leaving directory `/opt/linux-source-2.6.38'<br />
# ls<br />
chrdev_rw.c chrdev_rw.ko chrdev_rw.mod.c chrdev_rw.mod.o chrdev_rw.o Makefile modules.order Module.symvers test_code<br />
# cd test_code/<br />
# ls<br />
test_rw.c<br />
# gcc test_rw.c -o test_rw<br />
# ls<br />
test_rw test_rw.c<br />
<br />
OK, 模組和測試程式都編好了後,就來測試一下。<br />
# cd ..<br />
# insmod ./chrdev_rw.ko<br />
chrdev_rw driver(major number 250) installed.<br />
# mknod /dev/ch_rw c 250 0<br />
# cd test_code/<br />
# ./test_rw<br />
Before write, char is ff<br />
write: Success<br />
After write, char is cc<br />
<br />
成功~~~~~<br />
<br />
我們目前是用 read_lock 和 write_lock做資料讀寫的鎖定,<br />
但實際上還有很多種方式,到時,在後面的教學,我將會為各位說明更多種的實作方法。<br />
<br />
<br />
註記及聲明:<br />
本教學,是參考Linux Device Driver Programming驅動程式設計由平田豐著的這本書。csw.dawnhttp://www.blogger.com/profile/01094796808081390589noreply@blogger.com0