打印

嵌入式Linux 2.6 内核专题

Linux2.6 驱动设计――从 2.4 到 2.6
作者 Ray

RTEMS版权所有,转载请注明来源ray@rtems" target="_blank">www.rtems.net,作者ray@rtems

Linux 2.6 和 2.4 的比较我不想废话,总体来说 2.6 功能更强,但是资源消耗更多。

由于 2.6 内核在驱动框架,底层调用上和 2.4 内核有很多差别,所以本文主要是为程序员提供 2.4 到 2.6 迁移的指导。

2.6 和 2.4 主要的不同在于

? 内核的 API 变化,增加了不少新功能(例如 mem pool )

? 提供 sysfs 用于描述设备树

? 驱动模块从 .o 变为 .ko

移植 hello word
下面是一个最简单的 2.4 驱动:

#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
int init_module(void)
{
printk(KERN_INFO "Hello, world\n");
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye cruel world\n");
}

2.6的hello world版本!

#include < linux/module.h>
#include < linux/config.h>
#include < linux/init.h>
MODULE_LICENSE("GPL");// 新,否则有 waring, 去掉了 #define MODULE, 自动定义
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);// 必须!!
module_exit(hello_exit); // 必须!!

注意,在 2.4 中 module_init 不是必须的,只要驱动的初始化函数以及析沟函数命名使用了缺省的 init_module 和 cleanup_module

编译生成:
2.4

gcc -D__KERNEL__ -DMODULE -I/usr/src/linux- 2.4.27 /include -O2 -c testmod.c

2.6

makefile 中要有 obj-m:= hello.o

然后:

make -C /usr/src/linux- 2.6.11 SUBDIRS=$PWD modules (当然简单的 make 也可以)

哈哈够简单!!

其他不同:
计数器:
以前 2.4 内核使用 MOD_INC_USE_COUNT 增加计数例如:

void

inc_mod(void)

{

MOD_INC_USE_COUNT;

} /* end inc_mod */


/************************************************************************

* Calculator DEC

************************************************************************/

void

dec_mod(void)

{

MOD_DEC_USE_COUNT;

} /* end dec_mod */

现在这个也过时了 !!

2.6 ,用户函数要加载模块,使用:

int try_module_get(&module);

函数卸载模块使用

module_put()

而驱动中不必显示定义 inc 和 dec

没有 kdev_t 了
现在都流行用 dev_t 了 , 而且是 32 位的

结构体初始化
老版本使用:

static struct some_structure = {

field1: value,

field2: value

};

现在流行用:

static struct some_structure = {

.field1 = value,

.field2 = value,

...

};

malloc.h
要用核态内存?用 <linux/slab.h> 好了,

内存池
内存管理变化不大,添加了memory pool*(#include<linux/mempool.h> )。(现在什么都是pool,内存 线程 ....)这是为块设备提供的,使用mempool最大的优点是分配内存不会错,也不会等待(怎么这个也和RTEMS学)。对于embed的设备还是有些用处的。标准调用方式:

mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data);

使用mempool的函数 :

mempool_alloc_t / mempool_free_t

mempool_alloc_slab / mempool_free_slab

mempool_alloc / mempool_free

mempool_resize



结构体赋值
以前,驱动中结构体赋值使用:

static struct some_structure = {

field1: value,

field2: value

};


现在要用:

static struct some_structure = {

.field1 = value,

.field2 = value,

...

};

例如 :

static struct file_operations yourdev_file_ops = {

.open = yourdev_open,

.read = yourdev_read_file,

.write = yourdev_write_file,

};


min() , max()
不少程序员定义自己的 min 和 max 宏,大家也知道宏不安全, Linux 定义了 min 和 max 函数(注意不是模板函数,需要自己制定比较类型!)

原型变化
call_usermodehelper()

request_module()

函数原型变化了,用到的赶快查 !!!

Devfs
唉,还没怎么用,就过时了的技术,这就是 linux 。不是我们落伍,是世界变化快


字符设备
2.6 中主从设备编号不再局限于原来的 8bit

register_chrdev() 可以升级为:

