Apr 28, 2008

S3C2440, USB in Linux

他媽的USB似乎根本就沒啟動

帥哥的測試:
GPH10 控制小 port:0 是打開 1 是關掉
GPH8 控制大 port: 1 是打開 0 是關掉

送電之後就可以用了...他媽的白費兩個禮拜

05/23 :
之前請正哥寄信去要電路圖都不屌我們

COLOR 打電話去就要到了

更正
GPH8 : USB_HOST_EN

GPH10 : nUSB_PULL_UP_EN

USB_HOST_EN 控制 USB_H_5V --> USB HOST PORT 的供電 (大PORT)

nUSB_PULL_UP_EN 控制 USB_C_D+ --> MINI USB 的供電 (小PORT)


掛載usb隨身碟


掛載的時候說找不到codepage:要把kernel重編
-> File systems

-> Native language support (NLS [=y])

把需要用的codepage & charset 加進去

driver message:
usb 1-1: new full speed USB device using s3c2410-ohci and address 3
usb 1-1: configuration #1 chosen from 1 choice
scsi2 : SCSI emulation for USB Mass Storage devices
usb 1-1: Product: USB Mass Storage Device
usb 1-1: Manufacturer: USBest Technology
usb 1-1: SerialNumber: 000000000001CC

scsi 2:0:0:0: Direct-Access     UDISK    PDU01-4G 81H2.0  0.00 PQ: 2
sd 2:0:0:0: [sdb] 7897087 512-byte hardware sectors (4043 MB)
sd 2:0:0:0: [sdb] Write Protect is off
sd 2:0:0:0: [sdb] Assuming drive cache: write through
sd 2:0:0:0: [sdb] 7897087 512-byte hardware sectors (4043 MB)
sd 2:0:0:0: [sdb] Write Protect is off
sd 2:0:0:0: [sdb] Assuming drive cache: write through
sdb:<7>usb-storage: queuecommand called sdb1
sd 2:0:0:0: [sdb] Attached SCSI removable disk
sd 2:0:0:0: Attached scsi generic sg1 type 0

[busybox] # mkdir /mnt/usb

[busybox] # mount -t auto /dev/sdb1 /mnt/usb

隨身碟可以用了

rt73 USB Driver for Linux


rt73 (USB) CVS hourly tarball: rt73-CVS

解開之後,進去Modules這個資料夾

設定目標kernel位置:
export KERNDIR=/home2/fyodor/kernel/linux-2.6.24.3

他的Makefile會用KERNDIR裡面的CC & CROSS_COMPILE設定

然後簡單make,就編出了rt73.ko

但是有一個warning
!!! WARNING: Module file much too big (>1MB)
!!! Check your kernel settings or use 'strip'
*** Module rt73.ko built successfully

# arm-linux-strip rt73.ko

就變小了

=========================

另一個編譯方式  (2.6.25出來啦!)
make armdebug ARCH=arm \

CROSS_COMPILE=/usr/local/arm/3.4.1/bin/arm-linux- \

KERNDIR=/home2/fyodor/kernel/linux-2.6.25

status code :


s3c2410-ohci s3c2410-ohci: urb c2704ec0 path 1 ep0in 5ec20000 cc 5
--> status -62

all status code : include/asm-generic/errno.h
#define ETIME           62      /* Timer expired */

Document of error codes : Documentation/usb/error-codes.txt

-ETIME (**)
No response packet received within the prescribed bus turn-around time.  This error may instead be reported as -EPROTO or -EILSEQ.

利用 simtec-usb driver (discarded)


問題:gpio的設定方式,是否適合2440?

(已解決,看下面)

2440 WinCE bootloader裡面初始化usb的gpio:從GPH10送出0
// Enable USB_PULLUP on GPIO PIN (tied to USB D+) & set high
pIOPregs->GPHCON &= ~(3 << 20);    // clear GPH10
pIOPregs->GPHCON |=  (1 << 20);    // config as output
pIOPregs->GPHUP  |=  (1 << 10);    // pullup disabled
pIOPregs->GPHDAT &=  ~(1 << 10);    // set Low (Enable)

GPHCON[21:20] = 01 (GPH10=OUTPUT)

GPHUP[10] = 1         (DISABLE PULL UP)

GPHDAT[10] = 0

初始化


