2015年11月25日

Acer Chromebook 13 Chrubuntu UPower修正

前言:
因為Ubuntu 14.04沒有MATE for armhf,
加上網路上建議用Ubuntu 15.04加上BlueZ 5來解決Bluetooth Smart的問題,
因此目前正著手將chrubuntu 15.04放上Acer Chromebook 13。

目前狀態還不錯,整體支援性感覺比Ubuntu 14.04還要好得多,
需要修正的比較少,
但這次有個大問題,電池電量無法顯示,
這問題在Ubuntu 14.04有出現,但xfce4上面能夠顯示就將就不管它,
Ubuntu 15.04沒這麼幸運,因此就下去Debug了。

問題原因:
問題的關鍵很容易透過systemctl看得出來,就是UPower Daemon無法啟動,
UPower Daemon執行檔在
/usr/lib/upower/upowerd

可以透過
/usr/lib/upower/upowerd -v

取得執行過程的訊息。

出問題的訊息如下:
問題解法:
經過Trace和gdb追蹤,還有拿桌上型電腦正常運作的upowerd比對後,
得到的root cause如下:
1. native-path錯誤
2. object path錯誤

native-path錯誤:
其實從訊息可以注意到,upowerd不認識bq24735@5-0009這顆電源管理IC,
Google後發現,它在新版Kernel中有針對名稱有Patch,
但我們的使用情境中,Kernel不能變動,且驅動程式已經處理過了,
因此我們要改的就是upowerd這端。

針對native-path的修改如下:
up-native.c



修改up-native.c,檢查名稱,如果開頭沒有「/」,
就加上Acer Chromebook 13的prefix名稱。

這邊的修改用了malloc,但因為這行程式碼grep看起來,用的位置不多,
所以應該是不會有memory leak的問題。

object path錯誤:
針對object path的修改如下:
另一個問題則是object path,這個問題是真正會引發Segfault的問題所在,
參考:
http://upower.freedesktop.org/docs/UPower.html


在upowerd中,DBus的名稱必須是固定如上圖所示,
但在前面的問題截圖中可以注意到,它名稱變成:
/org/freedesktop/UPower/devices/line_power_bq24735@5-0009

這造成upowerd後面程式碼parse時出現問題而Segfault。

針對up-device.c修改如下:
up-device.c



這邊只是簡單的查詢bq24735電源管理IC和sbs電池管理IC,
然後根據這2顆IC的情況修改成相對應的字串。

結果:
修改後執行結果。

upowerd執行如下:


看起來upowerd運作正常。

MATE的電源統計程式:



從電源統計程式看起來,能夠正確取得AC和電池狀態。

UPower檔案下載:
Ubuntu ARM 15.04 UPower deb下載
Ubuntu ARM 15.10 UPower deb下載

Ubuntu ARM 15.04 UPower完整deb打包
Ubuntu ARM 15.10 UPower完整deb打包

Ubuntu ARM 15.04 UPower完整程式碼含修改打包
Ubuntu ARM 15.10 UPower完整程式碼含修改打包

Chrubuntu 15.04修整好後,也會和先前一樣放tar檔提供下載。

2015年8月16日

COSCUP 2015 Jserv 封麥的感慨

我竟然有資訊業老人的感慨出現,太可怕了!
我從來不是 Linux 的名人,但我的確很早就在玩 Linux,
因此我覺得我可以從旁觀者角度看這些。

我的啟蒙是 李建達 的黑皮書(FreeBSD入門與應用),
黑皮書的那些年,名人當屬 李建達、woju,
顯學是 FreeBSD,ipfw、陽光沙灘BBS、news、bind、sendmail...等,
還記得當時的中文系統 big5con 嗎?還記得加密終端機 SNP?

就在某個 moment,RedHat CLE 出現了,Debian 無痛起步出現了,
鳥哥 出現了,Jserv 出現了!
顯學變成了 Linux,busybox、u-boot、RedBoot、Embedded Linux,
還記得當時的入門開發板,S3C4510B、S3C2410X,
努力一星期,只是為了把BootLoader放上去,
或是patch Kernel讓它能開機、網路能運作。

現在,Big Data 興起、物聯網興起、機器人興起,
顯學變成了Python、GoLang、Hadoop...等,而 Jserv,封麥了,
我感覺到資訊業一個世代隨著 Jserv 封麥,正式結束了。

在感慨一個世代結束的同時,也對新的世代充滿期待,
資訊業不缺名人,也永遠有新的顯學,
在這個新世代興起的 moment,除了以高速學習新顯學外,
就是繼續以旁觀者的角度,期待新的名人出現,
帶領大家往偉大的新航路前進。

附上我自己的黑皮書封面照片,
(舊版黑皮書暫時找不到,這本是新版)。

2015年1月25日

HPLIP bb-soap解析 - 4 - bb_end_page 和 bb_end_scan

前言:
接續前篇,這篇會將bb_end_page和bb_end_scan一起po完,主要會是解析bb_end_scan,
因為從前面的flow可以發現,bb_end_page實際動作應該只有做hpmud_channel_close(),
其他幾乎沒看到在幹嘛,所以這篇主要就變成了bb_end_scan的解析。

在一開始時,嘗試要把Close Code Library自己實做,覺得似乎非常困難,
要知道這可是現成的事務機,要破解它的Protocol應該很難吧......

實際下去理解並dump它的通訊內容後,其實並不難,
整個flow看完理解後,我就在想,真的還需要補充實做bb_soap嗎?
自己參考SANE backends範例寫個CM1015專用的SANE backends算了,
反正底層一樣呼叫hpmud,其他就自己解決了。

而且看到現在,感覺已經偏了,怎麼好像在研究SOAP的感覺(加油,魔王只剩SOAP DIME了),
我並沒有想要理解SOAP啊.........

bb_end_page:
目前瞭解,看起來就只有呼叫hpmud_channel_close()。

所以這裡描述就是:
  • bb_end_page
    • hpmud_channel_close()
結束。

bb_end_scan:
動作流程如下:
  • bb_end_scan
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_close()
bb_end_scan解析:
同前面,一樣把它溝通內容列出,共4個write、4個read。

write:
cat hpmud_write_channel_7.dump
POST / HTTP/1.1
Host: http:0
User-Agent: gSOAP/2.7
Content-Type: application/soap+xml; charset=utf-8
Transfer-Encoding: chunked
Connection: close



cat hpmud_write_channel_8.dump
1b9
前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

cat hpmud_write_channel_9.dump
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:CancelJob><ScanIdentifier>scanjob 10153</ScanIdentifier></wscn:CancelJob></SOAP-ENV:Body></SOAP-ENV:Envelope>


cat hpmud_write_channel_10.dump
0

前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

read:
cat hpmud_read_channel_16.dump
HTTP/1.1 200 OK
Server: gSOAP/2.7
Content-Type: application/soap+xml; charset=utf-8
Transfer-Encoding: chunked
Connection: close



cat hpmud_read_channel_17.dump
1B7
前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

cat hpmud_read_channel_18.dump
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:CancelJobResponse><succeeded>false</succeeded></wscn:CancelJobResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>


cat hpmud_read_channel_19.dump
0

前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

write解析:
雖然從XML看得出來,明顯很單純,但我們一樣用瀏覽器來看看,如下:

這裡訊息很簡單,就只有CancelJob和ScanIdentifier。
裡面帶的參數,就是前面bb_start_scan裡面帶的scanjob。

所以這裡合理的懷疑,
前面bb_start_scan,除了送出Scan參數外,
會對事務機發出一個掃描工作的request。

當掃描工作結束時,也就是這裡bb_end_scan,
會對事務機發出取消掃描工作的request,
通知事務機,掃描工作已結束或已完成,
事務機應該會在內部把這項掃描工作相關的資料結構刪除。

read解析:
同樣用瀏覽器看看,如下:

這裡可以看到,回傳的參數也很簡單,就只有successed。

這裡的false我不確定是固定回傳false,
還是因為我是測試,所以沒有成功取消。

HPLIP bb-soap解析 - 3 - bb_start_scan - 上集

前言:
接續前篇,通過整個flow的拆解和bb_open內容的解析,
我們大致可以知道CM1015的溝通過程。

針對bb_start_scan,我考慮分成上、下2集,
上集可以先po,下集我不確定能不能po得成,因為目前還沒有參透。

因此,po的順序會是:
  • bb_start_scan上集 
  • bb_end_page 
  • bb_end_scan
最後再回頭看能不能po得出bb_start_scan。

