5.21.2009

USB On-The-Go Basics - Cable

在 USB 的世界裡,有分Host跟Peripheral ,任何的傳輸動作都是 Host先 send 封包出來,所以知道誰是 Host 誰是 Peripheral 是很重要的在USB的protocol 裡, 再因為 USB cable 是決定OTG devcie是當A-Device(Host)還是B-Device(peripheral)的依據,所以我們先認識一下USB OTG 的 cable.



  1. 一般標準的USB cable 的頭就有分A 頭跟B 頭,A頭就是接Host, B頭就是接peripheral.





  2. 後來多了一個叫 mini-USB 的B頭,是給像隨身聽這類小產品用的,也都只是當peripheral




  3. 後來又出了一個叫 OTG mini-AB receptacle.就是專給 OTG deivce 用的母頭. 它可接mini-A公頭也可接mini-B公頭



  4. 下圖上方,是Camera 當 Host, Printer當 Peripheral ,它可能的功能就是讓Camera 裡的照片直接透過Printer印出。下方那一個,兩個Camera 都是用OTG Mini-AB 母頭,也就是可插A頭也可插B頭,那要怎麼區分誰是 Host? 誰是 Peripheral呢? 就是靠 cable 的接頭來決定。在A頭跟B頭裡面的 ID pin 是不同的,A頭裡 ID是pull low, B頭裡ID是pull hi。而 device 再依照ID pin 來決定自己是Host 還是peripheral。



  5. 因為Mini-AB母頭可接A or B, 在這樣的情形下 user 有可能會接反,如下圖,原本Camera是要當Host,因為接反插入 B 頭而變為 Peripheral, 而 Printer 也是一樣,那不就不能動了。好再OTG 架構也想到這個問題,所以提供了一個叫 Host Negotiation Protocol (HNP) 來結決這個問題,讓 user 不用換 calbe 也可繼續用。






5.12.2009

設計者的悲哀

在吉米丘的blog 上看到的,好笑到不行



真是道盡設計者的悲哀

5.11.2009

USB OTG flow at Qaulcomm

BOOL Cl13611OTG::ISTProcess() @ Cl13611.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\otg)

-> BOOL Cl13611OTG::UpdateInput()
-> BOOL Cl13611OTG::EventNotification()

-> BOOL USBOTG::EventNotification() @ Usbotg.cpp (\wm\public\common\oak\drivers\usbotg\mdd)

do

-> BOOL Cl13611OTG::UpdateInput() @ Cl13611.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\otg)
-> USBOTG_STATES USBOTG::StateChange(USBOTG_STATES usbOtgState) @ Usbotg.cpp (\wm\public\common\oak\drivers\usbotg\mdd)
-> BOOL USBOTG::EnterState(USBOTG_STATES usbOtgState)
if (OTG state has changed)

BOOL Cl13611OTG::NewStateAction(USBOTG_STATES usbOtgState , USBOTG_OUTPUT usbOtgOutput) @Cl13611.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\otg)

-> BOOL Cl13611OTG::SetupTransCtr(USBOTG_OUTPUT usbOtgOutput)

if(usbOtgOutput.bit.drv_vbus)(A-device is driving Vbus)

turn on Vbus

else

turn off Vbus


if (usbOtgOutput.bit.loc_sof = true) (loccal device is generating activity on the bus)

LoadUnloadHCD(TRUE)

else

LoadUnloadUSBFN(TRUE)

-> BOOL USBOTG::NewStateAction(USBOTG_STATES usbOtgState , USBOTG_OUTPUT usbOtgOutput )


else
break while()



while(OTG state != USBOTG_states_unknow)


5.05.2009

USB and Chargering

在USBIF 裡有測到下列狀況的VBUS電流:
1. USB 有認到時的電流: 100mA/500mA
2. USB 沒(還沒)認到時的電流: 100mA/500mA
3. 電腦 suspend 時的電流: 2.5mA
4. 正常運作時的電流: 100mA/500mA

所以有兩個地方,USB 需通知charging driver
1. 電腦認到 USB 時
2. 電腦 suspend 時

*以下是 Quallcomm 認到通知的flow(quallcomm 是以有被設了new address 才開始充電)

UfnPdd_SetAddress() @Msm_usbhs.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\fn)

-> UfnPDD_NotifyChargerCurrent(), 帶pdd->dChargerCurrent進去,init 在 s_deviceRegParams @Msm_subhs.cpp, 目前設定100, 意思是 100 mA

-> DeviceIOControl 帶IOCTL_OTG_SET_REMOTE_DEV_A_INFO 參數,和要充的電流大小
Cl13611OTG::IOControl() @Cl13611.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\otg)

這裡會收到 IOCTL_OTG_SET_REMOTE_DEV_A_INFO , pBufIn 就是要充的電流大小

*以下是 電腦 suspend 通知的 flow
UfnPDD_NotifySuspend() @Msm_usbhs.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\fn)
這個不是WINAPI ,找不到從哪裡call 來,可能是 Quallcomm 的lib