參考usb-simtec.c裡的初始化:
int usb_simtec_init(void)
{
printk("USB Power Control, (c) 2004 Simtec Electronics\n");
s3c_device_usb.dev.platform_data = &usb_simtec_info;


s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB4, 1);
return 0;
}

(simtec用GPB4,在CoAsia2440上不適用!)

然後加在smdk2440里...

[arch/arm/mach-s3c2440/mach-smdk2440.c]
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(16934400);
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));

s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB4, 1);

}

宣告


[arch/arm/plat-s3c24xx/devs.c]

統統加進去
static unsigned int power_state[2];

static void usb_s3c2440_powercontrol(int port, int to)
{
pr_debug("usb_s3c2440_powercontrol(%d,%d)\n", port, to);

power_state[port] = to;

if (power_state[0] && power_state[1])
s3c2410_gpio_setpin(S3C2410_GPB4, 0);
else
s3c2410_gpio_setpin(S3C2410_GPB4, 1);
}

static irqreturn_t usb_s3c2440_ocirq(int irq, void *pw)
{
struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;

if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
pr_debug("usb_simtec: over-current irq (oc detected)\n");
s3c2410_usb_report_oc(info, 3);
} else {
pr_debug("usb_simtec: over-current irq (oc cleared)\n");

s3c2410_usb_report_oc(info, 0);
}

return IRQ_HANDLED;
}

static void usb_s3c24440_enableoc(struct s3c2410_hcd_info *info, int on)
{
int ret;

if (on) {
ret = request_irq(IRQ_USBOC, usb_s3c2440_ocirq,
IRQF_DISABLED | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
"USB Over-current", info);
if (ret != 0) {
printk(KERN_ERR "failed to request usb oc irq\n");
}
} else {
free_irq(IRQ_USBOC, info);
}
}

static struct s3c2410_hcd_info usb_smdk2440_info = {
.port[0]        = {
.flags  = S3C_HCDFLG_USED
},
.port[1]        = {
.flags  = S3C_HCDFLG_USED
},
.power_control  = usb_s3c2440_powercontrol,
.enable_oc      = usb_s3c24440_enableoc,

};

EXPORT_SYMBOL(usb_smdk2440_info);

資料結構:


[include/asm-arm/arch-s3c2410/usb-control.h]
struct s3c2410_hcd_info {
struct usb_hcd          *hcd;
struct s3c2410_hcd_port port[2];

void            (*power_control)(int port, int to);
void            (*enable_oc)(struct s3c2410_hcd_info *, int on);
void            (*report_oc)(struct s3c2410_hcd_info *, int ports);
};

struct s3c2410_hcd_port {
unsigned char   flags;
unsigned char   power;
unsigned char   oc_status;
unsigned char   oc_changed;
};

ohci-s3c2410需要設定gpio


確定解決方法了,帥哥很暴力

在vivi裡面寫了一個程式去try gpio

終於找到控制usb host送電的gpio

(在這兒 s3c2440 USB Storage )

帥哥跟小黑的作法是套用simtec的driver

但是simtec的driver裡面還有over-current的保護機制

因為不確定CoAsia2440的電路是拉哪個gpio去控制usb oc

所以我決定不用simtec的driver

只簡單的在ohci-s3c2410.c的probe & remove裡面控制送電

static int usb_hcd_s3c2410_probe
printk("usb : set power gpio for USB\n");
s3c2410_gpio_cfgpin(S3C2410_GPH10, S3C2410_GPH10_OUTP);
s3c2410_gpio_pullup(S3C2410_GPH10, 0);
s3c2410_gpio_setpin(S3C2410_GPH10, 0);
s3c2410_gpio_cfgpin(S3C2410_GPH8, S3C2410_GPH8_OUTP);
s3c2410_gpio_pullup(S3C2410_GPH8, 1);
s3c2410_gpio_setpin(S3C2410_GPH8, 1);

static void usb_hcd_s3c2410_remove
printk("usb : shutdown power gpio for USB\n");
s3c2410_gpio_cfgpin(S3C2410_GPH10, S3C2410_GPH10_OUTP);
s3c2410_gpio_pullup(S3C2410_GPH10, 1);
s3c2410_gpio_setpin(S3C2410_GPH10, 1);
s3c2410_gpio_cfgpin(S3C2410_GPH8, S3C2410_GPH8_OUTP);
s3c2410_gpio_pullup(S3C2410_GPH8, 0);
s3c2410_gpio_setpin(S3C2410_GPH8, 0);