bb_start_scan和hpmud動作流程:
  • bb_open
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_close()
  • bb_start_scan
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
  • bb_get_parameters
  • bb_get_parameters
  • bb_end_page
    • hpmud_channel_close()
  • bb_end_scan
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_close()
      • bb_close
      • bb_unload
      這裡我們注意到紅字標示的部份,也就是hpmud_channel_open/hpmud_channel_close的部份。

      我們會發現,bb_start_scan和其他幾個bb function的特異之處,
      bb_start_scan只有做hpmud_channel的open,但並沒有close,
      它實際的close動作是到bb_end_page才做。

      bb_start_scan溝通內容:
      照例,我們打印出bb_start_scan的溝通內容,bb_start_scan有4個write,和一堆read,
      上集我們只印出前面3個,
      後面的我還看不懂,而且內容大部分應該是掃描出的圖片內容,
      我就不列了。

      內容:
      write:
      cat hpmud_write_channel_3.dump
      POST / HTTP/1.1
      Host: http:0
      User-Agent: gSOAP/2.7
      Content-Type: application/soap+xml; charset=utf-8
      Transfer-Encoding: chunked
      Connection: close
      
      

      cat hpmud_write_channel_4.dump
      54f

      cat hpmud_write_channel_5.dump
      <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:InitiateScanRequest><ScanTicket><JobDescription><JobName>scanjob 10153</JobName><JobOriginatingUsername>Eric Cartman</JobOriginatingUsername></JobDescription><DocumentParameters><Format>scanJFIF</Format><InputSource>scanPlaten</InputSource><ContentType>scanAuto</ContentType><DocumentCompression><CompressionType>scanJPEG</CompressionType><JPEGQualityFactor>10</JPEGQualityFactor></DocumentCompression><Contrast>0</Contrast><Brightness>0</Brightness><ScanRegion><ScanRegionXOffset>0</ScanRegionXOffset><ScanRegionYOffset>0</ScanRegionYOffset><ScanRegionWidth>8499</ScanRegionWidth><ScanRegionHeight>11689</ScanRegionHeight></ScanRegion><ColorProcessing>scanGrayScale8</ColorProcessing><Resolution><ResolutionWidth>75</ResolutionWidth><ResolutionHeight>75</ResolutionHeight></Resolution><PadImage>true</PadImage><GammaCorrection>2.2</GammaCorrection></DocumentParameters></ScanTicket><DestinationID>PC</DestinationID><ScanIdentifier>linux-rocks</ScanIdentifier></wscn:InitiateScanRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

      cat hpmud_write_channel_6.dump
      0
      
      

      read:
      cat hpmud_read_channel_5.dump
      HTTP/1.1 200 OK
      Server: gSOAP/2.7
      Content-Type: application/dime
      Transfer-Encoding: chunked
      Connection: close
      
      

      cat hpmud_read_channel_6.dump
      800
      1.1 200 OK
      Server: gSOAP/2.7
      Content-Type: application/dime
      Transfer-Encoding: chunked
      Connection: close
      
      

      cat hpmud_read_channel_7.dump
       )▒cid:id0http://schemas.xmlsoap.org/soap/envelope/
      
      linux-rocksid1image/jpeg▒▒▒▒JFIF▒▒C
       $.' ",#(7),01444'9=82<.342▒▒
                                  l}▒▒
      
      ...............
      
      HEX表示:

      write解析:
      送給事務機的XML內容訊息很多,原則上就是提供事務機掃描的參數,
      但這邊有幾個訊息是重點,而且有藏彩蛋,哈.....作者還真是幽默啊......

      一堆不好看,我們把這串另存成XML,用瀏覽器打開看看,如下:

      這裡注意到,裡面除了掃描資訊外,有幾個重點:
      • JobName
      • JobOriginatingUsername
      • DestinationID
      • ScanIdentifier
      這幾條看起來並不像是掃描參數,其中JobName是關鍵,會在後面其他function使用到。

      作者的幽默感來自於JobOriginatingUsername的名稱Eric Cartman,這是誰?
      是作者本人嗎?還是描述什麼?Google看看......
      Google找到他......

      read解析:
      read的內容我還沒搞懂,把目前知道的部份po出來。

      我們從SOAP的HTTP Header理解,從Content-Type: application/dime來看,
      我們可以知道這是一個application/dime類型的資料,
      Google後得知,SOAP有2種夾帶附件的資料格式:
      • MIME
      • DIME
      這裡使用了SOAP DIME做為傳遞的資料格式。

      目前我對SOAP DIME還不清楚,還在解譯中,僅把我找到的參考資料列出,
      其他等解譯後,下集再寫。

      SOAP DIME參考:

      JPEG格式參考:
      http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format
      http://bbs.csdn.net/topics/190036200
      上述2個JPEG參考可以知道,JPEG Header的最開頭是
      FF D8 FF E0
      • FF D8
        • 表示圖片開頭
      • FF E0
        • 表示JPEG APP0的開頭

      HPLIP bb-soap解析 - 2 - bb_open

      前言:
      接續前篇,在前篇大致知道了整個CM1015掃描的flow,
      搭配AAA的印出的訊息, 我們可以知道bb_soap幾個function和hpmud的呼叫關聯。

      進一步搭配從hpmud_read和hpmud_write寫出的dump內容,
      我們可以知道它們溝通的訊息內容。

       這篇,前半段會簡單解析bb_soap和hpmud的動作,
      然後這篇重點會針對bb_open進行描述,
      原則上,bb_open動作知道了,我目前認為和CM1015的溝通,就大致清楚了。

      bb_soap和hpmud動作:
      由前一篇的幾個dump,加上bb_soap整個flow,拆解對照後,可以得到下面的動作流程:
      • bb_open
        • hpmud_channel_open()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_close()
      • bb_start_scan
        • hpmud_channel_open()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
          • 這裡看AAA訊息,中間有摻雜許多function動作,甚至bb_get_parmameters呼叫時,都還有read動作,目前相當懷疑下面的read是在額外的thread處理的
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
      • bb_get_parameters
      • bb_get_parameters
      • bb_end_page
        • hpmud_channel_close()
      • bb_end_scan
        • hpmud_channel_open()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_close()
          • bb_close
          • bb_unload
          由這段列出的流程中可以看出來,
          bb_open是第1個關卡,裡面包含了完整的open/write/read/close動作,
          下段開始,我們就進入本篇主題,將bb_open內容列出並解析。

          bb_open解析:
          前面我們得知,bb_open內包含了2個write,4個read,這邊我們按順序列出內容:
          write:
          cat hpmud_write_channel_1.dump
          POST / HTTP/1.1
          Host: http:0
          User-Agent: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          
          
          cat hpmud_write_channel_2.dump
          19E
          <?xml version="1.0" encoding="UTF-8"?>
          <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:GetScannerElements></wscn:GetScannerElements></SOAP-ENV:Body></SOAP-ENV:Envelope>
          0
          
          

          read:
          cat hpmud_read_channel_1.dump
          HTTP/1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          
          

          cat hpmud_read_channel_2.dump
          7CB
          1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          
          

          cat hpmud_read_channel_3.dump
          <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:ScanElements><ScannerConfiguration><DeviceSettings><FormatSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentFormat" SOAP-ENC:arraySize="3"><item>scanDIB</item><item>scanJFIF</item><item>scanMMRf</item></FormatSupported><CompressionSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eCompressionType" SOAP-ENC:arraySize="3"><item>scanNoCompression</item><item>scanJPEG</item><item>scanMMR</item></CompressionSupported><JPEGQualityFactorSupported>false</JPEGQualityFactorSupported><ContentSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentType" SOAP-ENC:arraySize="4"><item>scanAuto</item><item>scanText</item><item>scanMixed</item><item>scanPhoto</item></ContentSupported><DocumentSizeAutoDetectSupported>true</DocumentSizeAutoDetectSupported></DeviceSettings><Platen><ColorSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eColorEntryType" SOAP-ENC:arraySize="4"><item>scanBlackandWhite1</item><item>scanGrayScale8</item><item>scanRGB24</item><item>scanRGB48</item></ColorSupported><PlatenMinimumSize><DimensionsWidth>500</DimensionsWidth><DimensionsHeight>300</DimensionsHeight></PlatenMinimumSize><PlatenMaximumSize><DimensionsWidth>8500</DimensionsWidth><DimensionsHeight>11690</DimensionsHeight></PlatenMaximumSize><PlatenOpticalResolution><ResolutionWidth>1200</ResolutionWidth><ResolutionHeight>1200</ResolutionHeight></PlatenOpticalResolution></Platen></ScannerConfiguration><ScannerStatus><ScannerCurrentTime>0001-01-01T01:01:01Z</ScannerCurrentTime><ScannerState>scanIdle</ScannerState><ActiveCondition>scanNone</ActiveCondition></ScannerStatus></wscn:ScanElements></SOAP-ENV:Body></SOAP-ENV:Envelope>

          cat hpmud_read_channel_4.dump
          0
          
          ersion="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:ScanElements><ScannerConfiguration><DeviceSettings><FormatSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentFormat" SOAP-ENC:arraySize="3"><item>scanDIB</item><item>scanJFIF</item><item>scanMMRf</item></FormatSupported><CompressionSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eCompressionType" SOAP-ENC:arraySize="3"><item>scanNoCompression</item><item>scanJPEG</item><item>scanMMR</item></CompressionSupported><JPEGQualityFactorSupported>false</JPEGQualityFactorSupported><ContentSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentType" SOAP-ENC:arraySize="4"><item>scanAuto</item><item>scanText</item><item>scanMixed</item><item>scanPhoto</item></ContentSupported><DocumentSizeAutoDetectSupported>true</DocumentSizeAutoDetectSupported></DeviceSettings><Platen><ColorSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eColorEntryType" SOAP-ENC:arraySize="4"><item>scanBlackandWhite1</item><item>scanGrayScale8</item><item>scanRGB24</item><item>scanRGB48</item></ColorSupported><PlatenMinimumSize><DimensionsWidth>500</DimensionsWidth><DimensionsHeight>300</DimensionsHeight></PlatenMinimumSize><PlatenMaximumSize><DimensionsWidth>8500</DimensionsWidth><DimensionsHeight>11690</DimensionsHeight></PlatenMaximumSize><PlatenOpticalResolution><ResolutionWidth>1200</ResolutionWidth><ResolutionHeight>1200</ResolutionHeight></PlatenOpticalResolution></Platen></ScannerConfiguration><ScannerStatus><ScannerCurrentTime>0001-01-01T01:01:01Z</ScannerCurrentTime><ScannerState>scanIdle</ScannerState><ActiveCondition>scanNone</ActiveCondition></ScannerStatus></wscn:ScanElements></SOAP-ENV:Body></SOAP-ENV:Envelope>

          由上述可以知道下列資訊:

          • 傳送時
            • 傳送的是SOAP格式的HTTP + XML,中間會帶後續資料長度的神秘HEX數值
          • 接收時
            • 第1條是SOAP的HTTP
            • 第2條看起來,內容只有神秘HEX數值,其他應該只是buffer沒清除
            • 第3條是SOAP的XML,也就是實際事務機回應的內容
            • 第4條看起來,內容只是神秘HEX數值0,標示後面沒資料,同樣的,buffer沒清除

          內容我沒有細看,
          粗淺看起來,事務機回覆的內容應該是描述事務機的能力,和支援的項目、格式。

          傳送部份看起來只是制式化的訊息,應該是不用特別處理,
          要掃描時,固定按這個訊息送即可,應該不用特別處理。

          至於回覆的資料要不要parse,目前我還不清楚,可能要看SANE需不需要這些資訊。

          結論:
          bb_open看起來,應該就跟hello沒啥不同,
          大致就是跟事務機通知一下,取得事務機狀態,
          確定事務機目前可以準備掃描工作而已。

          傳遞的訊息雖然是XML,但應該都是制式化的,
          不用特別parse處理,應該都是千篇一律。

          總之,bb_open就是按上述訊息丟,大概確定收到訊息和上面差不多即可。

          2015年1月24日

          HPLIP bb-soap解析 - 1

          前言:
          接續前面2篇網樂通Scanner Server文章
          這篇開始,會將我針對HP Color LaserJet CM1015掃描功能的Close Code解析,
          因為目前尚未破解,所以這系列會不會有完結篇不確定,
          解析到哪,又剛好有空、有興趣,就po到哪。

          背景資訊:
          HP Color LaserJet CM1015這台HP事務機功能如下:
          • USB介面
          • 有彩色掃描功能
          • 有彩色列印功能
          • 是雷射列印
          這台事務機在Linux上,從HPLIP 2.8.10開始支援,Linux上提供
          • 黑白、彩色掃描
          • 黑白、彩色列印
          • 印表機狀態資訊
          相關資訊可以參考:
          HP Color LaserJet cm1015 Multifunction Printer

          而根據HPLIP 2.8.10的Release時間回推,這台應該是在2008年的款式,
          我的購買時間我已經忘了。

          HPLIP本身雖然是OpenSource的專案,但HP並沒有將全部的檔案都OpenSource,
          HPLIP在大部分機種上要求要安裝Driver Plugin,
          這個Driver Plugin提供了這些機種需要的Close Code Library,
          它們包括:
          • bb_marvell-x86_32.so
          • bb_marvell-x86_64.so
          • bb_soapht-x86_32.so
          • bb_soapht-x86_64.so
          • bb_soap-x86_32.so
          • bb_soap-x86_64.so
          • fax_marvell-x86_32.so
          • fax_marvell-x86_64.so
          • hbpl1-x86_32.so
          • hbpl1-x86_64.so
          • lj-x86_32.so
          • lj-x86_64.so
          以CM1015來說,CM1015需要bb_soap。

          從程式碼看起來,
          HP不同機種使用了不同的Protocol,不同Protocol使用不同的Close Code Library檔案,
          CM1015的Protocol看起來只是單純的SOAP,使用的是bb_soap。

          怎麼知道是用bb_soap?
          因為我在網樂通上手動把Driver Plugin放上去,執行scanimage後,
          在/var/log/syslog出現類似如下:
          scanimage: common/utils.c 188: unable to load library /usr/local/hplip/share/hplip/scan/plugins/bb_soap.so: /usr/local/hplip/share/hplip/scan/plugins/bb_soap.so: wrong ELF class: ELFCLASS32

          當然,這是示意訊息,原始錯誤訊息印象中是Segfault,但它的確標明了使用的library。

          因為HP只將Protocol Close,掃描的上層是SANE,下層是HPMUD + libusb,示意圖如下:
          所以透過修改程式,
          可以在HPMUD和sane-hpaio backend加上printf,
          就能知道它的呼叫flow,儘管它沒有Open,
          也能知道傳遞什麼給事務機,步驟是什麼。

          解析開始:
          建立環境:
          建個VM,USB map進去,按網樂通類似步驟把HPLIP、SANE、CUPS build出來。

          找程式起始點:
          首先先找hpaio backend的呼叫點,找到是在
          hplip-3.14.10/scan/sane/

          繼續找bb_soap的呼叫點,找到主要是
          hplip-3.14.10/scan/sane/soap.c

          再來找hpmud,找到是
          hplip-3.14.10/io/hpmud/

          主要應該是
          hplip-3.14.10/io/hpmud/hpmud.c

          至於hplip-3.14.10/io/mudext不用管它,看裡面有註明是給python用的library。

          查看程式,修改程式碼,加printf:
          看soap.c,看到
          • ps->bb_open = get_library_symbol(ps->bb_handle, "bb_open")
          • ps->bb_close = get_library_symbol(ps->bb_handle, "bb_close")
          • ps->bb_get_parameters = get_library_symbol(ps->bb_handle, "bb_get_parameters")
          • ps->bb_is_paper_in_adf = get_library_symbol(ps->bb_handle, "bb_is_paper_in_adf")
          • ps->bb_start_scan = get_library_symbol(ps->bb_handle, "bb_start_scan")
          • ps->bb_end_scan = get_library_symbol(ps->bb_handle, "bb_end_scan")
          • ps->bb_get_image_data = get_library_symbol(ps->bb_handle, "bb_get_image_data")
          • ps->bb_end_page = get_library_symbol(ps->bb_handle, "bb_end_page")
          非常好,它將bb_soap的所有function都列好了,不用辛苦找。
          接著在這些呼叫點前後加上printf,把原本的DBG改成printf。

          hpmud裡面也是,把DBG都改成printf,看到open、close、read、write,都加上printf。

          重新編譯後,執行
          scanimage > AAA

          看看AAA裡面有什麼,如下:
          [10153] hpmud_probe_devices() bus=3
          sane_hpaio_open(/usb/HP_Color_LaserJet_CM1015?serial=00CNF87DL012)
          io_mode = 1
          [10153,13449,0,0,0,0] hpmud_device_open() uri=hp:/usb/HP_Color_LaserJet_CM1015?serial=00CNF87DL012 iomode=1
          bb_open(session)
          [10153] hpmud_channel_open() dd=1 name=HP-SOAP-SCAN
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd380 size=154 sectime=45
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd458 size=426 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_close() dd=1 cd=19
          bb_open end
          sane_hpaio_control_option (option=mode action=auto value=na)
          sane_hpaio_control_option (option=resolution action=auto value=na)
          sane_hpaio_control_option (option=brightness action=auto value=na)
          sane_hpaio_control_option (option=contrast action=auto value=na)
          sane_hpaio_control_option (option=compression action=auto value=na)
          sane_hpaio_control_option (option=jpeg-quality action=auto value=na)
          sane_hpaio_control_option (option=tl-x action=auto value=na)
          sane_hpaio_control_option (option=tl-y action=auto value=na)
          sane_hpaio_control_option (option=br-x action=auto value=na)
          sane_hpaio_control_option (option=br-y action=auto value=na)
          sane_hpaio_get_option_descriptor(option=option-cnt)
          sane_hpaio_control_option (option=option-cnt action=get value=14)
          sane_hpaio_get_option_descriptor(option=option-cnt)
          sane_hpaio_control_option (option=option-cnt action=get value=14)
          sane_hpaio_get_option_descriptor(option=mode-group)
          sane_hpaio_get_option_descriptor(option=mode)
          sane_hpaio_get_option_descriptor(option=resolution)
          sane_hpaio_get_option_descriptor(option=advanced-group)
          sane_hpaio_get_option_descriptor(option=brightness)
          sane_hpaio_get_option_descriptor(option=contrast)
          sane_hpaio_get_option_descriptor(option=compression)
          sane_hpaio_get_option_descriptor(option=jpeg-quality)
          sane_hpaio_get_option_descriptor(option=geometry-group)
          sane_hpaio_get_option_descriptor(option=tl-x)
          sane_hpaio_get_option_descriptor(option=tl-y)
          sane_hpaio_get_option_descriptor(option=br-x)
          sane_hpaio_get_option_descriptor(option=br-y)
          sane_hpaio_control_option (option=br-x action=get value=14149222)
          sane_hpaio_control_option (option=tl-x action=get value=0)
          sane_hpaio_control_option (option=br-y action=get value=19459342)
          sane_hpaio_control_option (option=tl-y action=get value=0)
          sane_hpaio_control_option (option=tl-x action=get value=0)
          sane_hpaio_get_option_descriptor(option=br-x)
          sane_hpaio_control_option (option=br-x action=set value=14149222)
          sane_hpaio_control_option (option=tl-y action=get value=0)
          sane_hpaio_get_option_descriptor(option=br-y)
          sane_hpaio_control_option (option=br-y action=set value=19459342)
          sane_hpaio_start()
          bb_start_scan
          [10153] hpmud_channel_open() dd=1 name=HP-SOAP-SCAN
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd380 size=154 sectime=45
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5ca8f0 size=5 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5ca910 size=1359 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd8a9 size=7 sectime=1
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          bb_start_scan end
          bb_get_parameters
          bb_get_parameters end
          set traits iPixelsPerRow=632 iBitsPerPixel=8 lNumRows=876 iComponentsPerPixel=1
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=1024 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=2048 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=3072 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=4096 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=5120 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=6144 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=7168 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=8192 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=9216 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=10240 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=450 index=0 input=0xd68e10 inputAvail=450 inputUsed=450 inputNextPos=10690 output=(nil) outputAvail=0 outputThisPos=0
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=(nil) outputAvail=0 outputThisPos=0
          act traits iPixelsPerRow=637 iBitsPerPixel=1 lNumRows=876 iComponentsPerPixel=1
          bb_getparameters
          bb_getparameters end
          sane_hpaio_get_parameters(): format=0, last_frame=1, lines=876, depth=1, pixels_per_line=637, bytes_per_line=80
          P4
          # SANE data follows
          637 876
          sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=0
          -sane_hpaio_read() output=0xd7ba40 bytes_read=32768 maxLength=32768 status=0
          ▒       ▒sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=32768
          -sane_hpaio_read() output=0xd7ba40 bytes_read=32768 maxLength=32768 status=0
          ▒       ▒sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=65536
          -sane_hpaio_read() output=0xd7ba40 bytes_read=4544 maxLength=32768 status=0
          sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=70080
          bb_end_page
          [10153] hpmud_channel_close() dd=1 cd=19
          bb_end_page end
          -sane_hpaio_read() output=0xd7ba40 bytes_read=0 maxLength=32768 status=5
          sane_hpaio_cancel()
          bb_end_scan
          [10153] hpmud_channel_open() dd=1 name=HP-SOAP-SCAN
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd380 size=154 sectime=45
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5cb190 size=5 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5cb1b0 size=442 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd8a9 size=7 sectime=1
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_close() dd=1 cd=19
          bb_end_scan end
          sane_hpaio_close()
          bb_close
          close end bb_unload
          bb unload end
          [10153] hpmud_device_close() dd=1
          這整段一長串,會注意到:
          1. bb_soap function呼叫流程,如下:
          • bb_open
          • bb_start_scan
          • bb_get_parameters
          • bb_get_parameters
          • bb_end_page
          • bb_end_scan
          • bb_close
          • bb_unload
          2. 和USB的動作都使用下列這些function:
          • hpmud_channel_open
          • hpmud_channel_close
          • hpmud_channel_read
          • hpmud_channel_write
          查看hpmud傳輸內容:
          修改hpmud.c,在hpmud_channel_read和hpmud_channel_write裡面加上寫檔,
          讀取和寫入的資料統統寫到檔案中,我是如下:
          讀取部份:
          hpmud_read_channel_1.dump
          hpmud_read_channel_2.dump
          .....

          寫入部份:
          hpmud_write_channel_1.dump
          hpmud_write_channel_2.dump
          .....

          精彩的來了,我們看看它到底傳什麼給事務機,又從事務機收什麼回來?
          cat /tmp/hpmud_write_channel_1.dump
          POST / HTTP/1.1
          Host: http:0
          User-Agent: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          

          cat /tmp/hpmud_write_channel_2.dump
          19E
          
          <?xml version="1.0" encoding="UTF-8"?>
          <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:GetScannerElements></wscn:GetScannerElements></SOAP-ENV:Body></SOAP-ENV:Envelope>
          0
          

          cat /tmp/hpmud_read_channel_1.dump
          HTTP/1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          

          cat /tmp/hpmud_read_channel_2.dump
          7CB
          1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          

          dump出來的訊息好面熟,看起來很像是HTTP和XML啊.....
          Google soap,查到:
          SOAP Wiki

          原來SOAP是以HTTP + XML為核心的物件描述語言,
          而CM1015以SOAP做為溝通的通訊協定。

          這裡有個部份我一開始想不通,它每份資料的斷點在哪裡?為何會出現19E這樣的神秘字串?
          後來比對hpmud_read_channel和hpmud_write_channel的動作,搭配神秘數字0,
          終於搞清楚它神秘字串是表示後面還有多少字要傳送或接收,
          當這段資料後面沒東西時,就傳遞個0,表示後面沒資料,
          有資料時,神秘字串是後一筆資料的字串長度的HEX表示。

          以19E為例,19E表示:
          <?xml version="1.0" encoding="UTF-8"?>
          <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:GetScannerElements></wscn:GetScannerElements></SOAP-ENV:Body></SOAP-ENV:Envelope>
          
          這整段的資料長度。

          本篇先到此為止,後續再戰。

          2015年1月19日

          網樂通 - HPLIP、CUPS、SANE Scanner Server - HP Color LaserJet CM1015,功敗垂成

          前言:
          去年過年的目標,現在重新開始,但目前仍舊失敗,
          失敗原因在HPLIP部份程式碼沒有OpenSource。
          目前我還在努力,看有沒有辦法把沒有OpenSource的部份自己實做出來。

          功能目標:
          在網樂通上,透過USB連接HP Color LaserJet CM1015,
          達成掃描功能,並進一步做到掃描伺服器。
          也許會問,列印呢?列印都沒達成,做什麼掃描?
          事實上,透過p910nd,應該是能夠輕鬆做到列印,只是還沒實際印過而已。

          實做目標:
          在網樂通上實做出SANE + HPLIP,透過網樂通直接下指令掃描,
          或透過SANE Scanner Server,網路掃描。

          HPLIP、CUPS、SANE需求:

          事實上,HPLIP依賴CUPS和SANE,
          除非單純build HPIJS,否則CUPS是必要的(掃描功能也需要),
          如果要使用掃描功能,SANE是必要的。

          而CUPS、SANE、HPLIP這三者,都需要libusb,它們都使用libusb當作USB溝通的底層。
          libusb可以使用libusb1.0或libusb,我這邊使用libusb1.0。

          SANE還需要jpeg library,tiff library可以裝也可以不裝。
          相依關係如圖:


          實做平台:
          最終使用 網樂通Debian wheezy。

          我實際上sh4twbox、archlinux、debian這3個平台都嘗試移植,
          但sh4twbox、archlinux都遇到問題,導致移植失敗。

          網樂通移植平台限制:
          sh4twbox:
          sh4twbox是我原本最期望使用的平台,也是我花費最多心力的平台,
          同樣,最後功敗垂成。

          sh4twbox的本體實際上是STLinux,但因為原廠不再支援STLinux 2.3,
          會發現STLinux 2.4版的libc使用的是2.14版,
          但網樂通上的libc是2.10版,
          網樂通和開發環境的版本不合,會導致CrossCompiler編譯的程式,執行時可能會有問題。
          另外,STLinux 2.4 CrossCompiler環境,原廠並沒有把libtool和pkg-config的路徑問題做修正,
          因此裝在CrossCompiler環境的library,經常會link到host的x86 library,
          造成過程經常出現問題。

          最後我的解決方法:
          針對pkg-config和libtool問題,
          針對configure出錯時,直接修改configure,讓它指定到正確的路徑,
          同時使用CFLAGS、CPPFLAGS、CXXFLAGS、LIBS這些環境變數,
          強制指定正確library的路徑和正確include的路徑。

          針對libc版本不合的問題,
          我注意到ST Linux 2.4 CrossCompiler的路徑中,有提供static library,
          我強制將shared library( .so檔案)改名,讓程式和library編譯時強制使用靜態編譯,
          編譯出來後,在網樂通上執行看看,看有沒有link到shared library。

          這方式最終看起來,好像能動,但Debug異常麻煩,不確定問題在哪。

          archlinux:
          我按照網路上的教學安裝gcc,網路上說需要另外下載gcc,覆蓋掉archlinux套件安裝的版本,
          我照著做,但在編譯時,會出現錯誤,上網Google結果都是要你重新安裝gcc,
          這我懷疑網上版的gcc和系統的部份library可能不合,後續放棄沒繼續了。

          Debian:
          不愧是Debian,套件夠完整,但系統也實在是肥很多。
          光下指令,就能感受到反應速度明顯比archlinux、sh4twbox慢,
          很可能預設啟動的service太多造成的。

          但Debian最大的好處是,套件庫齊全,針對CUPS、HPLIP、SANE的編譯,
          相依的library幾乎都直接有套件裝,不需要另外自己編譯,
          就library編譯部份省去不少功夫,但網樂通本地編譯,
          真的是等.....等......等......等......等.....

          過程:
          Debian上需要另外編譯CUPS、SANE、HPLIP的主要原因是:
          1. 這幾個套件在Debian上沒有提供套件
          2. 這幾個程式的相依套件庫太多,很多相依套件在sh4平台上沒有提供,這尤其發生在HPLIP上

          因此,我編譯時,只使用幾個功能,相依套件盡量少,最後使用下面這些:
          • libjpeg-dev
          • libtiff-dev
          • libusb-dev
          • libusb-1.0-0-dev 
          • libtool
          • pkg-config
          • gcc
          • g++
          編譯按順序如下:
          SANE:
          1.
          下載sane-backends Source Code並解壓縮,這邊我使用sane-backends-1.0.24版。

          2.
          ./configure --prefix=/usr/local/sane-backends --enable-libusb_1_0

          3.
          make

          4.
          make install

          CUPS:
          1.
          下載CUPS Soruce Code並解壓縮,這邊我使用CUPS-1.7.5版。

          2.
          ./configure --prefix=/usr/local/cups --disable-gssapi --without-perl --without-java --disable-gnutls --enable-libusb --disable-dbus --disable-openssl --enable-libusb --disable-dbus --disable-pam --disable-avahi --with-python=no

          3.
          make

          4.
          make install

          HPLIP:
          1.
          下載hplip Source Code並解壓縮,這邊我使用hplip-3.14.10版。

          2.
          設定環境變數
          export CPPFLAGS="-I/usr/local/sane-backends/include -I/usr/local/cups/include"
          export LIBS="-L/usr/local/sane-backends/lib -lsane -L/usr/local/cups/lib -lcups"


          3.

          將SANE、CUPS Library加入系統參考路徑中

          修改/etc/ld.so.conf.d/libc.conf,修改如下:

          # libc default configuration /usr/local/lib /usr/local/cups/lib /usr/local/sane-backends/lib

          執行ldconfig

          4.
          ./configure --prefix=/usr/local/hplip --enable-lite-build --disable-doc-build --disable-gui-build --disable-fax-build --disable-dbus-build --disable-cups11-build --disable-qt4 --disable-network-build

          5.
          make

          6.
          make install

          上述HPLIP編譯,會編譯HPLIP的列印和掃描功能,其他功能全部不裝。

          7.
          複製HPLIP的hpaio檔案到sane-backends中,如下:
          cp -v /usr/local/hplip/lib/sane/libsane-hpaio.* /usr/local/sane-backends/lib/sane/

          8.
          將hpaio加入到sane-backends的搜尋檔案中
          編輯/usr/local/sane-backends/etc/sane.d/dll.conf
          最後面加入
          hpaio

          9.
          複製HPLIP的model資訊
          從HPLIP的Source Code目錄中複製data到/usr/local/hplip/share/hplip/data
          類似如下:
          cp -v -R /usr/local/printer_system/hplip-3.14.10/data /usr/local/hplip/share/hplip/data

          10.
          將HPLIP的library路徑加入到系統參考路徑中,如下修改:
          修改/etc/ld.so.conf.d/libc.conf,修改如下:
          # libc default configuration
          /usr/local/lib
          /usr/local/cups/lib
          /usr/local/sane-backends/lib
          /usr/local/hplip/lib

          執行ldconfig

          到此安裝完成,接著要Debug。

          除錯方法:
          針對SANE,可以如下除錯:
          1.
          設定環境變數,如下:
          export SANE_DEBUG_DLL="255"

          2.
          執行/usr/local/sane-backends/bin/sane-find-scanner
          如果找到Scanner,表示SANE這關過了,
          如果沒找到,請直接跳到第5步驟,看syslog。

          3.
          執行/usr/local/sane-backends/bin/scanimage -L
          如果找到Scanner,表示HPLIP第1關過了,
          如果沒找到,請直接跳到第5步驟,看syslog。

          4.
          執行/usr/local/sane-backends/bin/scanimage > /tmp/image.img,
          如果/tmp/image.img有檔案產生,表示HPLIP一切正常,
          如果有問題,會顯示錯誤。

          5.
          過程中有錯誤,可以看/var/log/syslog,裡面會列出錯誤原因。

          功敗垂成:
          我家的HP事務機是HP Color LaserJet CM1015,參考:

          它提到這段話:
          Driver Plugin Information:
          This printer REQUIRES a downloadable driver plug-in. Use hp-setup to install the printer, and to download and install the plug-in. In general, required driver plugins are required for printing support. Driver plug-ins are released under a proprietary (non-open) license and are not part of the HPLIP tarball release.

          這台事務機的Linux Driver需要HP的Driver Plugin,
          而Driver Plugin我也手動安裝了,
          但關鍵問題是,Driver Plugin裡面包裹了4個Close Code Library,
          這4個Close Code Library並非全部都需要,這跟HP印表機、掃描器、事務機型號相關,
          更明確的說,這4個是4個不同的Protocol需要的library,
          以我的CM1015而言,CM1015需要的是bb_soap這個library。

          因為這4個library只提供x86 32bits和64bits版本,
          因此無法使用在網樂通上,也無法使用在ARM平台上,
          相關討論參考:

          展望:
          HP Color LaserJet CM1015是舊式的HP事務機,
          這表示它的protocol相對單純,
          目前我透過在HPLIP Source Code加上printf的方式(在libsane-hpaio和hpmud),
          在x86機器上呼叫scanimage後,查看呼叫過程,
          試圖拆解bb_soap內的功能,
          事實上從libsane-hpaio的程式碼看起來,
          bb_soap內其實只有下列function,分別是:
          • bb_open()
          • bb_close()
          • bb_get_parameters()
          • bb_is_paper_in_adf()
          • bb_start_scan()
          • bb_end_scan()
          • bb_get_image_data()
          • bb_end_page()
          我目前應該已經解開bb_open()、bb_close()、bb_start_scan(),
          有成功看到掃描器動作,
          但我目前不清楚收到的資料哪些部份才是圖像,
          圖像和後續bb_get_image_data()、bb_end_scan()、bb_end_page()的行為還不清楚,
          我相信,
          如果我能成功破譯這些function動作,
          修改HPLIP Source Code後,就能讓網樂通成為掃描列印伺服器。

          參考資料:

          2015年1月11日

          Acer Chromebook 13 Ubuntu (Chrubuntu)

          前言:
          Google提供了我們Linux Geek一個好玩具。

          Acer在去年底推出Acer Chromebook 13這台Chromebook,
          我看了規格後覺得,這台非常適合Linux玩家,未來不知道,
          但過去要找到這樣的玩具,還台灣廠商做的,很少很少(根本是沒有啦.....)

          Acer Chromebook 13我是透過網拍買的二手機(我是12月中旬買的),
          但因為距離上市日期不長,加上它的特性,我相信機器都還很乾淨,
          要被操到硬體問題一堆,難度很高,
          在這裡要感謝賣家,用不錯的價格提供了一台好玩具。

          規格:
          Acer Chromebook 13的規格如下:
          • CPU:ARM Cortex-A15 4核心 (Nvidia Tegra K1)
          • Video:Nvidia Kepler架構192核心
          • LCD:13.3吋LED背光LCD (1366x768)
          • RAM:4GB DDR3 (不可擴充)
          • Storage:32GB eMMC
          • Webcam:前置Webcam (1280x720)
          • WiFi:802.11ac
          • Bluetooth:Bluetooth 4.0
          • Card Reader:SD-Card
          • Battery:3220 mAh
          看到第1條相信就傻了,再看第2條,更傻。
          這台Notebook,使用的是ARM處理器,而且是Nvidia出的ARM處理器,所以內含Nvidia顯示。

          這台機器非常有趣,它的真身其實是:
          Tegra-K1
          原價屋NVIDIA Jetson TK1開箱

          它是Nvidia針對行動平台出的ARM處理器,
          除了Acer Chromebook 13外,還使用在下面幾個產品上:
          此外,Nvidia提供的車用電腦開發平台,也是使用這塊Nvidia Tegra K1。


          機器問題點:
          問題1:無法安裝Windows
          Acer Chromebook 13最大的問題,正是它的特色所在,
          它使用的是Nvidia ARM處理器,因此無法在上面安裝Windows,
          這對於大部分玩家而言,就會是個大問題,
          無法安裝Windows,表示無法隨心所欲的安裝程式、系統。

          問題2:ChromeOS有夠難用
          ChromeOS的主要問題是,它全部功能都要透過網路,
          你要寫Word、Excel、PowerPoint:Google Document
          你要記事本:Google Keep
          你要儲存檔案:Google Drive
          你要看影片聽音樂:一個簡易的播放器,並整合Google Drive

          那如果現在沒有網路呢?
          你要寫Word、Excel、PowerPoint:.........
          你要記事本:..........
          你要看影片聽音樂:..........

          那不用說了,這根本就是垃圾,沒有使用者會買單的。



          當上述2個問題同時存在,你買了一台Chromebook,
          只能使用Google線上服務,離線後通通不能用,
          又不准你安裝其他作業系統,
          請問你下個動作是什麼?

          我猜:
          1. 退貨
          2. 網拍賣掉
          3. 丟角落堆灰塵

          ChromeOS的設計有其特色,但目前設計有瑕疵,實用性很糟糕,
          關於它的設計理念,我放在最下面附註。

          Linux Geek禮物:
          雖然機器有上述2個怪問題,但對於Linux Geek來說,這些問題都不是問題。

          Chromebook有2個特別計畫:
          • chrubuntu
          • crouton
          這2個計畫都能讓Chromebook不再用ChromeOS,而改用Ubuntu或其他Linux distribution。

          這2個的區別是:
          • chrubuntu:是「安裝」一個獨立的Ubuntu,開機就直接進入Ubuntu
          • crouton:是「放置」一個Ubuntu,由ChromeOS切換進Ubuntu桌面環境
          2個我都使用過了,crouton不好用,
          而且在Acer Chromebook 13上,crouton無法使用顯示晶片硬體能力,
          我自己是沒有嘗試過,國外網友的意思是,
          Nvidia K1 X11 Driver只能被載入1次,重複載入時,第2次載入無法使用硬體能力。

          目前我是使用chrubuntu的方式,系統運作相當不錯。

          Acer Chromebook 13 Linux軟體(含作業系統)支援情況:
          針對Linux軟體支援情況,我們概括簡單的按下面分類:
          • 硬體驅動與Linux Kernel
          • Linux軟體、Library與ARM

          硬體驅動與Linux Kernel:
          Acer Chromebook 13出廠就是Linux,因此內部的硬體沒有Linux驅動的問題。
          這非常難得,大部分Notebook要裝Linux,都會遇到很多驅動程式不支援或支援不好的情況,
          但在Chromebook上,不會有這樣的問題。

          額外驅動程式,
          Google有提供各Chromebook的Kernel SourceCode,額外裝置的Kernel Module SourceCode只要支援ARM,就可以編譯出Kernel Module。

          這點Google做得相當好,它針對所有Chromebook型號,有提供一整棵Kernel SourceCode Tree,
          我們可以直接根據Chromebook型號,下載到相對應的Kernel SourceCode,也有提供目前使用的config(ChromeOS預載Kernel,直接有/proc/config.gz),可以自己修改Kernel,或編譯Module。

          因為它沒有RJ-45有線網路,我另外插一張USB3.0 Gigabit網路卡,
          驅動程式直接有module可以使用,連build都不用。
          哪一張?
          USB3.0 gigabit網路卡晶片大概只有1、2家,可以直接用的是Axis的晶片,
          很神奇,Axis本業是IP Camera,但竟然業外搞了一顆少見的USB3.0 gigabit chip。

          Linux軟體、Library與ARM:
          目前Ubuntu ARM(當然應該也包括Debian ARM)的套件完整度相當高,
          除了專門針對x86的軟體(例如:wine、VM)沒有之外,
          目前使用上,還沒遇到沒提供的OpenSource軟體或Library,
          哪些叫做有提供的?
          Java、FlashPlayer(Google包在Chromebook內)、GNOME、MPlayer、VLC、Firefox、Chromium、Qt Library、GTK+ Library、python...等,常見的軟體、Library都支援。

          到目前,只遇過一套程式可以裝,但執行會Crash,是畫3D的blender。

          所以使用上幾乎沒遇到問題,目前唯一的問題是,
          它的硬解Nvidia是用OpenMAX,提供的是GStreamer模組,
          MPlayer、VLC不支援OpenMAX,目前還只能ARM軟解。

          但這台ARM四核心很強大,除了H.264不行外,MPEG4以下等級,ARM軟解都直接ok。

          所以結論是,這台Chromebook 13,改用Ubuntu(Chrubuntu)後,整個頭好壯狀,考試都得100分。

          特色與優勢:
          1. 非常省電 (除動態時脈調整外,還動態開啟關閉CPU核心)
          這台是ARM系統,使用起來真的是很省電,
          Nvidia對Tegra K1的支援相當不錯,
          它因為是專門用在手機、平板的行動平台,對於省電有特殊設計。

          根據Tegra-K1描述,
          「理論上」它應該是NVIDIA 4-Plus-1 Quad-Core ARM Cortex-A15,
          這裡指的NVIDIA 4-Plus-1是說,
          「理論上」它應該有2顆ARM,
          1顆是4核心高階高時脈ARM,另一顆是單核心低時脈ARM,稱為LP :p,
          「理論上」它應該可以在閒置時,關閉4核心高階ARM,切換成使用LP ARM。

          「實務上」我找不到文獻說的參數來切換CPU,沒辦法很屌的做到切換成LP ARM,
          原因我有3個猜測:
          1. 我猜Google或Acer測試時發現不穩,把這功能關閉
          2. 這款SoC是閹割版,沒有額外這顆LP    ARM
          3. 工程師研發時,沒注意到這功能,沒開

          但除了這點有點可惜外,這台Chromebook的ARM直接build-in省電module,
          它除了一般PC動態時脈調整外,它可以動態的開啟、關閉CPU核心,
          當CPU工作量低時,就會先關閉1個核心,還是很低就關第2個核心,
          陸續關到剩下單核心。
          當CPU工作量增加時,時脈先拉高,然後開第2個核心,
          還是很高,開第3個核心,最終4個全開。

          開/關的切換過程完全不會有感覺,不會頓也沒遇過程式因為切換發生問題。

          2. 強大顯示運算
          買小筆電,看高解析度影片真的是慘,
          「號稱」可以硬解1080p影片,
          實際情況是,高bitrate影片就是解不動。

          這台是Nvidia血統的SoC,不用說,顯示晶片超強,
          Nvidia主打的特點就是超強繪圖運算,
          Tegra-K1的介紹中描述,它的應用環境包括:
          • 車用電腦中的環境辨識 (包括自動煞車的車前障礙物辨識、循跡系統的標線偵測...等)
          • 機器人的機器視覺 (障礙物辨識、物件辨識)
          所以這台有CUDA,可以直接用這台開發CUDA程式做顯示卡運算,
          雖然不知道意義在哪........

          播放影片部份,如果MPlayer、VLC能支援OpenMAX(正在研究中),
          那就可以丟掉爛爛的播放器,直接用MPlayer、VLC順暢播放H.264影片。

          3. 高CP值
          這台就算是原價,價格也相當實惠。
          客官啊.......
          它的雙胞胎兄弟NVIDIA Jetson TK1原價屋目前特價一塊還要NT 6090,
          你買這台NB,Acer附上13.3吋LCD、3220mAh電池、802.11ac WiFi、藍芽、32GB eMMC,
          只多賣你不到NT 4000,這樣的商品和價格,去哪找啊。

          怎麼改機成Ubuntu (Chrubuntu):
          我完全瞭解,介紹了半天,卻不提供安裝方式,根本是炫耀文,擺明找打。

          我還沒完全把Chrubuntu的script修改完,
          沒辦法提供出簡單、完整的安裝方式出來,
          不過,這裡我先把參考資料,目前建好的檔案放出來,
          高手高手高高手先自己試試看吧!

          參考資料:
          ChrUbuntu on Acer Chromebook 13

          上述參考資料的位址是最關鍵的,裡面開版大大實際上已經把7成的工作完成了,
          他做了下列事情:
          1. Ubuntu放上Acer Chromebook 13
          2. 整合了Nvidia在Linux For Tegra R19提供的Library
          3. 把Google改過針對Acer Chromebook 13的FlashPlayer移入Ubuntu
          4. 放上支援硬解的播放器(可能也是從Google的ChromeOS搬出來的)
          5. 將ChromeOS內的Kernel和modules複製到Ubuntu中

          其他網友在版上補充:
          1. Ubuntu NetworkManager在WiFi運作不正常的修正
          2. 音量快速鍵設定
          3. 開機後預設關閉藍芽
          4. Ubuntu 14.10無法順利安裝和使用,需使用Ubuntu 14.04

          自己安裝心得:
          我自己實際安裝,第1次安裝滿辛苦的,因為它下載網站設到歐洲,很慢.......
          過程失敗,就要重新開機,整個script重跑......很久.....
          所以最後script還自己邊try邊改......直到安裝成功......
          再之後,直接把安裝好,ok得版本tar起來,直接tar解開......

          另外,我自己修正包括:
          1. 修正按Power睡眠後起不來
          2. 除Xfce4外,安裝GNOME Fallback
          3. 輸入法加入新酷音輸入法
          4. 除音量快速鍵外,加入顯示器亮度快速鍵 (針對GNOME設定,Xfce4我不會設自定義快速鍵)
          5. 直接安裝好修正過的NetworkManager
          6. Nvidia的Linux For Tegra(L4T)改用R21.2版 (R21.2版支援CUDA 6.5,R19只支援到CUDA 6.0)
          7. 修正切換耳機沒聲音
          8. 加入CIFS和NFS的modules
          9. 開機後直接設定啟用動態開啟/關閉CPU核心的能力
          10. 安裝、設定思源黑體(Noto Sans)中文字型
          11. 開機後,顯示器亮度設為50%(預設是最亮)
          12. 安裝好Java、Firefox、Chromium、LibreOffice、MPlayer、VLC、aptitude

          我直接將改過得整個系統打包成tar檔案,
          省去chrubuntu script上網下載一堆套件安裝成系統的時間,
          高手高手高高手只需要:
          Step 1. 按chrubuntu教學,將Acer Chromebook 13設成Develop Mode
          Step 2.ChrUbuntu on Acer Chromebook 13執行chrubuntu.sh,變更Partition Size並Format成ext4
          Step 3. 將我改過的系統tar檔傳上去(我自己是用wget放到home目錄),解開到chrubuntu Partition
          Step 4. ChrUbuntu on Acer Chromebook 13,切換開機載入系統的Partition

          打完收工

          預設的帳號密碼和原來chrubuntu一樣:
          帳號:user
          密碼:user

          root預設禁用無法登入,使用sudo su變更後再改密碼。

          檔案壓縮後有1.35GB目前我放在MEGA上,
          未來歡迎幫我分流,或提供給我空間放置,連結如下:
          xubuntu-desktop_lazchrubuntu_l4tr21.tar.bz2

          下一篇,我希望可以修改完針對這個檔案安裝的chrubuntu.sh,
          再把完整步驟寫出來。

          目前使用上尚待解決的問題:
          1. MPlayer、VLC OpenMAX移植和硬解(如果用gstreamer base的播放器,如:totem,可以直接硬解)
          2. 睡眠後可能是顯示晶片沒停止很耗電,我電腦睡眠後丟著,白天上班晚上回來電池竟然沒電了
          3. 闔上螢幕不會關機;但睡眠後,闔上螢幕反而會開機
          4. GNOME環境下,System tray的電池開機後不會顯示;點設定->電源叫出後,睡眠->醒來後又會消失
          5. 睡眠醒來時,畫面會閃3下
          6. Firefox支援Java Plugin不支援FlashPlayer (這是個大哉問,跟Firefox要支援Chrome Plugin格式有關)
          7. Chromium支援FlashPlayer不支援Java Plugin (這是個大哉問,跟Java Plugin格式有關)
          8. 變更alsamixer設定後,切換到耳機模式,耳機有聲音喇叭沒聲音(正常);但在喇叭模式,耳機和喇叭都有聲音(不正常)
          9. 鍵盤沒有Del,同位置是電源,經常按錯啊 (這問題是來鬧的嗎....)
          10. 極少數時候,睡眠醒來後,執行中程式會Crash

          目前注意到大部分問題都發生在睡眠或睡眠醒來,
          我十分懷疑問題點在Systemd和UPower,
          事實上我發現到,Ubuntu預設睡醒的行為,都是針對x86或intel的動作,
          這台是Nvidia ARM,相關的動作都沒有或可能不完全,
          但目前我對Systemd和UPower都不算熟,chubuntu又算是改機成品,
          沒有正常的Ubuntu 14.04對照,不確定正確動作流程。

          題外話之ChromeOS設計理念:
          Google的Android在手機上異常成功的關鍵之一,就是捨棄了傳統的手機平台設計,
          傳統手機平台,都是一般作業系統搭配一個特殊的環境和特殊的SDK,
          像是OpenMoko
          在那個年代,我還在用PocketPC,最方便開發的系統是WinCE,使用VisualC++ Embedded。

          你要開發者在開發App前,要先經過一個複雜的「儀式」,
          才能把開發環境建置出來,環境內的桌面系統可能是Qt Library、GTK+ Library,
          又因為是手機平台,SDK還不大一樣,這開發者怎麼買單?

          Google的創舉在於,你不需要那個複雜的「儀式」,
          你也不需要學習離譜的SDK,你只要會「Java」,而且注意,
          不是Sun設計得莫名其妙的JavaME,而是直接用JavaSE就能開發,
          只要最後經過一道「詭異程序」,就能把Java程式放在Android上執行。
          所以就成功了...........

          Google的作法是,
          它把手機底層全部用一個Google的JavaVM包裹(JavaVM的設計公司是被Google買斷的),
          開發者不需要知道底層在幹嘛,只需要Java程式這個JavaVM能看懂,就能執行,
          那個「詭異程序」,就是負責將一般的Java程式,
          轉換成這個小型化JavaVM能看懂的格式,附帶包入安裝資訊...等。
          Google這作法當時,Java已經是熱門語言,程式開發者多,
          直接用現成語言和現成SDK就能開發,
          加上Google的名號,和當時hTC獨家的硬體工藝,使用者和開發者就買單了。

          事實上,當時Google還是擔心和其他同質平台遇到一樣的問題,
          因此發表前還搞了個Android前100大創意App徵選,
          除了搞聲勢外,就是要讓開發者能認識、熟悉這個平台的開發環境和模式。

          Google聽到有人在PC上,用「瀏覽器」當核心開發OS,
          手法和它在Android上一樣,差別是,
          一個用JavaVM,一個用瀏覽器的WebKit + JavaScript解譯器
          (瀏覽器在現代,幾乎可以視為一種Html + JavaScript語言的VM),
          直接就想複製這樣的模式到PC,要把Windows幹掉,這就是ChromeOS。

          ChromeOS的設計理念不錯,也很特別,
          但它的設計,只整合了網路服務,沒有整合本機程式,
          這讓整個ChromeOS變得失敗。

          我描述個對比,你在Android手機上操作,
          會因為是網路手機,所以沒辦法讀取手機內的影片、聲音、聯絡人、簡訊嗎?
          這當然不會發生吧.......

          但在ChromeOS上,竟然是搞成這樣,這真的是失敗設計,
          你要同一個架構這麼搞,你可以寫個獨立的Local WebServer,
          所有本機相關的操作,都透過Local WebServer呼叫執行。

          更簡單的作法,你直接在架構上開洞,在ChromeOS的SDK上開個API,
          能直接開啟本機程式,同樣可以引入檔案總管、小畫家、MPlayer、VLC...等,
          就不會搞成現在這樣,有新意但不好用。

          2015年1月10日

          HPLIP、SANE、CUPS、p910nd

          前言:
          去年過年前後,打算用網樂通做個列印、掃描伺服器,最後失敗了,
          一轉眼一年過了,
          最近又打算起死回生,再來一次。
          這次不鐵齒,看看OpenWRT上作法後,瞭解HPLIP、CUPS、p910nd後再開工,
          於是就打算把這幾樣寫成心得。

          介紹:
          • HPLIP是HP針對HP掃描器、印表機提供的Linux OpenSource驅動程式組合包。
          • SANE是Linux上的掃描器的軟體,裡面包含了網路掃描、掃描的前端軟體介面、掃描器驅動程式。
          • CUPS、p910nd都是Linux上的列印伺服器,p910nd是non-spooling的列印伺服器,CUPS則是spooling伺服器。
          簡單介紹結束,
          接著先針對CUPS和p910nd描述其架構,
          再介紹SANE架構,
          最後描述HPLIP和它們間的關係。

          p910nd與CUPS區別和兩者架構:

          p910nd:
          參考:
          [Oleg/Lly/CDMA@wifi] p910nd 列印伺服器(無spool)

          從參考的作者文中可以知道,
          p910nd的安裝,主要2個步驟:
          1. 確定Linux Kernel內USB Printer有支援
          2. p910nd daemon有啟動,並指定Port、USB Printer的Device File
          步驟完成,p910nd就會動了,而且p910nd需求極小,
          幾乎沒有相依太多library就能動作。

          再看看下面這個參考:
          DD-WRT Printer Sharing

          裡面描述了p910nd安裝外,也描述了Client端的安裝,
          包括CUPS、Linux、Windows、MacOSX的安裝介紹。

          簡單白話的說,
          p910nd本身只是USB<->Socket的轉譯器,
          它不負責印表機溝通,從Socket來的資料直接轉入USB當中,
          因此所有印表機的溝通,列印資料的轉譯,都要由Client端負責,
          印表機工作的排程,則要由印表機自己負責。

          因此p910nd優點是library相依性低,也不需要複雜的額外工作,
          至於Client端,
          Windows直接有原廠的驅動程式,
          Linux直接有CUPS搭配HPLIP就能達成,
          MacOSX看起來也是有驅動程式,這部份我不熟。

          CUPS:
          直接看系統方塊圖(wiki):

          CUPS是一整套完整的列印伺服器程式,
          裡面包含了使用者管理、列印語言轉譯、列印Queue、網路列印...等多個功能。

          我們單從CUPS的系統方塊圖來看,
          它前面提供了各種檔案格式的轉譯器,轉譯成PostScript,
          中間能將PostScript轉譯成各種列印語言,像是PCL...等,
          後面CUPS backend又能串接包括本機的USB、SerialPort...等,網路的IPP、網路芳鄰、AppleTalk...等網路介面。

          因此可以知道它是非常龐大的列印系統,
          從前端應用程式的檔案開始,就一路透過它層層處理,最後一樣透過它送到印表機上。

          優點當然是系統功能完整,但缺點就是相依的library多,
          程式的設定項目多比較複雜,
          在小型系統上就比較不方便移植,
          因此比較早期的OpenWRT、DD-WRT都只支援p910nd,
          較新的版本則已經有提供cups,
          自行移植則會遇到比較多的編譯問題,我自己最後編譯出來,執行後,網頁點幾下還是會segfault。

          SANE:
          SANE是Linux上最主要的掃描器解決方案,可能也是唯一的解決方案,
          有支援Linux的掃描器,大概都是提供SANE的驅動程式。

          SANE分前端(frontend)和後端(backend),
          SANE frontend主要提供給應用程式,送掃描動作給SANE;
          SANE backend主要就是SANE介面界接掃描器的驅動程式。

          SANE有提供一個特別的SANE frontend,叫做net,
          它能讓SANE能透過網路接收SANE的掃描動作,達成網路控制掃描器掃描。

          HPLIP:
          前面提這麼多,原因是HPLIP相依的東西很多,
          上述幾個是最關鍵的幾個。

          參考:

          直接看參考中的系統方塊圖:

          拆開來看HPLIP各項元件,我們先只看掃描器部份,看hp-scan那個垂直的部份。

          在HPLIP中,HP的掃描器是透過SANE支援的。
          hp-scan:
          hp-scan是HPLIP提供的掃描器工具程式,但hp-scan實際上是個SANE frontend,
          就是透過SANE backend掃描。

          libsane-hpaio:
          HPLIP提供了libsane-hpaio這個SANE backend用的延伸library,
          libsane-hpaio讓SANE backend透過它來操作HP掃描器,
          我不很確定裡面有沒有包含驅動程式,或是否有包含部份的驅動程式,
          但這個library非常重要,SANE需要靠它才能操作HP掃描器,
          在SANE中,它被稱為hpaio的SANE backend。

          hpmud:
          HPLIP實際操作HP印表機、掃描器的I/O library,
          所有的工作都透過這個library傳遞給USB或網路(網路印表機、網路掃描器時),
          它的下層,就是USB library或Socket,直接連結印表機、掃描器。

          D-Bus:
          掃描器這路看完後,我們來看D-BUS。
          在HPLIP中,各個應用程式和元件間溝通都是透過D-BUS,
          這些應用程式包括掃描器左邊那幾個小顆的,
          包括hp-systray、hp-toolbox、hp-sendfax這幾個工具程式,
          還有libsane-hpaio這個SANE backend。

          這些元件和程式的溝通都透過D-Bus,
          而D-Bus本身在HPLIP則是透過hp/hpfax backend管理。

          關於D-Bus,這邊不多介紹,簡單的說,它是Linux上IPC的一種,
          各應用程式可以透過D-Bus互相溝通,
          典型的例子是,播放程式透過D-Bus提供出播放音樂的資訊,
          Skype這類的通訊軟體透過D-Bus可以得到並顯示你正在播放的音樂資訊。

          部份總結:
          到目前為止,
          先整理下HPLIP做了什麼?搞了哪些元件?要在小系統上編譯,需要編譯哪些東西?
          1.
          HPLIP最核心的I/O主要是hpmud,負責最終和硬體通訊

          2.
          HPLIP使用SANE做為掃描器核心,要能掃描,除了SANE要ok之外,
          hpaio backend要確定ok,並有放置在SANE backend的目錄內

          3.
          hp-scan只是個SANE frontend,不用管它,用其他SANE程式效果一樣

          4.
          D-Bus在HPLIP是各程式的溝通平台,單純使用掃描功能,不用管它

          5.
          如果搭配p910nd,到目前為止的資訊已經足夠了,其他元件都只跟列印和CUPS相關

          HPLIP與CUPS:
          前面CUPS提到,CUPS架構很大,CUPS中間有許多轉譯器提供各種轉譯,
          HPLIP針對CUPS實做了hpcups、hpcupsfax...等幾個轉譯器,
          接收了從CUPS收到的列印資料(應該是PostScript)後,
          透過這些轉譯器轉譯,送給hp/hpfax backend,再透過hpmud送到印表機。

          這裡我比較不清楚的地方是,
          轉譯器轉譯後,是直接在轉譯器內送到hp/hpfax backend,
          還是轉譯器轉譯後,回到CUPS,再由CUPS送到hp/hpfax backend進行列印,
          這是圖上沒有表示的部份。