-> UfnPDD_NotifyChargerCurrent(), 帶current 變數進去,如果是suspend, current=0
如果不是,current=100

-> DeviceIOControl 帶IOCTL_OTG_SET_REMOTE_DEV_A_INFO 參數,和要充的電流大小
Cl13611OTG::IOControl() @Cl13611.cpp (\wm\platform\qcmsm\src\drivers\usb\highspeed\otg)

這裡會收到 IOCTL_OTG_SET_REMOTE_DEV_A_INFO , pBufIn 就是要充的電流大小

4.29.2009

add external jar file as part of a system library

FWIW, it appears that if you add the external jar file as part of a user library, specify that the user library is a system library, and add the user library to the Java Build Path then it will work.


For completeness to do this you can do the following:
1. Right-click the project in Eclipse and select "Build Path -> Add Libraries...".
2. Select User Library from the list and click Next.
3. Click the "User Libraries..." button.
4. Click "New..." in the User Libraries dialog.
5. Give the user library a name and select the System library checkbox and click OK.
6. Highlight the newly added user library in the list and click the "Add JARs..." button and add the desired jar files.
7. Click OK on the User Libraries dialog.
8. Make sure the new user library is checked in the Add Library dialog and click Finish.

4.28.2009

AVD(Android Viutual Device)的注意事項

當你正在選擇system image target for 你的AVD時,請心存下列三項

Keep these points in mind when you are selecting a system image target for your AVD:

1. target 的 API level 很重要,因為你的應用程式沒辦法在比它的 API Level 還少的 system image 上跑,在應用程式的 manifest 檔的 attribute 裡的 minSdkVersion 有定義.想知道更多資訊有關 system API Level 跟應用程式 minSdkVersion 之間的關系,請看Specifying Minimum System API Version

The API Level of the target is important, because your application will not be able to run on a system image whose API Level is less than that required by your application, as specified in the minSdkVersion attribute of the application's manifest file. For more information about the relationship between system API Level and application minSdkVersion, see Specifying Minimum System API Version.

2. 強烈鼓勵,建立至少一個AVD, 它的 API Level 大於你的應用程式, 因為這可以讓你測試你的應用程式的forward-compatibility. forward-compatibility 的測試可用來保證,使用者透過system update download 你的應用程式之後,可以運作正常。

Creating at least one AVD that uses a target whose API Level is greater than that required by your application is strongly encouraged, because it allows you to test the forward-compatibility of your application. Forward-compatibility testing ensures that, when users who have downloaded your application receive a system update, your application will continue to function normally.

3. 如果你的應用程式宣告了一個 user-library 元件在它的 manifest 檔,那這個應用程式只能跑在有外部 library 的 system image.如果你要你的應用程試跑在你建立的 AVD 上, 請確定應用程式的 uses-library element 還有所選的 system image target 有無 includes 那個 library.

If your application declares a uses-library element in its manifest file, the application can only run on a system image in which that external library is present. If you want your application to run on the AVD you are creating, check the application's uses-library element and select a system image target that includes that library.

4.27.2009

實作一個假的 character driver 在emulator 上跑

大致上的做法就是將自己 build 的 kernel 放到 emulator, 然後再將自製假的 driver 放進 emulator 裡跑

1. 將 .config 從模擬器裡抓出來
因為模擬器裡的 kernel 的 CONFIG_MODULE 是關掉的。所以我們需要將它打開,否則不能 insmod 。
開了之後就要重 build 出 kernel image (zImage). 而要 build kernel 就需要模擬器裡的 kernel 的 .config。

先下載 Android 的 sdk , 因為 emulator 就在 SDK 裡,可到下面網址 download(註:我是以SDK 1.1為例子,SDK 1.5 還沒試過)


http://developer.android.com/sdk/1.1_r1/index.html



a. 解壓之後,執行 emulator


D:\workplace\android-sdk-windows-1.1_r1\tools>emulator


b. 在 emulator 執行的狀況下抓/proc/config.gz ,放到 \pulldata下


D:\workplace\android-sdk-windows-1.1_r1\tools>adb pull /proc/config.gz



2. 改 CONFIG_MODULES
將 config.gz 解壓之後放到 /mydroid/kernel 下, 然後找 CONFIG_MODULES ,並改為


CONFIG_MODULES=y



3. 改 kernel 的 Makefile
因為我們是跑 arm archtecture ,所以要改 tool chain
在 /mydroid/kernel/Makefile 裡,將 ARCH 跟 CROSS_COMPILE 改為下面


ARCH ?=arm
CROSS_COMPILE ?=../prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-


然後將 LDFLAGS_BUILD_ID mark 掉,如下


# LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,$(call ld-option, -Wl$(comma)--build-id,))


4. build kernel
(1) 先清乾淨


$make mrproper


(2) 將第二步驟的 config 改名為 .config ,放到 /mydroid/kernel 下
(3) make