下面是之前測試的方式,僅當作紀錄

============================================

[include/asm-arm/plat-s3c24xx/devs.h]
extern struct platform_device *s3c24xx_uart_devs[];
extern struct platform_device *s3c24xx_uart_src[];

extern struct s3c2410_hcd_info usb_smdk2440_info;
extern struct platform_device s3c_device_usb;

--

[arch/arm/plat-s3c24xx/devs.c]
/* USB Host Controller */

static struct s3c2410_hcd_info usb_smdk2440_info = {
.port[0]        = {
.flags  = S3C_HCDFLG_USED
},
.port[1]        = {
.flags  = S3C_HCDFLG_USED
},


};

EXPORT_SYMBOL(usb_smdk2440_info);

static struct resource s3c_usb_resource[] = {

.

.

.

struct platform_device s3c_device_usb = {
.name             = "s3c2410-ohci",
.id               = -1,
.num_resources    = ARRAY_SIZE(s3c_usb_resource),
.resource         = s3c_usb_resource,
.dev              = {
.dma_mask = &s3c_device_usb_dmamask,
.coherent_dma_mask = 0xffffffffUL,
.platform_data = &usb_smdk2440_info
}
};

EXPORT_SYMBOL(s3c_device_usb);

--

終於make過了

幹~星期一去學校再弄

/proc/bus/usb  is empty


kernel_src/Documentation/usb/proc_usb_info.txt

**NOTE**: If /proc/bus/usb appears empty, and a host controller
driver has been linked, then you need to mount the filesystem.

/etc/fstab 增加一行:
none  /proc/bus/usb  usbfs  defaults  0  0

/proc/bus/usb/devices:USB device information

debugfs & usbmon


# mount -t debugfs none_debugs /sys/kernel/debug

如果usbmon有load起來或是compile-in,/sys/kernel/debug裡面就會有一個usbmon

裡面大概長這樣:

# ls /sys/kernel/debug/usbmon/
0s  0u  1s  1t  1u

數字代表bus number,0 則是所有bus的資訊

所以現在要查看usb bus number:

# cat /proc/bus/usb/devices

注意T開頭那一行
T:  Bus=01 .......

所以usb在bus #1

或是乾脆listen all buses...

# cat /sys/kernel/debug/usbmon/0u > /tmp/all.usbmon.out


mdev in busybox


mdev是busybox裡用來取代udev的device 管理架構,節省資源且設定簡單

busybox mdev document

Mdev has two primary uses: initial population and dynamic updates.
Both require sysfs support in the kernel and have it mounted at /sys.
For dynamic updates, you also need to have hotplugging enabled in your kernel.


官方建議的mdev 初始化方式

Here's a typical code snippet from the init script:

[1] mount -t sysfs sysfs /sys

[2] echo /bin/mdev > /proc/sys/kernel/hotplug

[3] mdev -s
Of course, a more "full" setup would entail executing this before the previous

code snippet:

[4] mount -t tmpfs mdev /dev

[5] mkdir /dev/pts

[6] mount -t devpts devpts /dev/pts


初始設定的說明


[1] 執行mdev 之前務必要先掛載/sys
[2] 告訴kernel 把hotplug 交給mdev 去處理
[3] mdev 藉由掃瞄 /sys/class、/sys/block 來找到device, 然後在/dev 下建立device 節點
2[4-6] 不重要


# cat /etc/fstab
proc        /proc                 proc     defaults    0   0
none       /tmp                  ramfs   defaults    0   0
mdev      /dev                   ramfs   defaults    0   0
sysfs       /sys                    sysfs   defaults     0   0
none       /proc/bus/usb   usbfs   defaults     0  0

Wireless USB Adapter


我拿到的無線網路USB是ASUS的WL167G

裡面用的chip是Ralink的rt73(就是我們台灣的雷凌科技啦)

廠商就提供linux driver囉~  kernel版本2.4, 2.6都有

(剛才發現kernel裡面也有提供module)

kernel_rt73

測試過在桌機linux上運作正常

現在要port到板子上

參考資料


gmane.linux.usb.general:專門討論Linux USB Driver開發的 Mailing List


Linux Hotplugging

Linux USB

Busybox mdev document

Linux設備驅動程序學習(15)- Linux設備模型(熱插拔、mdev 與 firmware)

Linux那些事兒 之 我是Sysfs

0 comments:

Post a Comment