![](https://habrastorage.org/files/5cc/51f/5c5/5cc51f5c5f144d08bd8e7d5afb2254f6.png)
ããã°ã©ããŒã座ã£ãŠããã¿ã³ã䜿çšããŠå¥ã®æž©åºŠã»ã³ãµãŒãšããã°ã©ã ãäœæããŸããã ãããŠçªç¶ããã®ã»ã³ãµãŒã¯å°æ¥ã®ã¢ãã«ã§é»è©±ã®å°ããªã¡ãŒã«ãŒãæãã§ããããšãå€æããŸããã ãããã£ãŠãã¿ã¹ã¯ã¯Android OSã¬ãã«ã§I2C / GPIOã»ã³ãµãŒããµããŒãããããšã§ãããã»ã³ãµãŒã¯æºåž¯é»è©±èªäœã®äžå¯æ¬ ãªéšåã«ãªããšçŽæãããŠããããã§ãã
æ·±ãäžè«ãã§ããããããšã³ãã«ã¹ã¿ããŒããã®è¿ éãã€å®æçãªå¯Ÿå¿ã®åžæã¯ãããŸããã§ãããç«ãèšç·Žããæé ãªäŸ¡æ Œã®Androidããã€ã¹ã«éçãå ¥ããããšã«ããŸããã
ã¿ã¹ã¯ã¯ããã»ã©é£ãããªããã¿ãã¬ããããã®åè·¯ãèŠã€ããäœãå£ããã«å¿ èŠãªå Žæã«ã¯ãã ä»ãããæçµçãªãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ã»ã³ãµãŒã®ååšã«æçãªã³ãŒããæžãããšãæå³ããŸããã
ããã«ãããã®ãé çªã«èŠãŠãããŸãã
- ã¯ããã«
- ã¿ãã¬ãããªã©ã®å®éã®ããã€ã¹ã«æ¥ç¶ããæ¹æ³
- ãªãŒãã£ãªåºåã§ãããã°UARTãçã¿ããããæ©èœããªãããšãèŠã€ããæ¹æ³
- I2CãGPIOãå²ã蟌ã¿ãããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ã䜿çšããç°¡åãªã«ãŒãã«ãã©ã€ããŒã®äœææ¹æ³
- Androidããã«ãŠã§ã¢ã§éçãæœè±¡åããæ¹æ³ããŸãã¯æ¢åã®ãã®ã䜿çšããæ¹æ³
- ã·ã¹ãã ãµãŒãã¹ãè¿œå ããæ¹æ³ãšããµãŒãã¹ãæå¹ã«ããŠèŠã€ããããã«äœããè¿œå ããå Žæ
- SEAndroid / SELinuxãçªç ŽããŠã«ãŒã«ãè¿œå ããæ¹æ³
- ãã§ãã¯æ¹æ³-ç°¡åãªã¢ããªãæžã
- ãã¹ãŠããŸãšããæ¹æ³
- åã®æ®µèœã§äœããééã£ãŠããããšãç解ããæ¹æ³
ã¯ããã«
ãã€ãã®ããã«ãåé¡ã¯ã§ããã ãæ©ãã¿ã¹ã¯ã®äžè²«æ§ãšå®çŸå¯èœæ§ã蚌æããå¿ èŠãããããã«éçºããããããäœåã®ããã€ãã®éšåã圢æãããŸãããããã¹ãŠã説æããããã§ã¯ãããŸããããå°è±¡ã®å®å šæ§ã®ããã«ããããæäŸããŸãã
ã¿ãã¬ãããæ¢ããŠãéžæã¯ããã€ãã®çç£çãªçç±ã§ãã¯ãµã¹7ã«èœã¡ãŸããïŒå人ããããååã«hitã«è¥²ãããïŒbecauseãã¿ããã¹ã¯ãªãŒã³ãå£ããŠããŠã¹ã䜿çšããªããã°ãªããªãã£ãïŒã®ã§ãããã§ããŸã ãã¯ãµã¹ã§ããã®äžã«ãGoogleãµã€ãã®è©³çŽ°æ å ±ãšãœãŒã¹ã³ãŒãããããŸããã ããã«ã¿ãã¬ãããåãäžããã®ã¯æãã£ãã®ã§ãæåã«ãããã®ã¯Raspberry Pi3ã§ããã ã»ãšãã©ã®ãããã°ã¯ãããã§çºçããŸããã ããã«ããã®ç©èªã¯Raspberry Pi 3ãèšå¿µãããã®ã§ã¯ãããŸãããããœãããŠã§ã¢ã®åé¡ã®ã»ãšãã©ãRaspberry Pi 3ã§è§£æ±ºãããããšãèŠããŠãããŠãã ããã
ã¿ãã¬ãããªã©ã®å®éã®ããã€ã¹ã«æ¥ç¶ããæ¹æ³
åè·¯ã®ãªãã¿ãã¬ãããªã©ã®ã ãŸãããããã€ã¹ãžã®æ¥ç¶ã¯
çè«çã«ã¯ãã¿ãã¬ããã«ã¯éåžžã«å€ãã®I2Cãã¹ããããã©ã®GPIOãããæ¡éãã«å€§ããã¯ãã§ããé©åãªãã®ãèŠã€ããŠã¯ãã ä»ãããé©åãªã¬ãã«ã«åŒãäžããã ãã§ãã 幞ããªããšã«ãNexus 7ã¿ãã¬ããã«ã¯èé¢ã«ã¡ã©ããããŸãããèé¢ã«ã¡ã©ã¯ãå¶åŸ¡ãš2ã€ã®ãã³ïŒé»æºãšãªã»ããïŒã«I2Cã䜿çšããã ãã§ãã ãŸããI2Cãš2ã€ã®GPIOãå¿ èŠã§ãïŒ1ã€ã¯ãªã³/ãªãã¹ãªãŒãã¢ãŒãçšããã1ã€ã¯æ°ãã枩床枬å®ãç ç²ã«ããŠäžæããããïŒã
å®éã®å éšãšå³ã®çžé¢é¢ä¿ã¯ããã¹ãŠãã¿ãã¬ããã®ååã»ã©åçŽã§ã¯ãªãããšã瀺ããŸããã ã€ãŸããNexus 7ã«ã¯å°ãªããšã3ã€ã®ããŒãžã§ã³ããããŸãã
- 2013ããŒãžã§ã³ã¯ãä»ã®ããã»ããµãšããŸããŸãªå°ããªè©³çŽ°ããããããèŠã€ãã£ãåè·¯ã«é©åããŸãã
- 2012ããŒãžã§ã³.1ã«ã¯èé¢ã«ã¡ã©çšã®ã¯ãã ä»ããããã·ãŒããããããã¹ãŠãåé¡ãããŸãã
- 2012ããŒãžã§ã³.2ã«ã¯ã¯ãã ä»ãããå Žæããªããã¯ãã ä»ãã¯ã¯ããã«å°é£ã§ãã
2012幎ã«ã¯ã¿ãã¬ããããããæ¢æã®ã³ãã¯ã¿ã¯ãããŸããã§ãããããã«ããããã«ã¯å£ããã¿ãããšããŠã¹ããããŸããã ãã®çµæãã¿ã³ããªã³ãå²ãã§èžã£ãåŸãã¯ãã ä»ããããã³ãã¯ã¿ãåããå¥ã®ã¿ã³ããªã³ãè³Œå ¥ããããšã«ãªããŸããã é·ãéæ°ããNexus 7ã¯ãªããããããã¶ãŒã«ããæ€çŽ¢ããŸãããããã«ãããèã®äžãèŠãŠãã«ã¡ã©ã®äžã«ã¯ãã ä»ããããå Žæã§å¿ èŠãªãã®ãéžæã§ããŸããã
NDKã䜿çšããç°¡åãªããã°ã©ã ã䜿çšããç°¡åãªæ€çŽ¢ã«ãããæ£ããI2Cãã¹ã®çªå·ãèŠã€ãããŸããã ãããè¡ãã«ã¯ãrootåãããAndroidãšchmodãwitchcraftãšãšãã«adbçµç±ã§ã€ã³ã¹ããŒã«ããŠããã¹ãŠã®I2Cãã¹ããªãªãŒã¹ããå¿ èŠããããŸããã 䞊ã¹æ¿ãã®éçšã§ããã¹ã®ã¢ãã¬ã¹ãå°ãéãã§ã¿ãå¿ èŠããããŸãããã¢ãã¬ã¹ã®äžéšã¯æ¢ã«äºçŽãããŠããŠãéä¿¡ããããšãããšãã«ããããšãåãåã£ãããã§ãã ãã®çµæãã¿ãŒã²ãããã¹ã«ã¯ä»ã«èª°ãããªãããšãå€æããŸããã
ãªãªã«ã«
èå³æ·±ã詳现ã¯ããã ã¡æãåŸã«Androidã®ãã¹ãŠã®ããŒãžã§ã³ãåãããã«åœ¹ç«ã€ããã§ã¯ãªãããšã§ãããã®å Žåãææ°ã®å
¬åŒããŒãžã§ã³ã¯Android 5.1.1ã§ããã ã€ã³ã¹ããŒã«ãšãã ã¡æãã®åŸããã¹ãŠãåé¡ãªãèŠããããã«ãªããŸããããç§ãã¡ã®ããã°ã©ã ã¯/ devãã©ã«ããŒã«ããã¢ã¯ã»ã¹ã§ããŸããã§ããã adbã·ã§ã«ãšchmodã䜿çšããã¢ã¯ã»ã¹æš©ã®åŒ·å¶å€æŽã¯å¹æããããŸããã§ããã çèããåŸãAndroid 4.4.4ã«ããŒã«ããã¯ããããšã«ããŸããã åããã ã¡æãããã»ã¹ãç¹°ãè¿ããšãããã°ã©ã ã¯ããã«/ devã«ã¢ã¯ã»ã¹ã§ããŸããã ãŸããadbã·ã§ã«ã§ã¯ããŒãžã§ã³4.4.4ã®/ devãã©ã«ããŒã¯ã¹ãŒããŒãŠãŒã¶ãŒã«ç§»åããªããŠãèªã¿åãå¯èœã§ããããAndroid 5.1.1ã§ã¯èªã¿åãå¯èœã§ã¯ãªãã£ãããšã«ã泚æããŠãã ããã æãå¯èœæ§ãé«ãã®ã¯ãAndroid 4ããAndroid 5以éãžã®ç§»è¡äžã«OSã»ãã¥ãªãã£ã«é¢ããŠããªã倧ããªå€æŽãè¡ãããããã§ãïŒããã¯ãããããªã³ã¯äžã®3çªç®ã®ãã€ã³ãã§ãïŒã
GPIOã¯ã©ãã§ããïŒ
å³ã®æåã®ããŒãžã«ã¯ãäžè¬çãªæŠèŠã§ãèé¢ã«ã¡ã©ã¢ãžã¥ãŒã«OV5650ããšåŒã°ããã«ã¡ã©ããããŸãã
![](https://habrastorage.org/files/7e0/b83/b60/7e0b83b60c024da3a5b8e1019427ac28.png)
ãŸããtegra T30LïŒã€ãŸãã¡ã€ã³SoCïŒã«çŽæ¥æ¥ç¶ãããŠããããšã瀺ããŠããŸãã è¿ãã«I2C_CAM_è¡ããããŸã...èŠãŠã¿ãŸããã...
![](https://habrastorage.org/files/f97/e74/5ea/f97e745ea4f24c83b409efefefe0a76b.png)
9ããŒãžã«å¿ èŠãªãã®ããããŸãã ã»ãšãã©ãã¹ãŠã®ããŒãžã¯ãããã³ãã«ã¡ã©ãšãªã¢ã«ã¡ã©å°çšã§ãã ãŸããã«ã¡ã©ã«ã¯2ã€ã®ãã³CAM_RST_5Mããã³PWDN_5MããããããããGPIO_PBB0ããã³GPIO_PBB5ã®SoCã«æ¥ç¶ããããšããèšè¿°ããããŸãã ãããç§ãã¡ã«å¿ èŠãªãã®ã®ããã§ãã ããã«ã¯ãã ä»ãããæ¹æ³ãèŠã€ããã ããªã®ã§ãæ€çŽ¢ãç¶ããŸã...
![](https://habrastorage.org/files/92d/d1d/ef2/92dd1def24ad4a0b9189150c455cd483.png)
ãŸããããã ãã§ãã ãã®ããŒãžã«ã¯ãç®çã®ãã³ãå«ããã«ã¡ã©ã®é»æºãå ¥ã£ãŠããFFCã³ãã¯ã¿ã®èª¬æããããŸãã ãªãªãžãã«ã®ã¿ãã¬ããã§ã¯ãã³ãã¯ã¿ã¯ã¯ãã ä»ããããŠããŸããã ããããåŸã§ãã³ãã¯ã¿ãåããå¥ã®ã¿ãã¬ãããèŠã€ããŠã被害ãåããªãããã«ããŸãã
ããã«ãèŠã€ãã£ããã³ã®ãã¬ãŒã¹ã¯ãã©ãããã©ãŒã ã³ãŒãã§æ¢ã«åéããããã©ã€ããŒã«é¢ããéšåã«ããã«ã€ããŠæžãããŠããŸã...
ãªãŒãã£ãªåºåã§ãããã°UARTãçã¿ããããæ©èœããªãããšãèŠã€ããæ¹æ³
Linuxçšã®ãã©ã€ããŒãšäœã¬ãã«ã®ãœãããŠã§ã¢ãäœæããå Žåããã©ã€ããŒãããã«ããŒãããããããã«ãŒãã«/ã·ã¹ãã ããŒããã°ã確èªããããšãïŒéåžžã«ïŒæãŸããã§ãã ãããŠãäœããããŸãè¡ããªããšããã«ããã¹ãŠãåæ¢ããçç±ã¯äžæã§ãã
ãã®ãããã€ã³ã¿ãŒããããåžã£ãŠãNexusããã€ã¹ã«ã¯ãªãŒãã£ãªãžã£ãã¯ãä»ãããããã°UARTåºåãããããšãããããŸããã ãããŠãããã¯ãã®ããã«ãœãããŠã§ã¢èšå®ãªãã§ããèªäœã®ããã«åäœããŸãïŒ
- MICãã£ã³ãã«ã®ãªãŒãã£ãªãžã£ãã¯ã«ã¯ã3V以äžã®ã¬ãã«ã«å¿çããã³ã³ãã¬ãŒã¿ãã€ã³ã¹ããŒã«ãããŠããŸãã
- éåžžã¢ãŒãã§ã¯ãMICã®é»å§ã¯1.8Vã2.9Vã§ãã
- ã¬ãã«ãè¶ ãããšããã«ç¶æ ããã³ã«éä¿¡ãããå²ã蟌ã¿ã«ããããããã°ããªãŒãã£ãªãžã£ãã¯ãé§åããããšãã«ãŒãã«ã«éç¥ãããŸãã
- ãã®åŸãå·Šå³ã®ãã£ã³ãã«ã¯ããããRXãšTXã«ãªããŸããã1.8Vã®ãŸãŸã§ãããã³ã³ããŒã¿ãŒãå¿ èŠã§ãã
![](https://habrastorage.org/files/ae2/6fb/6e9/ae26fb6e960e47a38db4a6bf634f0348.png)
![](https://habrastorage.org/files/a92/5ac/66b/a925ac66b4a74b1487eaac7ac7d4f6c7.png)
ç¥ãããã«ãã¢ããã¿ãŒUSB-UART->ãªãŒãã£ãªãäœæãããŸããã ç«ã¡åŸçããUbuntu minicomã³ã³ãœãŒã«ã§ãªã³ã«ããŠãã¿ãã¬ãããããŒãããŸããããäœããããŸããã§ããã äžè¬çã«ã ã€ãŸããããªãã ããã«ãã«ã¹ã±ãŒã«ã®æ€çŽ¢ã§ã¯ãå·Šå³ã®ãã£ãã«ã©ã€ã³ãRX / TXã®ãŒãé»å§ã¬ãã«ã«éããŠããªããããäœããã®æ¹æ³ã§ãããã°uartããªã³ã«ãªããªãããšã瀺ãããŸããã ãŸããfastbootããå€ãã®ã³ãã³ããè©ŠããŸããããäœã圹ã«ç«ã¡ãŸããã§ããã ãã®ãã³ãã£ãŒã®çµããã«ç§ãã¡ãå®å¿ãããå¯äžã®ããšã¯ã å¥ã®äººãç°ãªããã¯ãµã¹ãè©Šãããšããæ å ±ã ãã§ããããŸã£ããåãUARTã¿ãã¬ãã以å€ã¯èµ·åããŸããããç§ãã¡ã®ãã®ã§ã¯ãããŸããã§ããã ã§ãé¢çœãã£ãã§ãã
ããã«åºæ¬çãªæ¹æ³ã¯ãããã»ããµã®ãªã³/ãªãã€ã³ã¿ãŒãã§ã€ã¹ãæ¥ç¶ããããšã§ããããããã€ã¹ãã€ã¢ã°ã©ã ã«ã¯ãã®å¯èœæ§ã瀺ãããŠããŸãããããã®æ¹åã«ã¯è¡ããŸããã§ããã
ãã®çµæãç§ãã¡ã®æãã¯ãAndroidã¹ãã¬ãŒãžã«Raspberry Piãäºåçã«äœ¿çšããããšã§ããã ããã§ãããã°ããŒããæ©èœãããã¹ãŠã®ãšã©ãŒããã£ããã§ããNexusã§ã¯ã«ãŒãã«ãããŒããããŠããªãå Žåã«äœãå€æŽããããæ確ã«ãªããŸããã çµ±èšã«ãããšãã»ãšãã©ã®æéé 延ã¯ãã¯ãã ä»ããããŠããªãGPIOãã³ãšãGPIOã§ã®äœæ¥ãèš±å¯ãããšããç¹ã§ã®tegra3ã®ææžåãããŠããªãæ©èœã«ãããã®ã§ãã
ã¡ãªã¿ã«ããããã°ã®ããã«å®å šãªããŠã³ããŒããã°ãèŠãã®ã¯é¢çœãã§ããadbãã°ã¬ããŒãã䜿çšããŠååŸã§ããŸãã
I2CãGPIOãå²ã蟌ã¿ãããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ã䜿çšããç°¡åãªã«ãŒãã«ãã©ã€ããŒã®äœææ¹æ³
ãã®ãããI2Cããã³GPIOãä»ããŠããã€ã¹ãæäœããã«ãŒãã«ãã©ã€ããŒãäœæããå¿ èŠãããã/ devãã©ã«ããŒã§å ã®ååã§åŒ·èª¿è¡šç€ºããå¿ èŠããã£ããããAndroidããã«ãŠã§ã¢ã¯ãã®ãã¡ã€ã«/ãã©ã€ããŒã«ã¢ã¯ã»ã¹ããŠäœããèªã¿æžãã§ããŸãã
ãã©ã€ããŒãäœæããéã®äžè¬çãªæ©èœïŒ
- ãã©ã€ããŒã¯ãã«ãŒãã«ã«ãã§ãŒã³ã§ããŒããããŸã-ãããã¬ãã«ã®ããã€ã¹ïŒãã©ãããã©ãŒã ããã¹ïŒã¯ãä»ã®ããã€ã¹ïŒããããæäœããããã®ç¹å®ã®ããã€ã¹ãšã¢ã«ãŽãªãºã ïŒãããŒãããŸãã
- ã«ãŒãã«ã®ã¢ã»ã³ããªäžã«ããã€ã¹ããªãŒãç¡å¹ã«ãªã£ãŠããå ŽåããŸãã¯å€ãã«ãŒãã«ããŒãžã§ã³ã®ããã«ãµããŒããããŠããªãå Žåããã§ãŒã³ãšããŒãé åºã¯ããã€ã¹ããªãŒãŸãã¯CããŒãã³ãŒãã«ãã£ãŠæ±ºå®ãããŸãã tegra3ã®ã±ãŒã¹ã¯2çªç®ã§ãã
- I2Céä¿¡ãééããã¯ã©ã€ã¢ã³ãã®i2cã®æ§é ãååŸããã«ã¯ããã©ãããã©ãŒã ããŒãã³ãŒãã«èšèŒãããŠããããã€ã¹ãšç»é²æžã¿ãã©ã€ããŒã®ãªã¹ããäžèŽããå Žåã«åŒã³åºããããããŒãé¢æ°ãäœæããå¿ èŠããããŸãã i2c_add_driverã
ããããæåã«ããã©ã€ããŒãããŠã³ããŒãããããã®åææ¡ä»¶ã ã€ãŸã ãã©ãããã©ãŒã åæåã³ãŒãã«ã€ããŠã
Nexus 7 2012ã¯Tegra3ããã»ããµäžã«æ§ç¯ãããŠããŸãã ã«ãŒãã«ã¯æ°ãããªãïŒ3.1.h.chïŒãããã€ã¹ããªãŒã¯ãããŸããã ããã¯ããã¹ãŠã®ããŒããŠã§ã¢ãCã³ãŒãã§èšè¿°ããã/ kernel / tegra / arch / arm / mach-tegra /
board-grouper-pinmux.cãã¡ã€ã«ã¯ããã¹ãŠã®SoCãã³ã®éã®æ§æãèšè¿°ããnVidiaã®ã«ãŒãã«ã®éããéšåã§ããããåæåããããã®äžè¬çãªé¢æ°ãå«ã¿ãŸãïŒãtegraããšããåèªã§å§ãŸããã¹ãŠã®é¢æ°ã¯ãã«ãŒãã«ã®éããéšåã§å®è£ ããããã€ããªåœ¢åŒã§æäŸãããŸãïŒ ããã§å€æŽããå¿ èŠããããã®ãèŠãŠã¿ãŸããã
board-grouper-pinmux.c
// ... // // , , // , /* We are disabling this code for now. */ #define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ { \ .gpio_nr = _gpio, \ .is_input = _is_input, \ .value = _value, \ } static struct gpio_init_pin_info init_gpio_mode_grouper_common[] = { GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD7, false, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC6, false, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PR0, false, 0), // . - :) GPIO_INIT_PIN_MODE(TEGRA_GPIO_PBB0, true, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PBB5, false, 0), }; // static __initdata struct tegra_pingroup_config grouper_pinmux_common[] = { // ... /* , GPIO_PBB0 GPIO_PBB5. O , , . */ /* CAMERA */ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, PULL_DOWN, NORMAL, INPUT), DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, INPUT), // //DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, INPUT), // : , nIRQ DEFAULT_PINMUX(GPIO_PBB0, RSVD1, PULL_UP, NORMAL, INPUT), DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, INPUT), //DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, INPUT), // // : , DEFAULT_PINMUX(GPIO_PBB5, VGP5, PULL_DOWN, NORMAL, OUTPUT), // ... }; // ... // // , static void __init grouper_gpio_init_configure(void) { int len; int i; struct gpio_init_pin_info *pins_info; u32 project_info = grouper_get_project_id(); if (project_info == GROUPER_PROJECT_NAKASI_3G) { len = ARRAY_SIZE(init_gpio_mode_grouper3g); pins_info = init_gpio_mode_grouper3g; } else { // - 3g, 3G len = ARRAY_SIZE(init_gpio_mode_grouper_common); pins_info = init_gpio_mode_grouper_common; } for (i = 0; i < len; ++i) { tegra_gpio_init_configure(pins_info->gpio_nr, pins_info->is_input, pins_info->value); pins_info++; } } // , pinmux` // nVidia int __init grouper_pinmux_init(void) { struct board_info board_info; u32 project_info = grouper_get_project_id(); tegra_get_board_info(&board_info); BUG_ON(board_info.board_id != BOARD_E1565); grouper_gpio_init_configure(); // tegra_pinmux_config_table(grouper_pinmux_common, ARRAY_SIZE(grouper_pinmux_common)); tegra_drive_pinmux_config_table(grouper_drive_pinmux, ARRAY_SIZE(grouper_drive_pinmux)); if (project_info == GROUPER_PROJECT_NAKASI_3G) { tegra_pinmux_config_table(pinmux_grouper3g, ARRAY_SIZE(pinmux_grouper3g)); } tegra_pinmux_config_table(unused_pins_lowpower, ARRAY_SIZE(unused_pins_lowpower)); grouper_pinmux_audio_init(); return 0; } // ...
board-grouper-sensors.cãã¡ã€ã«ã«ã¯ãããããçš®é¡ã®ç°ãªãããã€ã¹ã®ç»é²ãšãããã®ããã€ã¹ã®æãäžè¬çãªã¬ãã«ã®æ©èœïŒé»æºç®¡çãªã©ïŒãå«ãŸããŠããŸãã ããã§ãã«ãŒãã«ã®äžéšãšããŠèªã¿èŸŒãŸãããã©ã€ããŒã«ããã€ã¹ãç»é²ããããã®æ§é ãè¿œå ããå¿ èŠããããŸãã ãã®ãããªãã®ïŒ
board-grouper-sensors.c
// ... // // GPIO nIRQ // , // , , // , GPIO PWRD static const struct i2c_board_info tricky_sensor_board_info[] = { { I2C_BOARD_INFO("tricky",0x55), .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB0) }, }; // 2 GPIO (, ). // , // // linux/gpio static int grouper_tricky_init(void) { // tegra_gpio_enable, // int ret = 0; ret = gpio_request(TEGRA_GPIO_PBB5, "tricky_npwd"); if (ret < 0) { pr_err("Tricky: Error: cannot register GPIO_PWR_DOWN\n"); } else { ret = gpio_direction_output(TEGRA_GPIO_PBB5, true); if (ret < 0) { pr_err("Tricky: Error: cannot set GPIO_PWR_DOWN as output\n"); } else { tegra_gpio_enable(TEGRA_GPIO_PBB5); } } ret = gpio_request(TEGRA_GPIO_PBB0, "tricky_nirq"); if (ret < 0) { pr_err("Tricky: Error: cannot register GPIO_NIRQ\n"); return ret; } ret = gpio_direction_input(TEGRA_GPIO_PBB0); if (ret < 0) { gpio_free(TEGRA_GPIO_PBB0); pr_err("Tricky: Error: cannot set GPIO_NIRQ as input\n"); } else { tegra_gpio_enable(TEGRA_GPIO_PBB0); } printk("%s: Tricky OK", __FUNCTION__); return ret; } // ... // , // int __init grouper_sensors_init(void) { int err; grouper_camera_init(); #ifdef CONFIG_VIDEO_OV2710 i2c_register_board_info(2, grouper_i2c2_board_info, ARRAY_SIZE(grouper_i2c2_board_info)); #endif /* Front Camera mi1040 + */ pr_info("mi1040 i2c_register_board_info"); i2c_register_board_info(2, front_sensor_i2c2_board_info, ARRAY_SIZE(front_sensor_i2c2_board_info)); err = grouper_nct1008_init(); if (err) printk("[Error] Thermal: Configure GPIO_PCC2 as an irq fail!"); i2c_register_board_info(4, grouper_i2c4_nct1008_board_info, ARRAY_SIZE(grouper_i2c4_nct1008_board_info)); mpuirq_init(); i2c_register_board_info(2, cardhu_i2c1_board_info_al3010, ARRAY_SIZE(cardhu_i2c1_board_info_al3010)); if (GROUPER_PROJECT_BACH == grouper_get_project_id()) { i2c_register_board_info(2, cap1106_i2c1_board_info, ARRAY_SIZE(cap1106_i2c1_board_info)); } // grouper_tricky_init(); i2c_register_board_info(2/* I2C , */, tricky_sensor_board_info, ARRAY_SIZE(tricky_sensor_board_info)); return 0; } // TBD ( )
ã³ã¡ã³ãä»ãã®ãã©ã€ããŒéšåã³ãŒã
#include <linux/init.h> // Macros used to mark up functions eg __init __exit #include <linux/module.h> // Core header for loading LKMs into the kernel #include <linux/device.h> // Header to support the kernel Driver Model #include <linux/kernel.h> // Contains types, macros, functions for the kernel #include <linux/fs.h> // Header for the Linux file system support #include <linux/i2c.h> // main sensor communication protocol #include <linux/gpio.h> // sensor`s wake/sleep and new data interrupts are processed via two pins #include <linux/interrupt.h> // Support GPIO IRQ handler #include <asm/uaccess.h> // copy_to_user and copy_from_user functions #include <asm/io.h> // Access to memset() #include <linux/workqueue.h> // Make IRQ event into deferred handler task #include <linux/mutex.h> // Sync data buffer usage between IRQ-work and outer read requests #include <linux/delay.h> // Access to mdelay // /dev/tricky_temperature #define DEVICE_NAME "tricky_temperature" // #define CLASS_NAME "tricky" // ... ... // MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Akimov"); MODULE_DESCRIPTION("Test Linux driver for tricky sensor"); ///< modinfo MODULE_VERSION("0.1"); // , static int majorNumber; static struct class* trickyClass = NULL; static struct device* trickyDevice = NULL; // ... ... // static u8 sensor_data_buffer[I2C_DATA_SIZE] = { 0 }; // I2C struct i2c_client *tricky_i2c_client = NULL; // static int dev_open(struct inode *, struct file *); static ssize_t dev_read(struct file *, char *, size_t, loff_t *); static ssize_t dev_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param); // I2C static int tricky_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); static int tricky_i2c_remove(struct i2c_client *i2c_client); // static int set_sensor_power(u8 enabled); // I2C static int read_raw_temperatures(void); // static irq_handler_t tricky_data_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs); // static void read_data_work_handler(struct work_struct *w); // static struct workqueue_struct *wq = NULL; static DECLARE_DELAYED_WORK(read_data_work, read_data_work_handler); static struct mutex read_data_mutex; // static struct file_operations fops = { .open = dev_open, .read = dev_read, .unlocked_ioctl = dev_ioctl }; // static const struct i2c_device_id tricky_i2c_id[] = { { CLASS_NAME, 0 }, { }, // , }; MODULE_DEVICE_TABLE(i2c, tricky_i2c_id); // , static struct i2c_driver tricky_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = CLASS_NAME, }, .id_table = tricky_i2c_id, .probe = tricky_i2c_probe, .remove = tricky_i2c_remove }; // i2c i2c , static int tricky_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { tricky_i2c_client = client; return 0; } // static int tricky_i2c_remove(struct i2c_client *i2c_client) { if (tricky_i2c_client != NULL) { i2c_unregister_device(tricky_i2c_client); tricky_i2c_client = NULL; } return 0; } // static int __init tricky_temperature_init(void) { int err; // Try to dynamically allocate a major number for the device -- more difficult but worth it majorNumber = register_chrdev(0, DEVICE_NAME, &fops); if (majorNumber<0){ pr_err(KERN_ALERT "Tricky failed to register a major number\n"); return majorNumber; } printk(KERN_INFO "Tricky: registered correctly with major number %d\n", majorNumber); // Register the device class trickyClass = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(trickyClass)){ // Check for error and clean up if there is pr_err(KERN_ALERT "Failed to register device class\n"); err = PTR_ERR(trickyClass); // Correct way to return an error on a pointer goto err_char_dev; } printk(KERN_INFO "Tricky: device class registered correctly\n"); // Register the device driver trickyDevice = device_create(trickyClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); if (IS_ERR(trickyDevice)){ // Clean up if there is an error pr_err(KERN_ALERT "Failed to create the device\n"); err = PTR_ERR(trickyDevice); goto err_class; } printk(KERN_INFO "Tricky: device class created correctly\n"); // Made it! device was initialized // I2 , // (, board grouper sensors) probe err = i2c_add_driver(&tricky_i2c_driver); if (err < 0) { pr_err("Tricky: Error: %s: driver registration failed, error=%d\n", __func__, err); goto err_dev; } // I2C ... // IRQ callback` // , err = request_irq( i2c_client->irq, (irq_handler_t)tricky_data_irq_handler, IRQF_TRIGGER_FALLING, "tricky_gpio_handler", NULL); // no shared interrupt lines if (err < 0) { pr_err("Tricky: Error: %s: cannot register GPIO_NIRQ irq handler: Error=%d\n", __func__, err); goto err_drv; } // IRQ wq = create_singlethread_workqueue("tricky_work"); mutex_init(&read_data_mutex); printk(KERN_INFO "Tricky: initialization completed\n"); return 0; err_irq: destroy_workqueue(wq); free_irq(i2c_client->irq, NULL); err_drv: i2c_del_driver(&tricky_i2c_driver); err_dev: device_destroy(trickyClass, MKDEV(majorNumber, 0)); // remove the device class_unregister(trickyClass); // unregister the device class err_class: class_destroy(trickyClass); // remove the device class err_char_dev: unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number return err; } // static void __exit tricky_temperature_exit(void) { if (delayed_work_pending(&read_data_work) != 0) cancel_delayed_work_sync(&read_data_work); destroy_workqueue(wq); free_irq(i2c_client->irq, NULL); i2c_del_driver(&tricky_i2c_driver); if (tricky_i2c_client != NULL) { i2c_unregister_device(tricky_i2c_client); tricky_i2c_client = NULL; } device_destroy(trickyClass, MKDEV(majorNumber, 0)); class_unregister(trickyClass); class_destroy(trickyClass); unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_INFO "Tricky: Goodbye\n"); } static int dev_open( struct inode *node, struct file *filep) { printk(KERN_INFO "Tricky: Open the LKM!\n"); return 0; } static ssize_t dev_read( struct file *filep, char *buffer, size_t len, loff_t *offset) { int ret; // , (HAL) , if (!buffer || len != I2C_DATA_SIZE) { return -EINVAL; } mutex_lock(&read_data_mutex); ret = copy_to_user(buffer, sensor_data_buffer, I2C_DATA_SIZE); mutex_unlock(&read_data_mutex); if (ret != 0) { return -ENOMEM; } return 0; } static ssize_t dev_ioctl( struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { switch (ioctl_num) { case IOCTL_POWER: ret = set_sensor_power(ioctl_param != CMD_POWER_WAKEUP ? 1 : 0); if (ret < 0) { return ret; } break; case ... // more commands default: pr_err(KERN_INFO "Tricky: invalid command type to apply\n"); return -EINVAL; } return 0; } static int set_sensor_power(u8 enabled) { gpio_set_value(GPIO_PWR_DOWN, enabled != 0); return 0; } // I2C : (2 ) // static int read_raw_temperatures(void) { int ret; struct i2c_msg write_message; struct i2c_msg read_message; write_message.addr = I2C_SLAVE_ADDRESS; write_message.flags = 0; // plain write write_message.buf = (char*)i2c_read_temperatures_address; write_message.len = sizeof(i2c_read_temperatures_address); memset(sensor_data_buffer, 0, sizeof(sensor_data_buffer)); read_message.addr = I2C_SLAVE_ADDRESS; read_message.flags = I2C_M_RD; // plain read read_message.buf = (char*)sensor_data_buffer; read_message.len = sizeof(sensor_data_buffer); // read out data ret = i2c_transfer(tricky_i2c_client->adapter, &write_message, 1); if (ret < 0) { pr_err(KERN_INFO "Tricky: Cannot write data address. Error=%d\n", ret); return ret; } ret = i2c_transfer(tricky_i2c_client->adapter, &read_message, 1); if (ret < 0) { pr_err(KERN_INFO "Tricky: Cannot read data from the sensor. Error=%d\n", ret); return ret; } return 0; } // - // , I2C , // I2C // , , , // static irq_handler_t tricky_data_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) { // , if (delayed_work_pending(&read_data_work) == 0) queue_delayed_work(wq, &read_data_work, msecs_to_jiffies(1)); return (irq_handler_t)IRQ_HANDLED; } // , // // ( , ) static void read_data_work_handler(struct work_struct *w) { int ret; mutex_lock(&read_data_mutex); ret = read_raw_temperatures(); mutex_unlock(&read_data_mutex); if (ret < 0) { printk(KERN_INFO "Tricky: read_data_work_handler. Ret = %d\n", ret); } } // , module_init(tricky_temperature_init); module_exit(tricky_temperature_exit);
åå¥ã«ãã¢ã»ã³ããªã®ãã¡ã€ã«ã§ããKConfigãšMakefileã«èšåããå¿ èŠããããŸãã
KConfigã§ã¯ãMakefileã§äœæãããTRICKY_SENSORïŒCONFIG_ãã¬ãã£ãã¯ã¹ãªãïŒãšããååã§ãã¢ã»ã³ããªäžã«èæ ®ã«å ¥ãã段èœãããã«è¿œå ããŸãã ãŸããmake menuconfigã䜿çšãããšããã©ã€ããŒã衚瀺ãããŸãã
Kconfig
menuconfig THERMAL tristate "Generic Thermal sysfs driver" help Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal zone and cooling device. Each thermal zone contains its own temperature, trip points, cooling devices. All platforms with ACPI thermal support can use this driver. If you want this support, you should say Y or M here. config THERMAL_HWMON bool depends on THERMAL depends on HWMON=y || HWMON=THERMAL default y config TRICKY_SENSOR default y bool prompt "Tricky temperature sensor support"
ã¡ã€ã¯ãã¡ã€ã«
obj-$(CONFIG_THERMAL) += thermal_sys.o obj-$(CONFIG_TRICKY_SENSOR) += tricky_temperature.o
ãã®çµæãã«ãŒãã«çšã«æ¬¡ã®ãã¡ã€ã«ãååŸããŸãã
kernel/tegra/arch/arm/mach-tegra/board-grouper-pinmux.c kernel/tegra/arch/arm/mach-tegra/board-grouper-sensors.c kernel/tegra/drivers/thermal/tricky_sensor.c kernel/tegra/drivers/thermal/KConfig kernel/tegra/drivers/thermal/Makefile
Androidããã«ãŠã§ã¢ã§éçãæœè±¡åããæ¹æ³ããŸãã¯æ¢åã®ãã®ã䜿çšããæ¹æ³
次ã®ã¬ãã«ã«é²ã¿ãŸãããã ãã©ã€ããŒã¯äœæãããŠãããAndroidã®ãŠãŒã¶ãŒç©ºééšåã«ç§»åããŠããŸããããã§ããã©ã€ããŒã«äœããã®æ¹æ³ã§ãã€ã³ãããå¿ èŠããããŸãã
Androidã§åãçš®é¡ã®åšèŸºæ©åšã®å€ãã®å®è£ ã䜿çšããããã«ãããŒããŠã§ã¢ã¢ãã¹ãã©ã¯ã·ã§ã³ã®ããŸããŸãªã€ã³ã¿ãŒãã§ã€ã¹ãå«ãããã«ãŠã§ã¢ã¬ã€ã€ãŒïŒC / C ++ã§èšè¿°ïŒããããŸãïŒããŒããŠã§ã¢ã¢ãã¹ãã©ã¯ã·ã§ã³ã¬ãã«-HALïŒã ãããŠãããããçš®é¡ã®æž©åºŠç£æ°ãªã©ã®ããã« ã»ã³ãµãŒãããå ŽæããããŸãã ãããããã®HALã®å¶éã¯ããã®APIãèªã¿åãå°çšã§ããããšã§ããããã¯ããããã®ããã€ã¹ã«åæã«ã¢ã¯ã»ã¹ã§ããå€ãã®ãŠãŒã¶ãŒããã°ã©ã ãèãããšåŠ¥åœã§ãã ãããŠãäžæ¹ã®èšå®ãå€æŽãããšãããäžæ¹ã®èšå®ã«ãªããŸãã ãã®ãã¹ãŠã¯ãããã§éåžžã«ãã説æãããŠããŸã ã
ãŸããç¹ã«ã»ã³ãµãŒãæäœããèªã¿åãå°çšã¢ãŒãã«é¢ããŠã¯ãäžèšã®ãªã³ã¯ããã®åŒçšã§ãã
ãµã³ããªã³ã°é »åºŠãšæ倧ã¬ããŒãé 延以å€ã«ãã¢ããªã±ãŒã·ã§ã³ã¯ã»ã³ãµãŒãã©ã¡ãŒã¿ãŒãæ§æã§ããŸããã ããšãã°ããé«ç²ŸåºŠãã¢ãŒããšãäœé»åãã¢ãŒãã®äž¡æ¹ã§æ©èœããç©çã»ã³ãµãŒãæ³åããŠãã ããã ãã以å€ã®å Žåã¯ã¢ããªã±ãŒã·ã§ã³ãé«ç²ŸåºŠã¢ãŒããèŠæ±ããå¥ã®ã¢ãŒãã¯äœé»åã¢ãŒããèŠæ±ããå¯èœæ§ããããããAndroidããã€ã¹ã§äœ¿çšã§ããã®ã¯ããã2ã€ã®ã¢ãŒãã®ãã¡1ã€ã ãã§ãã ãã¬ãŒã ã¯ãŒã¯ãäž¡æ¹ã®ã¢ããªã±ãŒã·ã§ã³ãæºããæ¹æ³ã¯ãããŸããã ãã¬ãŒã ã¯ãŒã¯ã¯åžžã«ãã¹ãŠã®ã¯ã©ã€ã¢ã³ããæºè¶³ãããå¿ èŠããããããããã¯ãªãã·ã§ã³ã§ã¯ãããŸããã
ã¢ããªã±ãŒã·ã§ã³ããã»ã³ãµãŒãŸãã¯ãã®ãã©ã€ããŒã«ããŒã¿ãéä¿¡ããã¡ã«ããºã ã¯ãããŸããã ããã«ããã1ã€ã®ã¢ããªã±ãŒã·ã§ã³ãã»ã³ãµãŒã®åäœãå€æŽã§ããªããªããä»ã®ã¢ããªã±ãŒã·ã§ã³ãç ŽæããããšããªããªããŸãã
ããããç§ãã¡ã¯æ¬åœã«ããã€ã¹ãå¶åŸ¡ããŸãïŒããšãã°ãé»åã¢ãŒããšæž¬å®ã¢ãŒããåãæ¿ããŸãïŒããŸããã»ã³ãµãŒã¯å ¬åŒã«ææžåãããŠããããããã°ã©ã ã®ã¿ãåäœãããããç¬èªã®HALãäœæããŸãã ããã§ã¯åºæ¬çãªããšã¯ã¢ã¯ã»ã¹å¯èœãªè±èªã§æžãããŠããã®ã§ãåŸã§ã©ã®ãããªããŒã¿æ§é ãšãã®çç±ãæããã«ãªããŸãã
ç¬èªã®ããŒããŠã§ã¢ãäœæããŸãã ãããè¡ãã«ã¯ãIDãèŠã€ããŠãã¢ãžã¥ãŒã«ã®èª¬æãããã³æŽŸçé¢æ°ãå«ãhw_device_tãå«ãæ§é äœãäœæããå¿ èŠããããŸãã Googleã¯ããã®ã¬ãã«ã§ã®å®è£ ãšã€ã³ã¿ãŒãã§ãŒã¹ã®å€èŠ³ãæ£ç¢ºã«æå®ããŠããªããããå 貎ãæ¯ãè¿ãããšãªããè¯ããã®ããŸãå§ããããšãã§ããŸãã
sensor_tricky_temperature.h
#ifndef ANDROID_TRICKY_INTERFACE_H #define ANDROID_TRICKY_INTERFACE_H #include <stdint.h> #include <sys/cdefs.h> #include <sys/types.h> #include <hardware/hardware.h> __BEGIN_DECLS #define TRICKY_HARDWARE_MODULE_ID "tricky" struct tricky_device_t { struct hw_device_t common; int (*read_sample)(unsigned short *psynchro, short *pobj_temp, short *pntc1_temp, short *pntc2_temp, short *pntc3_temp); int (*activate)(unsigned char enabled); int (*set_mode)(unsigned char is_continuous); }; __END_DECLS #endif // ANDROID_TRICKY_INTERFACE_H
sensor_tricky_temperature.c
#include <errno.h> #include <cutils/log.h> #include <cutils/sockets.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/i2c.h> #include <hardware/sensor_tricky_temperature.h> #define LOG_TAG "TRICKY" #define DEVICE_NAME "/dev/tricky_temperature" #define TRICKY_MODE_0 0 #define TRICKY_MODE_1 1 int fd = 0; int read_sample(unsigned short *psynchro, short *pobj_temp, short *pntc1_temp, short *pntc2_temp, short *pntc3_temp) { int ret = 0; unsigned char buffer[10]; ALOGD("HAL -- read_sample() called"); ret = read(fd, (char*)buffer, sizeof(buffer)); if (ret < 0) { ALOGE("HAL -- cannot read raw temperature data"); return -1; } if (psynchro) *psynchro = (unsigned short)(buffer[3] << 8 | buffer[2]); if (pobj_temp) *pobj_temp = (short)(buffer[1] << 8 | buffer[0]); if (pntc1_temp) *pntc1_temp = (short)(buffer[5] << 8 | buffer[4]); if (pntc2_temp) *pntc2_temp = (short)(buffer[7] << 8 | buffer[6]); if (pntc3_temp) *pntc3_temp = (short)(buffer[9] << 8 | buffer[8]); ALOGD("HAL - sample read OK"); return 0; } int activate(unsigned char enabled) { int ret = 0; ALOGD("HAL - activate(%d) called", enabled); ret = ioctl(fd, 0, enabled ? TRICKY_MODE_0 : TRICKY_MODE_1); if (ret < 0) { ALOGE("HAL - cannot write activation state"); return -1; } ALOGD("HAL - activation state written OK"); return 0; } int set_mode(unsigned char is_continuous) { int ret; ALOGD("HAL -- set_mode(%d) called", is_continuous); ret = ioctl(fd, 1, is_continuous ? TRICKY_MODE_0 : TRICKY_MODE_1); if (ret < 0) { ALOGE("HAL - cannot write mode state"); return -1; } ALOGD("HAL - mode state written OK"); return 0; } static int open_tricky(const struct hw_module_t* module, char const* name, struct hw_device_t** device) { int ret = 0; struct tricky_device_t *dev = malloc(sizeof(struct tricky_device_t)); if (dev == NULL) { ALOGE("HAL - cannot allocate memory for the device"); return -ENOMEM; } else { memset(dev, 0, sizeof(*dev)); } ALOGD("HAL - openHAL() called"); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (struct hw_module_t*)module; dev->read_sample = read_sample; dev->activate = activate; dev->set_mode = set_mode; *device = (struct hw_device_t*) dev; fd = open(DEVICE_NAME, O_RDWR); if (fd <= 0) { ALOGE("HAL - cannot open device driver"); return -1; } ALOGD("HAL - has been initialized"); return 0; } static struct hw_module_methods_t tricky_module_methods = { .open = open_tricky }; struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = TRICKY_HARDWARE_MODULE_ID, .name = "Tricky HAL Module", .author = "Pavel Akimov", .methods = &tricky_module_methods, };
ã¢ãžã¥ãŒã«ããã«ãããã«ã¯ã Android.mkãã¡ã€ã«ãå¿ èŠã§ãã
Android.mk
# LOCAL_PATH := $(call my-dir) # .mk , # # , LOCAL_PATH include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false # , LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw # LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware # , LOCAL_SRC_FILES := sensor_tricky_temperature.c # LOCAL_MODULE := techartmsjdts.default LOCAL_MODULE_TAGS := debug include $(BUILD_SHARED_LIBRARY)
ãŸããã³ã³ãã€ã«ãããã©ã€ãã©ãªãlibhardwareã«å«ããããã®å¥ã®Android.mkãã¡ã€ã«ã ã¢ãžã¥ãŒã«ã®IDãååã§è¿œå ããŸãã
Android.mk
hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time \ power usbaudio audio_remote_submix camera consumerir tricky include $(call all-named-subdir-makefiles,$(hardware_modules))
HALã®åºåã«ã¯ã次ã®ãã¡ã€ã«ããããŸã
hardware/libhardware/include/hardware/sensor_tricky_temperature.h hardware/libhardware/modules/Android.mk hardware/libhardware/modules/tricky/sensor_tricky_temperature.c hardware/libhardware/modules/tricky/Android.mk
ã·ã¹ãã ãµãŒãã¹ãè¿œå ããæ¹æ³ãšããµãŒãã¹ãæå¹ã«ããŠèŠã€ããããã«äœããè¿œå ããå Žæ
ããã«ã誰ããHALã«é»è©±ããå¿ èŠããããŸãã OCã®ä»ã®éšåã§ã¯ããã®ãããªããšã¯ãJavaã§èšè¿°ãããã·ã¹ãã ãµãŒãã¹ãšãã®ãããŒãžã£ãŒã䜿çšããŠè¡ãããŸãã è¡ã®å€ã«åºãªãããã«ããã«ã¯ãå¥ã®ãã®ãæžããŸãã åœç€Ÿã®ãµãŒãã¹ã¯æ¬¡ã®ãã¡ã€ã«ã«åå ããŸãã
frameworks\base\core\java\android\app\ContextImpl.java frameworks\base\core\java\android\content\Context.java frameworks\base\core\java\android\hardware\temperature\ITrickyService.aidl frameworks\base\core\java\android\hardware\temperature\TrickyTemperatureData.aidl frameworks\base\core\java\android\hardware\temperature\TrickyTemperatureData.java frameworks\base\core\java\android\hardware\temperature\TrickyManager.java frameworks\base\services\java\com\android\server\temperature\TrickyService.java frameworks\base\services\java\com\android\server\SystemServer.java frameworks\base\services\jni\Android.mk frameworks\base\services\jni\com_android_server_temperature_TrickyService.cpp frameworks\base\services\jni\onload.cpp frameworks\base\Android.mk
ãœãŒã¹ãããããããã«ããã€ãã£ãã¬ãã«ã¯ãŸã ããããªããããJNIãä»ããŠHALã¢ãžã¥ãŒã«ã«æ¥ç¶ããå¿ èŠããããŸãã åæã«ãåç §ã¿ã€ããæžãçããŸããããã¯AIDLãä»ããŠæ±ºå®ããC ++ããJavaã«æããå¿ èŠããããŸãã
ãµãŒãã¹ã®ãã€ãã£ãéšåã®ã³ãŒã
// LOG_TAG #define LOG_TAG "TRICKY" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/sensor_tricky_temperature.h> #include <stdio.h> // , , // , Android namespace android { static jlong init_native(JNIEnv *env, jobject clazz) { int err; hw_module_t* module; tricky_device_t* dev = NULL; // HAL // , hw // , // HAL ".default" - ( // - HAL, ) err = hw_get_module(TRICKY_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { err = module->methods->open(module, "", ((hw_device_t**) &dev)); if (err != 0) { ALOGE("init_native: cannot open device module: %d", err); return -1; } } else { ALOGE("init_native: cannot get device module: %d", err); return 0; } ALOGD("init_native: start ok"); // Java return (jlong)dev; } // static void finalize_native(JNIEnv *env, jobject clazz, jlong ptr) { tricky_device_t* dev = (tricky_device_t*)ptr; if (dev == NULL) { ALOGE("finalize_native: invalid device pointer"); return; } free(dev); ALOGD("finalize_native: finalized ok"); } // HAL // C++ TrickyTemperatureData static jobject read_sample_native(JNIEnv *env, jobject clazz, jlong ptr) { tricky_device_t* dev = (tricky_device_t*)ptr; int ret = 0; unsigned short synchro = 0; short obj_temp = 0; short ntc1_temp = 0; short ntc2_temp = 0; short ntc3_temp = 0; if (dev == NULL) { ALOGE("read_sample_native: invalid device pointer"); return (jobject)NULL; } ret = dev->read_sample(&synchro, &obj_temp, &ntc1_temp, &ntc2_temp, &ntc3_temp); if (ret < 0) { ALOGE("read_sample_native: Cannot read TrickyTemperatureData"); return (jobject)NULL; } // , // android.hardware.temperature.TrickyTemperatureData jclass c = env->FindClass("android/hardware/temperature/TrickyTemperatureData"); if (c == 0) { ALOGE("read_sample_native: Find Class TrickyTemperatureData Failed"); return (jobject)NULL; } // ( ) jmethodID cnstrctr = env->GetMethodID(c, "<init>", "()V"); if (cnstrctr == 0) { ALOGE("read_sample_native: Find constructor TrickyTemperatureData Failed"); return (jobject)NULL; } // ID . , , , getter` setter` jfieldID synchroField = env->GetFieldID(c, "synchro", "I"); jfieldID objTempField = env->GetFieldID(c, "objectTemperature", "I"); jfieldID ntc1TempField = env->GetFieldID(c, "ntc1Temperature", "I"); jfieldID ntc2TempField = env->GetFieldID(c, "ntc2Temperature", "I"); jfieldID ntc3TempField = env->GetFieldID(c, "ntc3Temperature", "I"); if (synchroField == 0 || objTempField == 0 || ntc1TempField == 0 || ntc2TempField == 0 || ntc3TempField == 0) { ALOGE("read_sample_native: cannot get fields of resulting object"); return (jobject)NULL; } // jobject jdtsData = env->NewObject(c, cnstrctr); env->SetIntField(jdtsData, synchroField, (jint)synchro); env->SetIntField(jdtsData, objTempField, (jint)obj_temp); env->SetIntField(jdtsData, ntc1TempField, (jint)ntc1_temp); env->SetIntField(jdtsData, ntc2TempField, (jint)ntc2_temp); env->SetIntField(jdtsData, ntc3TempField, (jint)ntc3_temp); ALOGD("read_sample_native: read ok"); return jdtsData; } // // JNI static JNINativeMethod method_table[] = { { "init_native", "()J", (void*)init_native }, { "finalize_native", "(J)V", (void*)finalize_native }, { "read_sample_native", "(J)Landroid/hardware/temperature/TrickyTemperatureData;", (void*)read_sample_native }, { "activate_native", "(JZ)Z", (void*)activate_native }, { "set_mode_native", "(JZ)Z", (void*)set_mode_native}, }; // onload.cpp, // system server int register_android_server_JdtsService(JNIEnv *env) { ALOGD("register_android_server_JdtsService"); return jniRegisterNativeMethods( env, "com/android/server/temperature/JdtsService", method_table, NELEM(method_table)); }; };
ããã«onload.cppã¯ããããå¿ èŠãšãããµãŒãã¹ã®ãã¹ãŠã®JNIéšåãããŒãããŸããç§ãã¡ã®ãã®ãå«ãã
onload.cpp
// ... #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" #include "utils/misc.h" namespace android { // ... int register_android_server_JdtsService(JNIEnv* env); }; using namespace android; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("GetEnv failed!"); return result; } ALOG_ASSERT(env, "Could not retrieve the env!"); // ... register_android_server_JdtsService(env); return JNI_VERSION_1_4; }
åŸæ¥ã®Android.mkã«ã¯ããã¹ãŠã®ããŒããçµã¿ç«ãŠãããã®æ å ±ãå«ãŸããŠãããJNIã®ããŒã¹ãããã«ãããŸãã
åç §ã¿ã€ãã¯AIDLã䜿çšããŠäœæããå¿ èŠããããŸãããã®èšèªã¯Androidã ãã§ãªããAndroidã®ããã»ã¹éããŒã¿è»¢éã®æ段ã§ããããã§ãããŸããããã転éããã«ã¯ã以äžã®ãªã¹ãã«ç€ºãããã«ãããŒã»ã«å¯èœã§ããå¿ èŠããããŸãã
TrickyTemperatureData.aidl
package android.hardware.temperature; parcelable TrickyTemperatureData;
TrickyTemperatureData.java
package android.hardware.temperature; import android.os.Parcel; import android.os.Parcelable; /** {@hide} */ public final class TrickyTemperatureData implements Parcelable { public int synchro; public int objectTemperature; public int ntc1Temperature; public int ntc2Temperature; public int ntc3Temperature; public static final Parcelable.Creator<TrickyTemperatureData> CREATOR = new Parcelable.Creator<TrickyTemperatureData>() { public TrickyTemperatureData createFromParcel(Parcel in) { return new TrickyTemperatureData(in); } public TrickyTemperatureData[] newArray(int size) { return new TrickyTemperatureData[size]; } }; public TrickyTemperatureData() { } private TrickyTemperatureData(Parcel in) { readFromParcel(in); } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(synchro); out.writeInt(objectTemperature); out.writeInt(ntc1Temperature); out.writeInt(ntc2Temperature); out.writeInt(ntc3Temperature); } public void readFromParcel(Parcel in) { synchro = in.readInt(); objectTemperature = in.readInt(); ntc1Temperature = in.readInt(); ntc2Temperature = in.readInt(); ntc3Temperature = in.readInt(); } @Override public int describeContents() { return 0; } }
ãµãŒãã¹èªäœãšãã®ãããŒãžã£ãŒã¯éåžžã«ã·ã³ãã«ã§æ°åããªãã®ã§ãããã§ã¯èª¬æããŸããããã¹ãŠãç£èŠãŸãã¯çªããªã³ã¯ã«é 眮ããŸãã
ããã§ããµãŒãã¹ã®ååã䜿çšããŠå®æ°ãè¿œå ããå¿ èŠããããŸãããã®ãµãŒãã¹ã䜿çšãããšãcontext.getSytemServiceãä»ããŠæ€çŽ¢ã§ããŸããã³ã¡ã³ãã«ã¯hideãå«ããå¿ èŠãããããšã«æ³šæããŠãã ãããããããªããšãã¢ã»ã³ããªã¯æ©èœããããã®ãããªååã¯APIã«æ£åŒã«ç»é²ãããããããã³ã°ããå¿ èŠããããšããã¡ãã»ãŒãžãæ®ããŸãã
// frameworks\base\core\java\android\content\Context.java /** * @hide */ public static final String TRICKY_SERVICE = "android.service.tricky.ITrickyService";
ãµãŒãã¹ãæ©èœãããã«ã¯ãããã§SystemServerãä»ããŠServiceManagerã«å«ããå¿ èŠããããŸãã
// frameworks\base\services\java\com\android\server\SystemServer.java // initAndLoop ... try { Slog.e(TAG, "Tricky Service"); trickyService = new TrickyService(context); ServiceManager.addService(Context.TRICKY_SERVICE, trickyService); } catch (Throwable e) { Slog.e(TAG, "Failure starting TrickyService", e); }
ãµãŒãã¹ãã¢ããªã±ãŒã·ã§ã³åŽã§äœ¿çšå¯èœã«ããã«ã¯ããã®ãããŒãžã£ãŒãã³ã³ããã¹ãã«è¿œå ããå¿ èŠããããŸãïŒéçããŒãã£ã³ã°ãããã¯å ïŒã
//frameworks\base\core\java\android\app\ContextImpl.java registerService(TRICKY_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder iBinder = ServiceManager.getService(Context.TRICKY_SERVICE); return new TrickyManager(ITrickyService.Stub.asInterface(iBinder)); }});
RegisterServiceèªäœã¯ãAndroid 4.4.4ã§ã¯æ¬¡ã®ããã«ãªããŸãã
private static int sNextPerContextServiceCacheIndex = 0; // .. fetcher map private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); } // , getSystemService // ... @Override public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
ç¬èªã®ã«ãŒã«ãè¿œå ããŠSEAndroid / SELinuxãçªç Žããæ¹æ³
ããŠããã¹ãŠã®ã³ãŒããèšè¿°ãããŠããããã§ããããã©ã€ããŒã¯å®å šã«ã«ãŒããŠãŒã¶ãŒã«ãã£ãŠææãããŠããããããµãŒãã¹ã¯éå§ãããããã°ã«å®è¡ããæš©éããªããšããã¡ãã»ãŒãžã衚瀺ããããããŠãäœãã®èšé²ãæžããšãçµæãšããŠãå©çã¯ãããŸãããå¿ èŠãªæš©å©ãšèŠåã¯ãsepolicyããŒãã§èŠå®ããå¿ èŠããããŸãã
initã¹ã¯ãªããã®ãã©ãããã©ãŒã åºæã®éšåãã·ã¹ãã å šäœã®ã»ãŒåæã®èµ·åãåŠçããŸãã
#(device/asus/grouper/init.grouper.rc) # ... on post-fs-data # ... # tricky temperature sensor # / system # root` chmod 0660 /sys/class/tricky/tricky_temperature/dev chown system system /sys/class/tricky/tricky_temperature/dev
ãŸããããã€ã¹ãã¡ã€ã«èªäœã®æš©å©ãšèš±å¯ãueventdã«ç»é²ããŸãã
# device/asus/grouper/ueventd.grouper.rc /dev/tricky_temperature 0660 system system
ãããŠ...ã·ã¹ãã ãµãŒãã¹ïŒã³ãŒãã§æ¢ã«è¿œå ããŠããå ŽæïŒã§ãµãŒãã¹ãèªã¿èŸŒãããšãã§ããããã«ãããããçš®é¡ã®SELinuxã«ãŒã«ãäœæããå¿ èŠããããŸãããŸãããµãŒãã¹ã§ãããã£ã©ã¯ã¿ãŒããã€ã¹ïŒãã©ã€ããŒïŒã®èªã¿åããšæžã蟌ã¿ãèš±å¯ããã«ãŒã«ãäœæããå¿ èŠããããŸããäž»ã«Brilloã®äŸã«äŸåããŠããŸãããç§ã¯ããã«å€¢äžã«ãªã£ãŠãã¹ãŠãç解ãããã©ããã¯ããããŸããããé çªã«è©ŠããŠã¿ãŸãããïŒ
1ã€ã®ãããã¯ãã¹ã«ã«ãŒã«ããããã¹ãŠã®ãã¡ã€ã«
##################################### # , # . # , . # (te_macros) # tricky_service_domain(domain) # Allow a base set of permissions common across Android daemons. define(`tricky_service_domain', ` init_daemon_domain($1) # Allow using binder and performing IPC to system services. binder_use($1) binder_service($1) # Allow access to files in /proc. # Fixes denials like: # avc: denied { read } for pid=1267 comm="peripheralman" name="misc" dev="proc" # ino=4026531967 scontext=u:r:peripheralman:s0 # tcontext=u:object_r:proc:s0 tclass=file permissive=0 allow $1 proc:file r_file_perms; allow $1 tricky_service:service_manager find; # Cut down on spam. dontaudit $1 kernel:system module_request; ') ##################################### # , , # # (tricky_service.te) type tricky_service, domain; type tricky_service_exec, exec_type, file_type; tricky_service_domain(tricky_service) ##################################### # , system manager # (service.te) type tricky_service, service_manager_type; # , # "tricky_service" . # SELinux https://source.android.com/security/selinux/ ##################################### # (service_contexts) android.service.jdtstemperature.IJdstsService u:object_r:tricky_service:s0 ##################################### # . # . # (device.te) type tricky_device, dev_type, mlstrustedobject; ##################################### # # (file_contexts) /dev/tricky_temperature u:object_r:tricky_device:s0 ##################################### # ( , , # "bootanim" # ) #(bootanim.te) allow bootanim tricky_device:chr_file rw_file_perms; ##################################### # , , SystemServer system apps # (system_server.te) allow system_server tricky_device:chr_file rw_file_perms; ##################################### # (system_app.te) allow system_app tricky_device:chr_file rw_file_perms;
ããã§ããµãŒãã¹çšã®æ°ãããã¡ã€ã³ãäœæããããã€ã¹ãç¹å®ãããµãŒãã¹ã«ãã©ã€ããŒãžã®èªã¿åãããã³æžã蟌ã¿æš©éãããããšã瀺ããŸããããã¡ãããããããã¹ãŠæžããã®ã¯åããŠã§ã¯ãããŸããã§ããããã®ãã¹ãŠã®ããŒãã®åŸãã·ã¹ãã ã¯æçµçã«ãããã¯ããããµãŒãã¹ã«é¢ããã¡ãã»ãŒãžãåãé€ããadbã·ã§ã«ã§ãã©ã€ããŒãã·ã¹ãã ã®ãŠãŒã¶ãŒåã«èšé²ãããäžçäžã«å ¬éãããŠããããšãæããã«ãªããŸããã
ãã§ãã¯æ¹æ³-ç°¡åãªã¢ããªãæžã
ãã¹ãŠãæ©èœããããšãäœããã®åœ¢ã§æ€èšŒããå¿ èŠããããŸãããã¡ãããadbã·ã§ã«ãä»ããŠlogcatããã£ãšèŠã€ããããšãã§ããŸãããäœããã®çç±ã§èª°ãããã®çµæã«æºè¶³ããŠããããã§ã¯ãªããããã«ã¹ã¿ã OCã«çµã¿èŸŒã¿ã¢ããªã±ãŒã·ã§ã³ãè¿œå ããŸãããã¡ããããã«ãã€ã³ããã®ã¿ãã¬ãããé€ãã誰ããããå¿ èŠãšããŸããããã±ãŒãž/ã¢ããª/ TrickyDemoãããã³ãã«ã/ã¿ãŒã²ãã/補å/core.mkã«å ¥ãããœãŒã¹ã§ã¯ãäºåå®çŸ©ããããã®ã®ãªã¹ãã§ããã瀺ããŸãã
ã¡ã€ã³ã³ãŒãå
éšã¢ããªã±ãŒã·ã§ã³
package com.android.trickydemo; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.Switch; import android.widget.TextView; import android.hardware.temperature.*; public class MainActivity extends Activity { private final String TAG = "TrickyDemo"; private final int POLLING_PERIOD_MS = 200; private TrickyManager mServiceManager = null; private TrickyTemperatureData mSensorData = null; private GaugeView mGaugeObj; private GaugeView mGaugeNtc1; private GaugeView mGaugeNtc2; private GaugeView mGaugeNtc3; private TextView mTextSynchro; private ImageView mIrqImage; private TextView mTextObj; private TextView mTextNtc1; private TextView mTextNtc2; private TextView mTextNtc3; // all temperatures are .2 points precision values in degrees Celsius final private Object mDataSync = new Object(); private boolean mMeasModeUpdateRequired; // set up when user switches between measurement modes and queues I2C expander command // to switch the mode private boolean mIsContinuousMode; // continuous mode (power is always on, no control) // burst mode (every cycle power on, read and power off required) private boolean mPowerState; private boolean mPowerUpdateRequired; private Thread mCommThread = null; private boolean mIsRunning = true; // the communication thread goes on unless onDestroy method is called @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // enforce the sensor to switch into continuous mode on startup mPowerUpdateRequired = true; mPowerState = true; mMeasModeUpdateRequired = true; mIsContinuousMode = true; mIrqImage = (ImageView) findViewById(R.id.image_led_irq); mGaugeObj = (GaugeView) findViewById(R.id.gauge_view_obj); mGaugeNtc1 = (GaugeView) findViewById(R.id.gauge_view_ntc1); mGaugeNtc2 = (GaugeView) findViewById(R.id.gauge_view_ntc2); mGaugeNtc3 = (GaugeView) findViewById(R.id.gauge_view_ntc3); mTextSynchro = (TextView) findViewById(R.id.text_synchro); mTextObj = (TextView) findViewById(R.id.text_obj); mTextNtc1 = (TextView) findViewById(R.id.text_ntc1); mTextNtc2 = (TextView) findViewById(R.id.text_ntc2); mTextNtc3 = (TextView) findViewById(R.id.text_ntc3); Switch switch_mode = (Switch) findViewById(R.id.switch1); switch_mode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { synchronized (mDataSync) { mIsContinuousMode = isChecked; mMeasModeUpdateRequired = true; } } }); Switch switch_power = (Switch) findViewById(R.id.switch_power); switch_power.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { synchronized (mDataSync) { mPowerState = isChecked; mPowerUpdateRequired = true; } } }); switch_power.setChecked(true); // power is on by default mServiceManager = (TrickyManager) getSystemService(TRICKY_SERVICE); mCommThread = new Thread() { @Override public void run() { while(mIsRunning) { synchronized (mDataSync) { if (mPowerUpdateRequired) { if (mServiceManager.activate(mPowerState)) { mPowerUpdateRequired = false; } else { Log.w(TAG, "Cannot update power state"); } } if (mMeasModeUpdateRequired) { if (mServiceManager.setMode(mIsContinuousMode)) { mMeasModeUpdateRequired = false; } else { Log.w(TAG, "Cannot update measurement mode"); } } } mSensorData = mServiceManager.readSample(); if (mSensorData != null) { updateUI(); } else { updateNonIRQUI(); } try { Thread.sleep(POLLING_PERIOD_MS); } catch (InterruptedException e) { e.printStackTrace(); } } } }; mCommThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { e.printStackTrace(); } }); mCommThread.start(); } @Override protected void onDestroy() { super.onDestroy(); try { mCommThread.join(POLLING_PERIOD_MS * 2); } catch (InterruptedException e) { e.printStackTrace(); } } private void updateUI() { runOnUiThread(new Runnable() { public void run() { float obj_temp = mSensorData.objectTemperature / 100.F; float ntc1_temp = mSensorData.ntc1Temperature / 100.F; float ntc2_temp = mSensorData.ntc2Temperature / 100.F; float ntc3_temp = mSensorData.ntc3Temperature / 100.F; String s_obj = String.format("%.2f °C", obj_temp); String s_ntc1 = String.format("%.2f °C", ntc1_temp); String s_ntc2 = String.format("%.2f °C", ntc2_temp); String s_ntc3 = String.format("%.2f °C", ntc3_temp); String s_synchro = String.format("Synchro = %d", mSensorData.synchro); mGaugeObj.setTargetValue(obj_temp); mTextObj.setText(s_obj); mGaugeNtc1.setTargetValue(ntc1_temp); mTextNtc1.setText(s_ntc1); mGaugeNtc2.setTargetValue(ntc2_temp); mTextNtc2.setText(s_ntc2); mGaugeNtc3.setTargetValue(ntc3_temp); mTextNtc3.setText(s_ntc3); mTextSynchro.setText(s_synchro); mIrqImage.setImageDrawable(getResources().getDrawable(R.drawable.led_green_hi)); Log.d(TAG, s_synchro + "Obj = " + s_obj + " NTC1 = " + s_ntc1 + " NTC2 = " + s_ntc2 + " NTC3 = " + s_ntc3); } }); } private void updateNonIRQUI() { runOnUiThread(new Runnable() { public void run() { mIrqImage.setImageDrawable(getResources().getDrawable(R.drawable.led_green_md)); } }); } }
ç°¡åã«ããããã«ãã¢ããªã±ãŒã·ã§ã³ã¯Android Studioã§äœæããïŒsdkãæ£ããèšå®ããããšãå¿ããªãã§ãã ãã-4.4.4ã§åéããŠããŸãïŒãäžèŠãªãã®ã¯ãã¹ãŠåãé¢ãããŸãããããããã«ãã«ã¯Android.mkãåã³äœ¿çšãããŸããããã¯ç§ã«ãšã£ãŠã¯ãã®ããã«èŠããŸãã
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_FILES := $(addprefix $(LOCAL_PATH)/, res) LOCAL_PACKAGE_NAME := TrickyDemo LOCAL_CERTIFICATE := platform LOCAL_STATIC_JAVA_LIBRARIES := android-support-core-utils-api24 include $(BUILD_PACKAGE)
ã¢ã»ã³ããªã«ééã£ãã©ã€ãã©ãªã®ãšã©ãŒãŸãã¯ãããã®ããã€ãã®æ¬ åŠãå«ãŸããŠããå Žåãout / target / common / obj / SHARED_LIBRARIESã調ã¹ãŠé©åãªååãæ¢ããŸãã
ãã¹ãŠãåéããæ¹æ³
ä»ã§ã¯ããã¹ãŠãåéããã ãã§ããã¿ãŒã²ããããã€ã¹ã®ãã©ã¡ãŒã¿ãŒã¯æ¬¡ã®ãšããã§ããHW
ïŒNexus 7ïŒ2012 grouperïŒ
OSïŒAndroid Kitkat 4.4.4 KTU84P
ã«ãŒãã«ïŒtegra3_android_defconfig 3.1.10-gle42d16
æåã«ãã«ãŒãã«ããã«ãããŸãã
å¿ èŠãªã«ãŒãã«ãœãŒã¹ã¯æ¬¡ã®ãšããã§ãã
git clone https://android.googlesource.com/kernel/tegra.git -b android-tegra3-grouper-3.1-kitkat-mr2
ããããã«ãŒãã«ãæ§ç¯ããããã«å¿ èŠãªããŒã«ãããŠã³ããŒãããŸãã
mkdir arm-eabi-4.6 cd arm-eabi-4.6 git init git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/
ã«ãŒãã«ããã«ãããæ¹æ³ïŒã«ãŒãã«ã®ã«ãŒããã©ã«ããŒã«ããïŒïŒ
ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make tegra3_android_defconfig ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make menuconfig ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make -j4 zImage
ã«ã¹ã¿ã å€æŽãã³ããŒããŠmenuconfigãäœæããåŸãããã€ã¹ãã©ã€ããŒã»ã¯ã·ã§ã³ã«ã¯ãããªãããŒãªæž©åºŠã»ã³ãµãŒçšã«éžæãããã©ã€ããŒãå«ãŸããŠããã¯ãã§ãïŒmenuconfig-äžèšã®ã³ãã³ãã䜿çšããŠãã®æ å ±ãåç §ããŠãã ããïŒãã«ãŒãã«ã¯é«éåããŠããŸããã¢ã»ã³ããªåŸãçµæã®ã€ã¡ãŒãžã¯kernel / tegra / arch / arm / boot / zImageã«ãããŸãã
次ã¯Androidã§ãããœãŒã¹ããAndroid OSããã«ãããã«ã¯ãé·æééå±ããªãããã«åŒ·åãªã³ã³ãã¥ãŒã¿ãŒãšãå€ãã®ãã£ã¹ã¯ã¹ããŒã¹ãå¿ èŠã§ãïŒè©³çŽ°ã¯ãã¡ãïŒãç§ã®å Žåãã¢ã»ã³ããªã¯Ubuntu 14.04 LTS x64ã§è¡ãããŸããïŒWindowsã§ã®ã¢ã»ã³ããªã¯ãµããŒããããŠããŸããïŒã
å¿ èŠãªããã±ãŒãžã®ã€ã³ã¹ããŒã«ããã»ã¹ã«ã€ããŠã¯ãããã§è©³ãã説æããŠããŸãããããã§ç§ã¯ããã«æ¢ãŸããªããå¯äžèŠããŠããã¹ãããšã¯ãç°ãªãããŒãžã§ã³ã®Javaã䜿çšããŠç°ãªãOSããŒãžã§ã³ãæ§ç¯ããããšã§ãïŒAndroid 7ã§ã¯OpenJDK Java 8ãNexus 7ããã³Android 4.xã§ã¯Oracle Java 6ïŒã
Androidããã«ãããåã«ç°å¢ãã»ããã¢ããããã«ã¯ããã¡ãããèªã¿ãã ããã
ãªããžããªãããœãŒã¹ãããŠã³ããŒãããã«ã¯ãGitã®ãã©ã€ããã¯ã§ããRepoã䜿çšããŸããããã«ãããããã«å€ãã®gitãªããžããªãæäœã§ããŸãïŒã€ã³ã¹ããŒã«ã®è©³çŽ°ã¯ãã¡ãïŒãRepoãã€ã³ã¹ããŒã«ããåŸãå°æ¥ã®ãœãŒã¹ããããã©ã«ããŒã«ç§»åããŠããããå®è¡ããŸãã
repo init -u https://android.googlesource.com/platform/manifest -b android-4.4.4_r2 cd .repo repo sync
ããŠã³ããŒãããã»ã¹ã¯çŽ50 GBã§ããŠã³ããŒãããããããéåžžã«æéãããããŸãã
次ã«ãNexusã®ããŒãžã§ã³4.4.4 KTU84Pã®è¿œå ã®ãã€ããªã補é å ããïŒAndroid OSãœãŒã¹ã®ãããã©ã«ããŒã®ã«ãŒãã«ïŒããŠã³ããŒãããŸãã
https://dl.google.com/dl/android/aosp/asus-grouper-ktu84p-b12ce5f7.tgz https://dl.google.com/dl/android/aosp/broadcom-grouper-ktu84p-646d5a68.tgz https://dl.google.com/dl/android/aosp/elan-grouper-ktu84p-742223b3.tgz https://dl.google.com/dl/android/aosp/invensense-grouper-ktu84p-724c855a.tgz https://dl.google.com/dl/android/aosp/nvidia-grouper-ktu84p-e6d581dc.tgz https://dl.google.com/dl/android/aosp/nxp-grouper-ktu84p-27abae08.tgz https://dl.google.com/dl/android/aosp/widevine-grouper-ktu84p-57b01f77.tgz
ãã€ããªã®å 容ã解åããŠæœåºããŸãã
tar -xvf asus-grouper-ktu84p-b12ce5f7.tgz tar -xvf broadcom-grouper-ktu84p-646d5a68.tgz tar -xvf elan-grouper-ktu84p-742223b3.tgz tar -xvf invensense-grouper-ktu84p-724c855a.tgz tar -xvf nvidia-grouper-ktu84p-e6d581dc.tgz tar -xvf nxp-grouper-ktu84p-27abae08.tgz tar -xvf widevine-grouper-ktu84p-57b01f77.tgz rm *.tgz ./extract-asus-grouper.sh ./extract-broadcom-grouper.sh ./extract-elan-grouper.sh ./extract-invensense-grouper.sh ./extract-nvidia-grouper.sh ./extract-nxp-grouper.sh ./extract-widevine-grouper.sh
ãŸããç§ãã¡ã¯åéããŸãïŒ
mkdir nexus cd nexus make clobber ( ) . build/envsetup.sh lunch aosp_grouper-userdebug make -j4
次ã®ã³ãã³ãã䜿çšããŠã以åã®ã¢ã»ã³ããªãåé€ã§ããŸãã
make clobber
ã¢ã»ã³ããªåŸãæçµã€ã¡ãŒãžã¯out / target / product / grouperãã©ã«ããŒïŒsystem.imgãrecovery.imgãramdisk.imgãuserdata.imgïŒã«é 眮ãããŸããã¢ããªã±ãŒã·ã§ã³apkãã¡ã€ã«ã¯ãout / target / product / grouper / obj / APPS / Jdts160demo_intermediates / package.apkã«ãããŸãã
fastbootãä»ããŠç»åãäœæããã³ã¢ããããŒãããŸããã¿ãã¬ããã®FLASHïŒããã©ã«ãã§ã¯ãboot.imgãsystem.imgãrecovery.imgãuserdata.imgãramdisk.imgïŒã«ã¢ããããŒãããå¿ èŠãããç»åãšãã³ã³ãã³ããå«ãandroid-info.txtãã¡ã€ã«ãå«ã.zipã¢ãŒã«ã€ããäœæããŸãã
require board=grouper require version-bootloader=4.23
ããŒãããŒããŒã®ããã©ã«ãããŒãžã§ã³ãåãã§ãªãå Žåã¯ãããããå®æããFactoryã€ã¡ãŒãžã€ã¡ãŒãžãããŠã³ããŒãããŠãããããflash_all.shã¹ã¯ãªãããå®è¡ã§ããŸãããŸããå€æŽãå ¥åããããã®ããŒã¹ã€ã¡ãŒãžãšããŠäœ¿çšããããšãã§ããŸãã
boot.imgãæŽæ°ããã«ã¯ãabootimgããŒã«ãã€ã³ã¹ããŒã«ããå¿ èŠããããŸãã
sudo apt-get install abootimg abootimg --create boot.img -k zImage -r ramdisk.img
abootimgã®ã³ãã³ãã§ã¯ã次ã®ãããªããŒããã©ã¡ãŒã¿ãæå®ã§ããŸãããšã³ã³ãœãŒã«ããããã§ããŸã åäœããŸããã®ã§ãããã§å°çã«ã
fastbootã¢ãŒãã«ç§»åããŸãããªãã·ã§ã³ïŒ
adb rebootããŒãããŒããŒïŒã¿ãã¬ããã®é»æºããªã³ã§ãusbçµç±ã§æ¥ç¶ãããadbã«ãã£ãŠèªèšŒãããŠãã
å ŽåïŒãªãã«ãªã£ãŠããå Žåã¯ãé»æºãã¿ã³ãšé³éãã¿ã³ãæŒããªãããªã³ã«ããŸãã
fastbootã®å¯çšæ§ã確èªããŸãïŒUSBãæ¥ç¶ãããUSBãããã°ãæå¹ã«ãªã£ãŠããŸãïŒã
fastboot devices
次ã«ãã³ãã³ãã®ãªã¹ããå®è¡ããŸãããã¹ãŠãåé€ããå¿ èŠã¯ãŸã£ãããªããå€æŽå¯èœãªéšåã®ã¿ãèš±å¯ãããŸãã
fastboot oem unlock fastboot erase boot fastboot erase cache fastboot erase recovery fastboot erase system fastboot erase userdata fastboot -2 update image.zip
åã®æ®µèœã§äœããééã£ãŠããããšãç解ããæ¹æ³
å®éãã¿ã¹ã¯ãå®äºããããã»ã¹ã§ã¯ã詳现ãæ·±ãæ£çŽã«æŽçããæéãããŸããªãããããã¯ãŒã¯ã®ç©ºãã¹ããŒã¹ã«ããå°ç³ãéãæããŸãããã¿ã¹ã¯ãéããããåŸãäœããã©ã®ããã«ãã©ãã§å®è¡ã§ãããã«ã€ããŠã®åæãšèªã¿åããç°ãªã£ãŠéå§ãããŸãããçµæã¯å°ããªãªã¹ãã§ãïŒ
- OSã®å€æŽã¯ãã¢ã»ã³ããªäžã«èæ
®ãããã«ãŒãã«ãšOSæ§é ã«çŽæ¥ã§ã¯ãªããå€ãã®ãªãŒããŒã¬ã€ãæžã蟌ãããšã«ãããdevices / asus / grouper / ...ãã©ã«ããŒã§è¡ãããšããå§ãããŸããäž»ãªæ
å ±æºãšåãæ§é ããããã¯ã§ãããã©ããããŸãã¯ç¹å®ã®èŠä»¶ããããã©ããã¯å®å
šã«ã¯ããããŸããã§ããã
- audio-jack . , , - . ããªãã¡ïŒ
- uart-1 & uart-4 debug, pinmux GPIO not_used/disabled.
- Google usb-uart FTDI , 50, .
- make menuconfig uart uart`. , .
- fastboot bootloader command line . , , .
- , . system