$make


一開始會問你一些問題,一律都答N
build 完之後,會在 /mydroid/kernel/arch/arm/boot 找到 image, 叫 zImage

5. build fake driver
(1) 從 Linux Device Driver Programming 一書裡,copy 個範例 driver, source C 如下


/*
* devone.c
*
*/
#include linux/init.h
#include linux/module.h
#include linux/types.h
#include linux/kernel.h
#include linux/fs.h
#include linux/cdev.h
#include asm/uaccess.h

MODULE_LICENSE("Dual BSD/GPL");

static int devone_devs = 1; /* device count */
static int devone_major = 0; /* dynamic allocation */
static int devone_minor = 0;
static struct cdev devone_cdev;

ssize_t devone_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int i;
unsigned char val = 0xff;
int retval;

for (i = 0 ; i < count ; i++) {
if (copy_to_user(&buf[i], &val, 1)) {
retval = -EFAULT;
goto out;
}
}

retval = count;
out:
return (retval);
}

struct file_operations devone_fops = {
.read = devone_read,
};

static int devone_init(void)
{
dev_t dev = MKDEV(devone_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;

alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, "devone");
if (alloc_ret)
goto error;
devone_major = major = MAJOR(dev);

cdev_init(&devone_cdev, &devone_fops);
devone_cdev.owner = THIS_MODULE;
devone_cdev.ops = &devone_fops;
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, devone_minor), 1);
if (cdev_err)
goto error;

printk(KERN_ALERT "devone driver(major %d) installed.\n", major);

return 0;

error:
if (cdev_err == 0)
cdev_del(&devone_cdev);

if (alloc_ret == 0)
unregister_chrdev_region(dev, devone_devs);

return -1;
}

static void devone_exit(void)
{
dev_t dev = MKDEV(devone_major, 0);

cdev_del(&devone_cdev);
unregister_chrdev_region(dev, devone_devs);

printk(KERN_ALERT "devone driver removed.\n");

}

module_init(devone_init);
module_exit(devone_exit);





Makefile 如下,你需要改 KERNELDIR ,這需要指到已經好的kernel,還有命令之前一定要是"tab"


KERNELDIR=/home/arik/Workspace/aydroid/kernel/
PWD := $(shell pwd)

obj-m := devone.o

modules:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules


clean:
rm -rf *.o *~ core.depend .*.cmd *.ko *.mod.c .tmp_versions




6. 將我們 build 的 zImage 放進 emulator 上跑


D:\workplace\android-sdk-windows-1.1_r1\tools>emulator.exe -kernel D:\workplace\
android-sdk-windows-1.1_r1\tools\lib\images\zImage


-kernel 後面的參數就是指到之前 build 出來的 kernel image

7. 把 busybox 放進 emulator
因為待會要用 busybox 的 mknod 指令( emulator 好像沒有), 所以要將 busybox 放進 emulator
(1) 讓 emulator 的 /system 這個目錄變成可 read/write. 開另一個 cmd 下


D:\workplace\android-sdk-windows-1.1_r1\tools>adb remount
* daemon not running. starting it now *
* daemon started successfully *
remount succeeded


(2) 下載 busybox


http://benno.id.au/android/busybox


(3) 把 busybox 放進 emulator


D:\workplace\android-sdk-windows-1.1_r1\tools>adb push busybox /system/bin
1703 KB/s (0 bytes in 1745016.001s)


(4) 更改 busybox 權限,否則不能用


D:\workplace\android-sdk-windows-1.1_r1\tools>adb shell
# chmod 566 /system/bin/busybox
chmod 566 /system/bin/busybox
#_



8. 把 ko 檔放進 emulator
跟放 busybox 一樣, 把假 driver 放進, 注意 emulator 裡只有 /system 目錄才可對外讀寫, 這裡我是放在 /system/bin


D:\workplace\android-sdk-windows-1.1_r1\tools>adb push devone.ko /system/bin
117 KB/s (0 bytes in 3763.000s)



9. 載入 module
跟在 linux 下做的一樣


D:\workplace\android-sdk-windows-1.1_r1\tools>adb shell
# busybox insmod /system/bin/devone.ko
busybox insmod /system/bin/devone.ko
# busybox lsmod
busybox lsmod
Module Size Used by Not tainted
devone 2624 0
#


10. 將 driver 掛上
掛上之前,要先知道它的 major id


# busybox cat /proc/devices
busybox cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
90 mtd
128 ptm
136 pts
252 devone
253 ttyS
254 rtc

Block devices:
1 ramdisk
7 loop
31 mtdblock
43 nbd
179 mmc
#


知道是 252 之後,就 mknod 上去


# busybox mknod /dev/devone c 252 0
busybox mknod /dev/devone c 252 0
# busybox ls -l /dev/devone
busybox ls -l /dev/devone
crw-rw-rw- 1 0 0 252, 0 Apr 30 02:26 /dev/devone
#