int register_chrdev_region(dev_t from, // 设备号 unsigned count, // 注册号 char *name); // 名称

该函数的动态版本(不知道主设备号时使用)

int alloc_chrdev_region(dev_t *dev, unsigned baseminor,

unsigned count, char *name);


新的 file_operations
register_chrdev_region 没有使用 register_chrdev_region 参数,因为设备现在使用 struct cdev 来定义他在 <linux/cdev.h> 中定义。

struct cdev {

struct kobject kobj;

struct module *owner;

struct file_operations *ops;

struct list_head list;

dev_t dev;

unsigned int count;

};

使用时首先需要分配空间: struct cdev *cdev_alloc(void);

然后对其初始化:

void cdev_init(struct cdev *cdev, struct file_operations *fops);

cdev 使用 kobject_set_name 设置名称:例如:

struct cdev *my_cdev = cdev_alloc(); kobject_set_name(&cdev->kobj, "my_cdev%d", devnum);

此后就可以使用 int cdev_add(struct cdev *cdev, dev_t dev, unsigned count); 将 cdev 加入到系统中。

删除 cdev 使用

void cdev_del(struct cdev *cdev);

对于没有使用 cdev_add 添加的 cdev 使用 kobject_put(&cdev->kobj); 删除 也就是使用: struct kobject *cdev_get(struct cdev *cdev); void cdev_put(struct cdev *cdev);

太极链;
struct inode -> i_cdev -> cdev

这样就从 inode 链接到 cdev


驱动体系:
/dev 到 /sys

/dev 也过时了,设备文件都跑到 /sys 里了!

# cd /sys

# ls

block bus class devices firmware kernel module power

:neutral:
知到了2.6内核的好处,很想在以后的开发中用2.6内核。但是不知道从2.4到2.6驱动的变化有多大,驱动是不是要自己一个个改?
我初学只能写些简单的驱动,或参考别人的驱动来开发。这种情况用2.6内核搞驱动是不是难度很大?
希望做过驱动移植的高手关照。
E mail:hfl9703@sohu.com QQ:124110671

TOP


欢迎交流!
qq:  124110671
E mail:hfl9703@sohu.com QQ:124110671

TOP

驱动

[quote:feac028354="jackzheng2002"]论坛里面的帖子就有这个的讨论,可以去看看。
如果驱动搞不定,可以发我邮箱,我可以发我的给你作为参考。


[quote:feac028354="buaazy"]我的问题解决了,使我的文件系统没有烧对地址,终于跑起来了。下面我将尝试驱动Cs8900,已经做好的大侠,能不能给写一个step by step, 在这里先谢了。
Linux version 2.6.11.7 (root@linux) (gcc version 3.4.1) #7 Sun Jul 3 11:44:49 CS
T 2005
CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。
id: unknown user name: 0
[@fa /]#[/quote][/quote]


想问问jackzheng2002 介绍2.6驱动的论坛在哪里?

TOP

编译了2.6.10的内核,到板子上跑出现如下问题:
Start linux ..
Setup linux parameters at 0x30000100
Uncompressing Linux..........................................................Linux version 2.6.10 (root@localhost.localdomain) (gcc version 3.4.4) #2 Mon6CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
CPU: D VIVT write-back cache
CPU: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Machine: SMDK2410
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2410A (id 0x32410002)
S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 MHz
S3C2410 Clock control, (c) 2004 Simtec Electronics
Built 1 zonelists
Kernel command line: initrd=0x30800000,0x440000  root=/dev/ram init=/linuxrc0irq: clearing pending status 00000008
irq: clearing subpending status 00000002
PID hash table entries: 512 (order: 9, 8192 bytes)
timer tcon=00500000, tcnt a509, tcfg 00000200,00000000, usec 00001e4c
Console: colour dummy device 80x30
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 64MB = 64MB total
Memory: 57744KB available (2150K code, 433K data, 100K init)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
CPU: Testing write buffer coherency: ok
checking if image is initramfs...it isn't (no cpio magic); looks like an inidFreeing initrd memory: 4352K
NET: Registered protocol family 16
S3C2410: Initialising architecture
SCSI subsystem initialized
usbcore: registered new driver usbfs
usbcore: registered new driver hub
NetWinder Floating Point Emulator V0.97 (double precision)
devfs: 2004-01-31 Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
JFFS2 version 2.2. (C) 2001-2003 Red Hat, Inc.
Console: switching to colour frame buffer device 80x25
fb0: Virtual frame buffer device, using 1024K of video memory
s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2410
s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2410
s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2410
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize
loop: loaded (max 8 devices)
elevator: using anticipatory as default io scheduler
nbd: registered device at major 43
PPP generic driver version 2.4.2
NET: Registered protocol family 24
SLIP: version 0.8.4-NET3.019-NEWTTY (dynamic channels, max=256).
CSLIP: code copyright 1989 Regents of the University of California.
SLIP linefill/keepalive option.
Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
INFTL: inftlcore.c $Revision: 1.18 $, inftlmount.c $Revision: 1.15 $
physmap flash device: 9c0000 at 540000
phys_mapped_flash: Found 1 x16 devices at 0x0 in 16-bit bank
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
cfi_cmdset_0001: Erase suspend on write enabled
RedBoot partition parsing not available
mtd: Giving out device 0 to phys_mapped_flash
Initializing USB Mass Storage driver...
usbcore: registered new driver usb-storage
USB Mass Storage support registered.
mice: PS/2 mouse device common for all mice
Advanced Linux Sound Architecture Driver Version 1.0.6 (Sun Aug 15 07:17:53 .ALSA device list:
  No soundcards found.
NET: Registered protocol family 2
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 4096 bind 8192)
NET: Registered protocol family 1
NET: Registered protocol family 17
RAMDISK: Compressed image found at block 0
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
Mounted devfs on /dev
Freeing init memory: 100K
mount /etc as ramfs
re-create the /etc/mtab entries
reboot(magic=00000000
)...
然后就不动咯
向各位达人讨教

TOP

[求助]VFS: Mounted root (yaffs filesystem) readonly??

正常启动应该是VFS: Mounted root (yaffs filesystem)
但我的怎么是VFS: Mounted root (yaffs filesystem) readonly.
请大侠们帮忙!!

完整的启动信息如下:
## Starting application at 0x21000000 ...
Uncompressing Linux............................................................. done, booting the kernel.
Linux version 2.6.11.10 (root@localhost.localdomain) (gcc version 3.3) #31 Thu Mar 16 13:13:05 CST 2006
CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Machine: ATMEL AT91RM9200
Warning: bad configuration page, trying to continue
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists
Kernel command line: root=/dev/mtdblock/7 rootfstype=yaffs console=ttyS0,115200 mem=64M
PID hash table entries: 512 (order: 9, 8192 bytes)
Console: colour dummy device 80x30
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 64MB = 64MB total
Memory: 62848KB available (1540K code, 318K data, 88K init)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
NetWinder Floating Point Emulator V0.97 (double precision)
devfs: 2004-01-31 Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
JFFS2 version 2.2. (NAND) (C) 2001-2003 Red Hat, Inc.
yaffs Mar 16 2006 11:17:34 Installing.
AT91 Real Time Clock driver.
AT91RM9200 RTC init
AT91 Watchdog Timer enabled (5 seconds)
ttyS0 at MMIO 0xfefff200 (irq = 1) is a AT91_SERIAL
ttyS1 at MMIO 0xfefc0000 (irq = 6) is a AT91_SERIAL
ttyS2 at MMIO 0xfefc4000 (irq = 7) is a AT91_SERIAL
ttyS3 at MMIO 0xfefc8000 (irq =  is a AT91_SERIAL
ttyS4 at MMIO 0xfefcc000 (irq = 9) is a AT91_SERIAL
io scheduler noop registered
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
loop: loaded (max 8 devices)
eth0: Link now 100-FullDuplex
eth0: AT91 ethernet at 0xfefbc000 int=24 100-FullDuplex (12:34:56:78:9a:00)
eth0: Davicom 9196 PHY (Copper)
NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c $Revision: 1.40 $
at91rm9200: flash mapping: 800000 at 10000000
at91rm9200 falsh: Found 1 x16 devices at 0x0 in 16-bit bank
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
cfi_cmdset_0001: Erase suspend on write enabled
Creating 5 MTD partitions on "falsh":
0x00000000-0x00020000 : "uBoot"
ftl_cs: FTL header not found.
0x00020000-0x00160000 : "Linux Kernel"
ftl_cs: FTL header not found.
0x00160000-0x005e0000 : "Linux Ramdisk"
ftl_cs: FTL header not found.
0x005e0000-0x007e0000 : "User Space"
ftl_cs: FTL header not found.
0x007e0000-0x00800000 : "uBoot Env"
ftl_cs: FTL header not found.
RDY = 1
RDY = 1
SmartMedia card inserted.
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Creating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00c00000 : "AT91 NAND partition 1, kernel"
ftl_cs: FTL header not found.
0x00c00000-0x01100000 : "AT91 NAND partition 2, filesystem"
ftl_cs: FTL header not found.
0x01100000-0x04000000 : "AT91 NAND partition 3, storage"
mice: PS/2 mouse device common for all mice
NET: Registered protocol family 2
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
NET: Registered protocol family 1
NET: Registered protocol family 17
yaffs: dev is 31457287 name is "mtdblock7"
yaffs: Attempting MTD mount on 30.7, "mtdblock7"
VFS: Mounted root (yaffs filesystem) readonly.
Mounted devfs on /dev
Freeing init memory: 88K
/etc/rc.d/rc.sysinit: 37: cannot create /var/run/utmp: Read-only file system
touch: /var/log/wtmp: Read-only file system
chgrp: /var/run/utmp: Read-only file system
chgrp: /var/log/wtmp: Read-only file system
chmod: /var/run/utmp: Read-only file system
chmod: /var/log/wtmp: Read-only file system
eth0: Setting MAC address to 00:02:02:03:03:00
eth0: Link now 100-FullDuplex
at91_led: version magic '2.6.11.10 ARMv4 gcc-4.0' should be '2.6.11.10 ARMv4 gcc-3.3'
insmod: cannot insert `/home/test/at91_led.ko': Invalid module format (-1): Exec format error
/etc/rc.d/rc.sysinit: 65: cannot create /var/log/dmesg: Read-only file system

什么原因造成 VFS: Mounted root (yaffs filesystem) readonly
都弄好几天了,MTD都选遍了,还解决不掉,急哦!!

TOP

没有人研究2。6内核了吗?

TOP

移植s3c2410的声卡,从2.6.11到2.6.16

就是前面superlp的版本,到2.6.16上面时,需要做几个改动:
Porting uda1341 sound card from 2.6.11 to 2.6.16

Step 1:
        download s3c2410_uda1341_superlp.c for 2.6.11 , and put it in directory: sound/driver/

Step 2:
        modify
        for file:       sound/driver/Kconfig
                config CONFIG_SND_s3c2410_uda1341
                tristate "s3c2410 uda1341"
                depends on SND
                help
                  Say Y here to include support for s3c2410_usa1341 sound.

                  To compile this driver as a module, choose M here: the module
                  will be called snd-uda1341.
        sound/driver/Makefile
                obj-$(CONFIG_CONFIG_SND_s3c2410_uda1341) += s3c2410-uda1341_superlp.o
Step 3:
        modify the original file s3c2410_uda1341_superlp.c
                a.      iis_base = (void*)S3C24XX_VA_IIC
                b.      change clk_use to clk_enable
                c.      change verfy_area to access_ok
        modify file  arch/arm/mach-s3c2410/s3c2410.c
                static struct map_desc s3c2410_iodesc[] __initdata = {
              IODESC_ENT(USBHOST),
              IODESC_ENT(CLKPWR),
              IODESC_ENT(LCD),
              IODESC_ENT(TIMER),
              IODESC_ENT(ADC),
              IODESC_ENT(WATCHDOG),
              IODESC_ENT(IIS),
                }
Step 4:
        make menuconfig,and select this driver "s3c2410 uda1341"
        make
        copy arch/arm/boot/zImage to the s3c2410 board
Step 4:
        mknod -m 777 dev/dsp c 14 3
        mknod -m 777 dev/mixer c 14 0
Step 5:
        test
                cat sample.wav >/dev/dsp
关于移植到2.6.16的其他问题,比如网卡,可以到我的blog来看看:
http://blog.donews.com/qiaolin/category/97102.aspx

TOP

Why 2.6? You are using the cross-dev-platform, the version of host has no impact....

If you just mean kernel upgrade, just googing... Not a difficult one... But what whould be noticed is backup your original kernel image  

TOP

我现在碰到了一个问题,在2442上移植yaffs2。使用了large page。
如果使用cramfs文件系统,没有任何问题;但选择了yaffs,却报错:"unable to mount devfs, err: -2" 。现在唯一的区别就是cmdline,cramfs: root=/dev/mtdblock2 rootfstype=cramfs ro noinitrd console=ttySAC1;
yaffs: cramfs: root=/dev/mtdblock2 rootfstype=yaffs rw noinitrd console=ttySAC1  
我被此问题困扰了两周,一直得不到解决。你可以帮我看看嘛?

TOP

:"unable to mount devfs, err: -2"

It is saying you got error in devfs...

TOP

dwkkfekoa,
我和你的问题一样,你解决了吗

TOP

我用的s3c44b0
可不可以移植2.6内核?
学习linux没其他原因 只是为了做一些更具挑战性的事情!

TOP

我的开发板的USB (2.0和1.1)都只能部分识别,无法创建sda等设备.而且这个问题不是简单的在usb/storage/unusual_devs.h中添加对应USB存储设备的信息就能解决的.
我开发版的USB接口芯片是PHILIPS的ISP1561,所用内核是2.6.11的.
以下是对内核中USB驱动代码的跟踪过程:
storage_probe --> usb_stor_acquire_resource --> usb_stor_control_tread --> us->proto_handler -->
usb_stor_transparemt_scsi_command -->usb_stor_invoke_transport --> us->transport --> usb_stor_Bulk_transport --> usb_stor_bulk_transfer_sg --> usb_stor_bulk_transfer_buf --> usb_stor_msg_common --> wait_for_completion .到此,已经进入了内核的核心层了,根据添加打印信息调试发现,执行了函数wait_for_completion后us->flags 这个表示出现不正常的值.

有USB方面的高手,就帮忙一起分析一下好吗?

TOP

arm9 偶买不起 只有arm7(s3c44b0) 还是向老师借的
学习linux没其他原因 只是为了做一些更具挑战性的事情!

TOP

我想请问一下 ,在LINUX-2.6.11的USB 驱动程序中, 当你插入一个U盘进行识别时,会调用usb/storage/usb.c中usb_stor_acquire_resource 函数,该函数定义如下:
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us)      
{                                                                                                               
        int p;

        us->current_urb = usb_alloc_urb(0, GFP_KERNEL);                                                //分配URB结构对象空间
        if (!us->current_urb) {
                US_DEBUGP("URB allocation failed\n");
                return -ENOMEM;
        }

        /* Lock the device while we carry out the next two operations */
        down(&us->dev_semaphore);

        /* For bulk-only devices, determine the max LUN value */
        if (us->protocol == US_PR_BULK) {
                p = usb_stor_Bulk_max_lun(us);
                if (p < 0) {
                        up(&us->dev_semaphore);
                        return p;
                }
                us->max_lun = p;
        }

        /* Just before we start our control thread, initialize
         * the device if it needs initialization */
        if (us->unusual_dev->initFunction)
                us->unusual_dev->initFunction(us);

        up(&us->dev_semaphore);

        /*
         * Since this is a new device, we need to register a SCSI
         * host definition with the higher SCSI layers.
         */
        us->host = scsi_host_alloc(&usb_stor_host_template, sizeof(us));
        if (!us->host) {
                printk(KERN_WARNING USB_STORAGE
                        "Unable to allocate the scsi host\n");
                return -EBUSY;
        }

        /* Set the hostdata to prepare for scanning */
        us->host->hostdata[0] = (unsigned long) us;

        /* Start up our control thread */
        p = kernel_thread(usb_stor_control_thread, us, CLONE_VM);
        if (p < 0) {
                printk(KERN_WARNING USB_STORAGE
                       "Unable to start control thread\n");
                return p;
        }
        us->pid = p;

        /* Wait for the thread to start */
        wait_for_completion(&(us->notify));

        return 0;
}

这个函数定义中有这么一步:
p = usb_stor_Bulk_max_lun(us);
注释说这主要是对批量的设备(U盘等),得到最大逻辑单元值.我查了一下,好象在SCSI协议模型中,每个逻辑单元用来操作SCSI设备,但还是不是很懂.

请问各位高手,LUN到底是什么东西,有什么用?在USB识别过程中获取LUN值有什么用啊?
为什么我多数U盘获得的LUN值都是0呢?

usb_stor_Bulk_max_lun函数在usb/storage/transport.c中定义为
/*
* Bulk only transport
*/

/* Determine what the maximum LUN supported is */
int usb_stor_Bulk_max_lun(struct us_data *us)
{
        int result;

        /* issue the command */
        result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
                                 US_BULK_GET_MAX_LUN,
                                 USB_DIR_IN | USB_TYPE_CLASS |
                                 USB_RECIP_INTERFACE,
                                 0, us->ifnum, us->iobuf, 1, HZ);

        US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
                  result, us->iobuf[0]);

        /* if we have a successful request, return the result */
        if (result > 0)
                return us->iobuf[0];

        /*
         * Some devices (i.e. Iomega Zip100) need this -- apparently
         * the bulk pipes get STALLed when the GetMaxLUN request is
         * processed.   This is, in theory, harmless to all other devices
         * (regardless of if they stall or not).
         */
        if (result == -EPIPE) {
                usb_stor_clear_halt(us, us->recv_bulk_pipe);
                usb_stor_clear_halt(us, us->send_bulk_pipe);
        }

        /*
         * Some devices don't like GetMaxLUN.  They may STALL the control
         * pipe, they may return a zero-length result, they may do nothing at
         * all and timeout, or they may fail in even more bizarrely creative
         * ways.  In these cases the best approach is to use the default
         * value: only one LUN.
         */
        return 0;
}

TOP