Commit d3ba3a7d authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 0abcbadd c89122b1
...@@ -35,7 +35,10 @@ void dpm_resume(void) ...@@ -35,7 +35,10 @@ void dpm_resume(void)
struct list_head * entry = dpm_off.next; struct list_head * entry = dpm_off.next;
struct device * dev = to_device(entry); struct device * dev = to_device(entry);
list_del_init(entry); list_del_init(entry);
resume_device(dev);
if (!dev->power.prev_state)
resume_device(dev);
list_add_tail(entry,&dpm_active); list_add_tail(entry,&dpm_active);
} }
} }
......
...@@ -12,9 +12,11 @@ ...@@ -12,9 +12,11 @@
static void runtime_resume(struct device * dev) static void runtime_resume(struct device * dev)
{ {
dev_dbg(dev, "resuming\n");
if (!dev->power.power_state) if (!dev->power.power_state)
return; return;
resume_device(dev); if (!resume_device(dev))
dev->power.power_state = 0;
} }
......
...@@ -39,16 +39,13 @@ int suspend_device(struct device * dev, u32 state) ...@@ -39,16 +39,13 @@ int suspend_device(struct device * dev, u32 state)
{ {
int error = 0; int error = 0;
if (dev->bus && dev->bus->suspend) dev_dbg(dev, "suspending\n");
dev->power.prev_state = dev->power.power_state;
if (dev->bus && dev->bus->suspend && !dev->power.power_state)
error = dev->bus->suspend(dev,state); error = dev->bus->suspend(dev,state);
if (!error) {
list_del(&dev->power.entry);
list_add(&dev->power.entry,&dpm_off);
} else if (error == -EAGAIN) {
list_del(&dev->power.entry);
list_add(&dev->power.entry,&dpm_off_irq);
}
return error; return error;
} }
...@@ -81,11 +78,18 @@ int device_suspend(u32 state) ...@@ -81,11 +78,18 @@ int device_suspend(u32 state)
while(!list_empty(&dpm_active)) { while(!list_empty(&dpm_active)) {
struct list_head * entry = dpm_active.prev; struct list_head * entry = dpm_active.prev;
struct device * dev = to_device(entry); struct device * dev = to_device(entry);
if ((error = suspend_device(dev,state))) { error = suspend_device(dev,state);
if (error != -EAGAIN)
goto Error; if (!error) {
else list_del(&dev->power.entry);
error = 0; list_add(&dev->power.entry,&dpm_off);
} else if (error == -EAGAIN) {
list_del(&dev->power.entry);
list_add(&dev->power.entry,&dpm_off_irq);
} else {
printk(KERN_ERR "Could not suspend device %s: "
"error %d\n", kobject_name(&dev->kobj), error);
goto Error;
} }
} }
Done: Done:
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/io.h> #include <asm/io.h>
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pnp.h> #include <linux/pnp.h>
#include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
......
...@@ -23,22 +23,25 @@ ...@@ -23,22 +23,25 @@
* - Switched to private locks not lock_kernel * - Switched to private locks not lock_kernel
* - Used ioremap/writew/readw * - Used ioremap/writew/readw
* - Added NOWAYOUT support * - Added NOWAYOUT support
* * 4/12 - 2002 Changes by Rob Radez <rob@osinvestor.com>
* 4/12 - 2002 Changes by Rob Radez <rob@osinvestor.com> * - Change comments
* - Change comments * - Eliminate fop_llseek
* - Eliminate fop_llseek * - Change CONFIG_WATCHDOG_NOWAYOUT semantics
* - Change CONFIG_WATCHDOG_NOWAYOUT semantics * - Add KERN_* tags to printks
* - Add KERN_* tags to printks * - fix possible wdt_is_open race
* - fix possible wdt_is_open race * - Report proper capabilities in watchdog_info
* - Report proper capabilities in watchdog_info * - Add WDIOC_{GETSTATUS, GETBOOTSTATUS, SETTIMEOUT,
* - Add WDIOC_{GETSTATUS, GETBOOTSTATUS, SETTIMEOUT, * GETTIMEOUT, SETOPTIONS} ioctls
* GETTIMEOUT, SETOPTIONS} ioctls * 09/8 - 2003 Changes by Wim Van Sebroeck <wim@iguana.be>
* 09/8 - 2003 Changes by Wim Van Sebroeck <wim@iguana.be> * - cleanup of trailing spaces
* - cleanup of trailing spaces * - added extra printk's for startup problems
* - added extra printk's for startup problems * - use module_param
* - use module_param * - made timeout (the emulated heartbeat) a module_param
* - made timeout (the emulated heartbeat) a module_param * - made the keepalive ping an internal subroutine
* - made the keepalive ping an internal subroutine * 3/27 - 2004 Changes by Sean Young <sean@mess.org>
* - set MMCR_BASE to 0xfffef000
* - CBAR does not need to be read
* - removed debugging printks
* *
* This WDT driver is different from most other Linux WDT * This WDT driver is different from most other Linux WDT
* drivers in that the driver will ping the watchdog by itself, * drivers in that the driver will ping the watchdog by itself,
...@@ -65,8 +68,16 @@ ...@@ -65,8 +68,16 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define OUR_NAME "sc520_wdt"
#define PFX OUR_NAME ": "
/* /*
* The SC520 can timeout anywhere from 492us to 32.21s. * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
*
* 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s
* 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s
*
* We will program the SC520 watchdog for a timeout of 2.01s.
* If we reset the watchdog every ~250ms we should be safe. * If we reset the watchdog every ~250ms we should be safe.
*/ */
...@@ -83,25 +94,33 @@ static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ t ...@@ -83,25 +94,33 @@ static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ t
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
/* #ifdef CONFIG_WATCHDOG_NOWAYOUT
* AMD Elan SC520 timeout value is 492us times a power of 2 (0-7) static int nowayout = 1;
* #else
* 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s static int nowayout = 0;
* 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s #endif
*/
#define TIMEOUT_EXPONENT ( 1 << 3 ) /* 0x08 = 2.01s */
/* #define MMCR_BASE_DEFAULT 0xfffef000 */
#define MMCR_BASE_DEFAULT ((__u16 *)0xffffe)
#define OFFS_WDTMRCTL ((unsigned int)0xcb0)
#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */
#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */
#define OUR_NAME "sc520_wdt" module_param(nowayout, int, 0);
#define PFX OUR_NAME ": " MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
#define WRT_DOG(data) *wdtmrctl=data /*
* AMD Elan SC520 - Watchdog Timer Registers
*/
#define MMCR_BASE 0xfffef000 /* The default base address */
#define OFFS_WDTMRCTL 0xCB0 /* Watchdog Timer Control Register */
/* WDT Control Register bit definitions */
#define WDT_EXP_SEL_01 0x0001 /* [01] Time-out = 496 us (with 33 Mhz clk). */
#define WDT_EXP_SEL_02 0x0002 /* [02] Time-out = 508 ms (with 33 Mhz clk). */
#define WDT_EXP_SEL_03 0x0004 /* [03] Time-out = 1.02 s (with 33 Mhz clk). */
#define WDT_EXP_SEL_04 0x0008 /* [04] Time-out = 2.03 s (with 33 Mhz clk). */
#define WDT_EXP_SEL_05 0x0010 /* [05] Time-out = 4.07 s (with 33 Mhz clk). */
#define WDT_EXP_SEL_06 0x0020 /* [06] Time-out = 8.13 s (with 33 Mhz clk). */
#define WDT_EXP_SEL_07 0x0040 /* [07] Time-out = 16.27s (with 33 Mhz clk). */
#define WDT_EXP_SEL_08 0x0080 /* [08] Time-out = 32.54s (with 33 Mhz clk). */
#define WDT_IRQ_FLG 0x1000 /* [12] Interrupt Request Flag */
#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */
#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */
static __u16 *wdtmrctl; static __u16 *wdtmrctl;
...@@ -112,15 +131,6 @@ static unsigned long wdt_is_open; ...@@ -112,15 +131,6 @@ static unsigned long wdt_is_open;
static char wdt_expect_close; static char wdt_expect_close;
static spinlock_t wdt_spinlock; static spinlock_t wdt_spinlock;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static int nowayout = 1;
#else
static int nowayout = 0;
#endif
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/* /*
* Whack the dog * Whack the dog
*/ */
...@@ -147,7 +157,7 @@ static void wdt_timer_ping(unsigned long data) ...@@ -147,7 +157,7 @@ static void wdt_timer_ping(unsigned long data)
} }
/* /*
* Utility routines * Utility routines
*/ */
static void wdt_config(int writeval) static void wdt_config(int writeval)
...@@ -157,10 +167,10 @@ static void wdt_config(int writeval) ...@@ -157,10 +167,10 @@ static void wdt_config(int writeval)
/* buy some time (ping) */ /* buy some time (ping) */
spin_lock_irqsave(&wdt_spinlock, flags); spin_lock_irqsave(&wdt_spinlock, flags);
dummy=readw(wdtmrctl); /* ensure write synchronization */ dummy=readw(wdtmrctl); /* ensure write synchronization */
writew(0xAAAA, wdtmrctl); writew(0xAAAA, wdtmrctl);
writew(0x5555, wdtmrctl); writew(0x5555, wdtmrctl);
/* make WDT configuration register writable one time */ /* unlock WDT = make WDT configuration register writable one time */
writew(0x3333, wdtmrctl); writew(0x3333, wdtmrctl);
writew(0xCCCC, wdtmrctl); writew(0xCCCC, wdtmrctl);
/* write WDT configuration register */ /* write WDT configuration register */
...@@ -168,7 +178,7 @@ static void wdt_config(int writeval) ...@@ -168,7 +178,7 @@ static void wdt_config(int writeval)
spin_unlock_irqrestore(&wdt_spinlock, flags); spin_unlock_irqrestore(&wdt_spinlock, flags);
} }
static void wdt_startup(void) static int wdt_startup(void)
{ {
next_heartbeat = jiffies + (timeout * HZ); next_heartbeat = jiffies + (timeout * HZ);
...@@ -176,28 +186,43 @@ static void wdt_startup(void) ...@@ -176,28 +186,43 @@ static void wdt_startup(void)
timer.expires = jiffies + WDT_INTERVAL; timer.expires = jiffies + WDT_INTERVAL;
add_timer(&timer); add_timer(&timer);
wdt_config(WDT_ENB | WDT_WRST_ENB | TIMEOUT_EXPONENT); /* Start the watchdog */
wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
printk(KERN_INFO PFX "Watchdog timer is now enabled.\n"); printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
return 0;
} }
static void wdt_turnoff(void) static int wdt_turnoff(void)
{ {
if (!nowayout) { /* Stop the timer */
/* Stop the timer */ del_timer(&timer);
del_timer(&timer);
wdt_config(0); /* Stop the watchdog */
printk(KERN_INFO PFX "Watchdog timer is now disabled...\n"); wdt_config(0);
}
printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
return 0;
} }
static void wdt_keepalive(void) static int wdt_keepalive(void)
{ {
/* user land ping */ /* user land ping */
next_heartbeat = jiffies + (timeout * HZ); next_heartbeat = jiffies + (timeout * HZ);
return 0;
}
static int wdt_set_heartbeat(int t)
{
if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
return -EINVAL;
timeout = t;
return 0;
} }
/* /*
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos)
...@@ -207,10 +232,8 @@ static ssize_t fop_write(struct file * file, const char * buf, size_t count, lof ...@@ -207,10 +232,8 @@ static ssize_t fop_write(struct file * file, const char * buf, size_t count, lof
return -ESPIPE; return -ESPIPE;
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) if(count) {
{ if (!nowayout) {
if (!nowayout)
{
size_t ofs; size_t ofs;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the magic character
...@@ -248,11 +271,11 @@ static int fop_open(struct inode * inode, struct file * file) ...@@ -248,11 +271,11 @@ static int fop_open(struct inode * inode, struct file * file)
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode * inode, struct file * file)
{ {
if(wdt_expect_close == 42) if(wdt_expect_close == 42) {
wdt_turnoff(); wdt_turnoff();
else { } else {
del_timer(&timer); printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); wdt_keepalive();
} }
clear_bit(0, &wdt_is_open); clear_bit(0, &wdt_is_open);
wdt_expect_close = 0; wdt_expect_close = 0;
...@@ -262,8 +285,7 @@ static int fop_close(struct inode * inode, struct file * file) ...@@ -262,8 +285,7 @@ static int fop_close(struct inode * inode, struct file * file)
static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
static struct watchdog_info ident= static struct watchdog_info ident = {
{
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "SC520", .identity = "SC520",
...@@ -307,10 +329,9 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -307,10 +329,9 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if(get_user(new_timeout, (int *)arg)) if(get_user(new_timeout, (int *)arg))
return -EFAULT; return -EFAULT;
if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ if(wdt_set_heartbeat(new_timeout))
return -EINVAL; return -EINVAL;
timeout = new_timeout;
wdt_keepalive(); wdt_keepalive();
/* Fall through */ /* Fall through */
} }
...@@ -351,81 +372,59 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, ...@@ -351,81 +372,59 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
* turn the timebomb registers off. * turn the timebomb registers off.
*/ */
static struct notifier_block wdt_notifier= static struct notifier_block wdt_notifier = {
{
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
static void __exit sc520_wdt_unload(void) static void __exit sc520_wdt_unload(void)
{ {
wdt_turnoff(); if (!nowayout)
wdt_turnoff();
/* Deregister */ /* Deregister */
misc_deregister(&wdt_miscdev); misc_deregister(&wdt_miscdev);
iounmap(wdtmrctl);
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
iounmap(wdtmrctl);
} }
static int __init sc520_wdt_init(void) static int __init sc520_wdt_init(void)
{ {
int rc = -EBUSY; int rc = -EBUSY;
unsigned long cbar;
spin_lock_init(&wdt_spinlock); spin_lock_init(&wdt_spinlock);
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
{
timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
timeout);
}
init_timer(&timer); init_timer(&timer);
timer.function = wdt_timer_ping; timer.function = wdt_timer_ping;
timer.data = 0; timer.data = 0;
rc = misc_register(&wdt_miscdev); /* Check that the timeout value is within it's range ; if not reset to the default */
if (rc) if (wdt_set_heartbeat(timeout)) {
{ wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n",
wdt_miscdev.minor, rc); WATCHDOG_TIMEOUT);
}
wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2);
if (!wdtmrctl) {
printk(KERN_ERR PFX "Unable to remap memory\n");
rc = -ENOMEM;
goto err_out_region2; goto err_out_region2;
} }
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) if (rc) {
{
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc); rc);
goto err_out_miscdev; goto err_out_ioremap;
} }
/* get the Base Address Register */ rc = misc_register(&wdt_miscdev);
cbar = inl_p(0xfffc); if (rc) {
printk(KERN_INFO PFX "CBAR: 0x%08lx\n", cbar); printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
/* check if MMCR aliasing bit is set */ WATCHDOG_MINOR, rc);
if (cbar & 0x80000000) {
printk(KERN_INFO PFX "MMCR Aliasing enabled.\n");
wdtmrctl = (__u16 *)(cbar & 0x3fffffff);
} else {
printk(KERN_INFO PFX "!!! WARNING !!!\n"
"\t MMCR Aliasing found NOT enabled!\n"
"\t Using default value of: %p\n"
"\t This has not been tested!\n"
"\t Please email Scott Jennings <smj@oro.net>\n"
"\t and Bill Jennings <bj@oro.net> if it works!\n"
, MMCR_BASE_DEFAULT
);
wdtmrctl = MMCR_BASE_DEFAULT;
}
wdtmrctl = (__u16 *)((char *)wdtmrctl + OFFS_WDTMRCTL);
wdtmrctl = ioremap((unsigned long)wdtmrctl, 2);
if (!wdtmrctl) {
printk (KERN_ERR PFX "Unable to remap memory.\n");
rc = -ENOMEM;
goto err_out_notifier; goto err_out_notifier;
} }
printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
timeout,nowayout); timeout,nowayout);
...@@ -433,8 +432,8 @@ static int __init sc520_wdt_init(void) ...@@ -433,8 +432,8 @@ static int __init sc520_wdt_init(void)
err_out_notifier: err_out_notifier:
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
err_out_miscdev: err_out_ioremap:
misc_deregister(&wdt_miscdev); iounmap(wdtmrctl);
err_out_region2: err_out_region2:
return rc; return rc;
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/scx200.h> #include <linux/scx200.h>
......
...@@ -264,7 +264,7 @@ wdt_init(void) ...@@ -264,7 +264,7 @@ wdt_init(void)
{ {
int ret; int ret;
printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n"); printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
if (timeout < 1 || timeout > 63) { if (timeout < 1 || timeout > 63) {
timeout = WATCHDOG_TIMEOUT; timeout = WATCHDOG_TIMEOUT;
......
...@@ -34,12 +34,4 @@ config EFI_VARS ...@@ -34,12 +34,4 @@ config EFI_VARS
Subsequent efibootmgr releases may be found at: Subsequent efibootmgr releases may be found at:
http://linux.dell.com/efibootmgr http://linux.dell.com/efibootmgr
config SMBIOS
tristate "BIOS SMBIOS table access driver."
help
Say Y or M here if you want to enable access to the SMBIOS table
via driverfs. It exposes /sys/firmware/smbios/ subdirectory tree
containing a binary dump of the SMBIOS table header as well as the SMBIOS
table.
endmenu endmenu
...@@ -3,4 +3,3 @@ ...@@ -3,4 +3,3 @@
# #
obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_SMBIOS) += smbios.o
/*
* linux/drivers/firmware/smbios.c
* Copyright (C) 2004 Dell Inc.
* by Michael Brown <Michael_E_Brown@dell.com>
* vim:noet:ts=8:sw=8:filetype=c:textwidth=80:
*
* BIOS SMBIOS Table access
* conformant to DMTF SMBIOS definition
* at http://www.dmtf.org/standards/smbios
*
* This code takes information provided by SMBIOS tables
* and presents it in sysfs as:
* /sys/firmware/smbios
* |--> /table_entry_point
* |--> /table
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2.0 as published by
* the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "smbios.h"
MODULE_AUTHOR("Michael Brown <Michael_E_Brown@Dell.com>");
MODULE_DESCRIPTION("sysfs interface to SMBIOS information");
MODULE_LICENSE("GPL");
#define SMBIOS_VERSION "1.0 2004-04-19"
struct smbios_device {
struct smbios_table_entry_point table_eps;
unsigned int smbios_table_real_length;
};
/* there shall be only one */
static struct smbios_device the_smbios_device;
#define to_smbios_device(obj) container_of(obj,struct smbios_device,kobj)
/* don't currently have any "normal" attributes, so we don't need a way to
* show them. */
static struct sysfs_ops smbios_attr_ops = { };
static __init int
checksum_eps(struct smbios_table_entry_point *table_eps)
{
u8 *p = (u8 *)table_eps;
u8 checksum = 0;
int i=0;
for (i=0; i < table_eps->eps_length && i < sizeof(*table_eps); ++i) {
checksum += p[i];
}
return( checksum == 0 );
}
static __init int
find_table_entry_point(struct smbios_device *sdev)
{
struct smbios_table_entry_point *table_eps = &(sdev->table_eps);
u32 fp = 0xF0000;
while (fp < 0xFFFFF) {
isa_memcpy_fromio(table_eps, fp, sizeof(*table_eps));
if (memcmp(table_eps->anchor, "_SM_", 4)==0 &&
checksum_eps(table_eps)) {
return 0;
}
fp += 16;
}
printk(KERN_INFO "SMBIOS table entry point not found in "
"0xF0000 - 0xFFFFF\n");
return -ENODEV;
}
static __init int
find_table_max_address(struct smbios_device *sdev)
{
/* break out on one of three conditions:
* -- hit table_eps.table_length
* -- hit number of items that table claims we have
* -- hit structure type 127
*/
u8 *buf = ioremap(sdev->table_eps.table_address,
sdev->table_eps.table_length);
u8 *ptr = buf;
int count = 0, keep_going = 1;
int max_count = sdev->table_eps.table_num_structs;
int max_length = sdev->table_eps.table_length;
while(keep_going && ((ptr - buf) <= max_length) && count < max_count){
if( ptr[0] == 0x7F ) /* ptr[0] is type */
keep_going = 0;
ptr += ptr[1]; /* ptr[1] is length, skip structure */
/* skip strings at end of structure */
while((ptr-buf) < max_length && (ptr[0] || ptr[1]))
++ptr;
/* string area ends in double-null. skip it. */
ptr += 2;
++count;
}
sdev->smbios_table_real_length = (ptr - buf);
iounmap(buf);
if( count != max_count )
printk(KERN_INFO "Warning: SMBIOS table structure count"
" does not match count specified in the"
" table entry point.\n"
" Table entry point count: %d\n"
" Actual count: %d\n",
max_count, count );
if(keep_going != 0)
printk(KERN_INFO "Warning: SMBIOS table does not end with a"
" structure type 127. This may indicate a"
" truncated table.");
if(sdev->smbios_table_real_length != max_length)
printk(KERN_INFO "Warning: BIOS specified SMBIOS table length"
" does not match calculated length.\n"
" BIOS specified: %d\n"
" calculated length: %d\n",
max_length, sdev->smbios_table_real_length);
return sdev->smbios_table_real_length;
}
static ssize_t
smbios_read_table_entry_point(struct kobject *kobj, char *buffer,
loff_t pos, size_t size)
{
struct smbios_device *sdev = &the_smbios_device;
const char *p = (const char *)&(sdev->table_eps);
unsigned int count =
size > sizeof(sdev->table_eps) ?
sizeof(sdev->table_eps) : size;
memcpy( buffer, p, count );
return count;
}
static ssize_t
smbios_read_table(struct kobject *kobj, char *buffer,
loff_t pos, size_t size)
{
struct smbios_device *sdev = &the_smbios_device;
u8 *buf;
unsigned int count = sdev->smbios_table_real_length - pos;
int i = 0;
count = count < size ? count : size;
if (pos > sdev->smbios_table_real_length)
return 0;
buf = ioremap(sdev->table_eps.table_address, sdev->smbios_table_real_length);
if (buf == NULL)
return -ENXIO;
/* memcpy( buffer, buf+pos, count ); */
for (i = 0; i < count; ++i) {
buffer[i] = readb( buf+pos+i );
}
iounmap(buf);
return count;
}
static struct bin_attribute tep_attr = {
.attr = {.name = "table_entry_point", .owner = THIS_MODULE, .mode = 0444},
.size = sizeof(struct smbios_table_entry_point),
.read = smbios_read_table_entry_point,
/* not writeable */
};
static struct bin_attribute table_attr = {
.attr = { .name = "table", .owner = THIS_MODULE, .mode = 0444 },
/* size set later, we don't know it here. */
.read = smbios_read_table,
/* not writeable */
};
/* no default attributes yet. */
static struct attribute * def_attrs[] = { NULL, };
static struct kobj_type ktype_smbios = {
.sysfs_ops = &smbios_attr_ops,
.default_attrs = def_attrs,
/* statically allocated, no release method necessary */
};
static decl_subsys(smbios,&ktype_smbios,NULL);
static void smbios_device_unregister(void)
{
sysfs_remove_bin_file(&smbios_subsys.kset.kobj, &tep_attr );
sysfs_remove_bin_file(&smbios_subsys.kset.kobj, &table_attr );
}
static void __init smbios_device_register(void)
{
sysfs_create_bin_file(&smbios_subsys.kset.kobj, &tep_attr );
sysfs_create_bin_file(&smbios_subsys.kset.kobj, &table_attr );
}
static int __init
smbios_init(void)
{
int rc=0;
printk(KERN_INFO "SMBIOS facility v%s\n", SMBIOS_VERSION );
rc = find_table_entry_point(&the_smbios_device);
if (rc)
return rc;
table_attr.size = find_table_max_address(&the_smbios_device);
rc = firmware_register(&smbios_subsys);
if (rc)
return rc;
smbios_device_register();
return rc;
}
static void __exit
smbios_exit(void)
{
smbios_device_unregister();
firmware_unregister(&smbios_subsys);
}
late_initcall(smbios_init);
module_exit(smbios_exit);
/*
* linux/drivers/firmware/smbios.c
* Copyright (C) 2002, 2003, 2004 Dell Inc.
* by Michael Brown <Michael_E_Brown@dell.com>
* vim:noet:ts=8:sw=8:filetype=c:textwidth=80:
*
* BIOS SMBIOS Table access
* conformant to DMTF SMBIOS definition
* at http://www.dmtf.org/standards/smbios
*
* This code takes information provided by SMBIOS tables
* and presents it in sysfs.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2.0 as published by
* the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _LINUX_SMBIOS_H
#define _LINUX_SMBIOS_H
#include <linux/types.h>
struct smbios_table_entry_point {
u8 anchor[4];
u8 checksum;
u8 eps_length;
u8 major_ver;
u8 minor_ver;
u16 max_struct_size;
u8 revision;
u8 formatted_area[5];
u8 dmi_anchor[5];
u8 intermediate_checksum;
u16 table_length;
u32 table_address;
u16 table_num_structs;
u8 smbios_bcd_revision;
} __attribute__ ((packed));
struct smbios_structure_header {
u8 type;
u8 length;
u16 handle;
} __attribute__ ((packed));
#endif /* _LINUX_SMBIOS_H */
...@@ -118,8 +118,14 @@ config I2C_I810 ...@@ -118,8 +118,14 @@ config I2C_I810
will be called i2c-i810. will be called i2c-i810.
config I2C_IBM_IIC config I2C_IBM_IIC
tristate "IBM IIC I2C" tristate "IBM PPC 4xx on-chip I2C interface"
depends on IBM_OCP && I2C depends on IBM_OCP && I2C
help
Say Y here if you want to use IIC peripheral found on
embedded IBM PPC 4xx based systems.
This driver can also be built as a module. If so, the module
will be called i2c-ibm_iic.
config I2C_IOP3XX config I2C_IOP3XX
tristate "Intel XScale IOP3xx on-chip I2C interface" tristate "Intel XScale IOP3xx on-chip I2C interface"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Support for the IIC peripheral on IBM PPC 4xx * Support for the IIC peripheral on IBM PPC 4xx
* *
* Copyright (c) 2003 Zultys Technologies. * Copyright (c) 2003, 2004 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* *
* Based on original work by * Based on original work by
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include "i2c-ibm_iic.h" #include "i2c-ibm_iic.h"
#define DRIVER_VERSION "2.0" #define DRIVER_VERSION "2.01"
MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -69,14 +69,14 @@ MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)"); ...@@ -69,14 +69,14 @@ MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)");
#endif #endif
#if DBG_LEVEL > 0 #if DBG_LEVEL > 0
# define DBG(x...) printk(KERN_DEBUG "ibm-iic" ##x) # define DBG(f,x...) printk(KERN_DEBUG "ibm-iic" f, ##x)
#else #else
# define DBG(x...) ((void)0) # define DBG(f,x...) ((void)0)
#endif #endif
#if DBG_LEVEL > 1 #if DBG_LEVEL > 1
# define DBG2(x...) DBG( ##x ) # define DBG2(f,x...) DBG(f, ##x)
#else #else
# define DBG2(x...) ((void)0) # define DBG2(f,x...) ((void)0)
#endif #endif
#if DBG_LEVEL > 2 #if DBG_LEVEL > 2
static void dump_iic_regs(const char* header, struct ibm_iic_private* dev) static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
...@@ -455,6 +455,16 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -455,6 +455,16 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
} }
for (i = 0; i < num; ++i){ for (i = 0; i < num; ++i){
if (unlikely(msgs[i].len <= 0)){ if (unlikely(msgs[i].len <= 0)){
if (num == 1 && !msgs[0].len){
/* Special case for I2C_SMBUS_QUICK emulation.
* Although this logic is FAR FROM PERFECT, this
* is what previous driver version did.
* IBM IIC doesn't support 0-length transactions
* (except bit-banging through IICx_DIRECTCNTL).
*/
DBG("%d: zero-length msg kludge\n", dev->idx);
return 0;
}
DBG("%d: invalid len %d in msg[%d]\n", dev->idx, DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
msgs[i].len, i); msgs[i].len, i);
return -EINVAL; return -EINVAL;
...@@ -549,19 +559,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){ ...@@ -549,19 +559,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){
struct ibm_iic_private* dev; struct ibm_iic_private* dev;
struct i2c_adapter* adap; struct i2c_adapter* adap;
struct ocp_func_iic_data* iic_data = ocp->def->additions;
int ret; int ret;
bd_t* bd = (bd_t*)&__res;
if (!iic_data)
printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
ocp->def->index);
if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){ if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){
printk(KERN_CRIT "ibm-iic: failed to allocate device data\n"); printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n",
ocp->def->index);
return -ENOMEM; return -ENOMEM;
} }
memset(dev, 0, sizeof(*dev)); memset(dev, 0, sizeof(*dev));
dev->idx = ocp->num; dev->idx = ocp->def->index;
ocp_set_drvdata(ocp, dev); ocp_set_drvdata(ocp, dev);
if (!(dev->vaddr = ioremap(ocp->paddr, sizeof(struct iic_regs)))){ if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n", printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
dev->idx); dev->idx);
ret = -ENXIO; ret = -ENXIO;
...@@ -570,7 +585,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ ...@@ -570,7 +585,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
init_waitqueue_head(&dev->wq); init_waitqueue_head(&dev->wq);
dev->irq = iic_force_poll ? -1 : ocp->irq; dev->irq = iic_force_poll ? -1 : ocp->def->irq;
if (dev->irq >= 0){ if (dev->irq >= 0){
/* Disable interrupts until we finish intialization, /* Disable interrupts until we finish intialization,
assumes level-sensitive IRQ setup... assumes level-sensitive IRQ setup...
...@@ -589,13 +604,12 @@ static int __devinit iic_probe(struct ocp_device *ocp){ ...@@ -589,13 +604,12 @@ static int __devinit iic_probe(struct ocp_device *ocp){
dev->idx); dev->idx);
/* Board specific settings */ /* Board specific settings */
BUG_ON(dev->idx >= sizeof(bd->bi_iic_fast) / sizeof(bd->bi_iic_fast[0])); dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
dev->fast_mode = iic_force_fast ? 1 : bd->bi_iic_fast[dev->idx];
/* clckdiv is the same for *all* IIC interfaces, /* clckdiv is the same for *all* IIC interfaces,
* but I'd rather make a copy than introduce another global. --ebs * but I'd rather make a copy than introduce another global. --ebs
*/ */
dev->clckdiv = iic_clckdiv(bd->bi_opb_busfreq); dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv); DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
/* Initialize IIC interface */ /* Initialize IIC interface */
...@@ -664,7 +678,7 @@ static void __devexit iic_remove(struct ocp_device *ocp) ...@@ -664,7 +678,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
static struct ocp_device_id ibm_iic_ids[] __devinitdata = static struct ocp_device_id ibm_iic_ids[] __devinitdata =
{ {
{ .vendor = OCP_VENDOR_IBM, .device = OCP_FUNC_IIC }, { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
{ .vendor = OCP_VENDOR_INVALID } { .vendor = OCP_VENDOR_INVALID }
}; };
...@@ -672,7 +686,7 @@ MODULE_DEVICE_TABLE(ocp, ibm_iic_ids); ...@@ -672,7 +686,7 @@ MODULE_DEVICE_TABLE(ocp, ibm_iic_ids);
static struct ocp_driver ibm_iic_driver = static struct ocp_driver ibm_iic_driver =
{ {
.name = "ocp_iic", .name = "iic",
.id_table = ibm_iic_ids, .id_table = ibm_iic_ids,
.probe = iic_probe, .probe = iic_probe,
.remove = __devexit_p(iic_remove), .remove = __devexit_p(iic_remove),
...@@ -685,7 +699,7 @@ static struct ocp_driver ibm_iic_driver = ...@@ -685,7 +699,7 @@ static struct ocp_driver ibm_iic_driver =
static int __init iic_init(void) static int __init iic_init(void)
{ {
printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n"); printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n");
return ocp_module_init(&ibm_iic_driver); return ocp_register_driver(&ibm_iic_driver);
} }
static void __exit iic_exit(void) static void __exit iic_exit(void)
......
...@@ -67,13 +67,18 @@ static struct adapter_parm adapter_parm[] = { ...@@ -67,13 +67,18 @@ static struct adapter_parm adapter_parm[] = {
.getsda = { 0x40, STAT, 1 }, .getsda = { 0x40, STAT, 1 },
.getscl = { 0x08, STAT, 1 }, .getscl = { 0x08, STAT, 1 },
}, },
/* type 4: ADM1025 and ADM1032 evaluation boards */ /* type 4: ADM1032 evaluation board */
{
.setsda = { 0x02, DATA, 1 },
.setscl = { 0x01, DATA, 1 },
.getsda = { 0x10, STAT, 1 },
.init = { 0xf0, DATA, 0 },
},
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
{ {
.setsda = { 0x02, DATA, 1 }, .setsda = { 0x02, DATA, 1 },
.setscl = { 0x01, DATA, 1 }, .setscl = { 0x01, DATA, 1 },
.getsda = { 0x10, STAT, 1 }, .getsda = { 0x10, STAT, 1 },
.init = { 0xf0, DATA, 0 }, /* ADM1025 doesn't need this,
but it doesn't hurt */
}, },
}; };
...@@ -85,4 +90,5 @@ MODULE_PARM_DESC(type, ...@@ -85,4 +90,5 @@ MODULE_PARM_DESC(type,
" 1 = home brew teletext adapter\n" " 1 = home brew teletext adapter\n"
" 2 = Velleman K8000 adapter\n" " 2 = Velleman K8000 adapter\n"
" 3 = ELV adapter\n" " 3 = ELV adapter\n"
" 4 = ADM1025 and ADM1032 evaluation boards\n"); " 4 = ADM1032 evaluation board\n"
" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n");
...@@ -145,6 +145,16 @@ config SENSORS_LM90 ...@@ -145,6 +145,16 @@ config SENSORS_LM90
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called lm90. will be called lm90.
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C && EXPERIMENTAL
select I2C_SENSOR
help
If you say yes here you get support for MAX1619 sensor chip.
This driver can also be built as a module. If so, the module
will be called max1619.
config SENSORS_VIA686A config SENSORS_VIA686A
tristate "VIA686A" tristate "VIA686A"
depends on I2C && EXPERIMENTAL depends on I2C && EXPERIMENTAL
......
...@@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_LM80) += lm80.o ...@@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_LM80) += lm80.o
obj-$(CONFIG_SENSORS_LM83) += lm83.o obj-$(CONFIG_SENSORS_LM83) += lm83.o
obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
......
...@@ -203,11 +203,12 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) ...@@ -203,11 +203,12 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
new_client->driver = &eeprom_driver; new_client->driver = &eeprom_driver;
new_client->flags = 0; new_client->flags = 0;
/* prevent 24RF08 corruption */
i2c_smbus_write_quick(new_client, 0);
/* Now, we do the remaining detection. It is not there, unless you force /* Now, we do the remaining detection. It is not there, unless you force
the checksum to work out. */ the checksum to work out. */
if (checksum) { if (checksum) {
/* prevent 24RF08 corruption */
i2c_smbus_write_quick(new_client, 0);
cs = 0; cs = 0;
for (i = 0; i <= 0x3e; i++) for (i = 0; i <= 0x3e; i++)
cs += i2c_smbus_read_byte_data(new_client, i); cs += i2c_smbus_read_byte_data(new_client, i);
......
/*
* max1619.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
* Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
* Jean Delvare <khali@linux-fr.org>
*
* Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim.
* It reports up to two temperatures (its own plus up to
* one external one). Complete datasheet can be
* obtained from Maxim's website at:
* http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b,
0x4c, 0x4e, I2C_CLIENT_END };
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
SENSORS_INSMOD_1(max1619);
/*
* The MAX1619 registers
*/
#define MAX1619_REG_R_MAN_ID 0xFE
#define MAX1619_REG_R_CHIP_ID 0xFF
#define MAX1619_REG_R_CONFIG 0x03
#define MAX1619_REG_W_CONFIG 0x09
#define MAX1619_REG_R_CONVRATE 0x04
#define MAX1619_REG_W_CONVRATE 0x0A
#define MAX1619_REG_R_STATUS 0x02
#define MAX1619_REG_R_LOCAL_TEMP 0x00
#define MAX1619_REG_R_REMOTE_TEMP 0x01
#define MAX1619_REG_R_REMOTE_HIGH 0x07
#define MAX1619_REG_W_REMOTE_HIGH 0x0D
#define MAX1619_REG_R_REMOTE_LOW 0x08
#define MAX1619_REG_W_REMOTE_LOW 0x0E
#define MAX1619_REG_R_REMOTE_CRIT 0x10
#define MAX1619_REG_W_REMOTE_CRIT 0x12
#define MAX1619_REG_R_TCRIT_HYST 0x11
#define MAX1619_REG_W_TCRIT_HYST 0x13
/*
* Conversions and various macros
*/
#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000)
#define TEMP_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000)
/*
* Functions declaration
*/
static int max1619_attach_adapter(struct i2c_adapter *adapter);
static int max1619_detect(struct i2c_adapter *adapter, int address,
int kind);
static void max1619_init_client(struct i2c_client *client);
static int max1619_detach_client(struct i2c_client *client);
static struct max1619_data *max1619_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
static struct i2c_driver max1619_driver = {
.owner = THIS_MODULE,
.name = "max1619",
.flags = I2C_DF_NOTIFY,
.attach_adapter = max1619_attach_adapter,
.detach_client = max1619_detach_client,
};
/*
* Client data (each client gets its own)
*/
struct max1619_data {
struct i2c_client client;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
u8 temp_input1; /* local */
u8 temp_input2, temp_low2, temp_high2; /* remote */
u8 temp_crit2;
u8 temp_hyst2;
u8 alarms;
};
/*
* Internal variables
*/
static int max1619_id = 0;
/*
* Sysfs stuff
*/
#define show_temp(value) \
static ssize_t show_##value(struct device *dev, char *buf) \
{ \
struct max1619_data *data = max1619_update_device(dev); \
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
}
show_temp(temp_input1);
show_temp(temp_input2);
show_temp(temp_low2);
show_temp(temp_high2);
show_temp(temp_crit2);
show_temp(temp_hyst2);
#define set_temp2(value, reg) \
static ssize_t set_##value(struct device *dev, const char *buf, \
size_t count) \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct max1619_data *data = i2c_get_clientdata(client); \
data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
i2c_smbus_write_byte_data(client, reg, data->value); \
return count; \
}
set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW);
set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH);
set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT);
set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST);
static ssize_t show_alarms(struct device *dev, char *buf)
{
struct max1619_data *data = max1619_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2,
set_temp_low2);
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
set_temp_high2);
static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2,
set_temp_crit2);
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2,
set_temp_hyst2);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
/*
* Real code
*/
static int max1619_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
return i2c_detect(adapter, &addr_data, max1619_detect);
}
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
*/
static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct max1619_data *data;
int err = 0;
const char *name = "";
u8 reg_config=0, reg_convrate=0, reg_status=0;
u8 man_id, chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto exit;
if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
memset(data, 0, sizeof(struct max1619_data));
/* The common I2C client data is placed right before the
MAX1619-specific data. */
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &max1619_driver;
new_client->flags = 0;
/*
* Now we do the remaining detection. A negative kind means that
* the driver was loaded with no force parameter (default), so we
* must both detect and identify the chip. A zero kind means that
* the driver was loaded with the force parameter, the detection
* step shall be skipped. A positive kind means that the driver
* was loaded with the force parameter and a given kind of chip is
* requested, so both the detection and the identification steps
* are skipped.
*/
if (kind < 0) { /* detection */
reg_config = i2c_smbus_read_byte_data(new_client,
MAX1619_REG_R_CONFIG);
reg_convrate = i2c_smbus_read_byte_data(new_client,
MAX1619_REG_R_CONVRATE);
reg_status = i2c_smbus_read_byte_data(new_client,
MAX1619_REG_R_STATUS);
if ((reg_config & 0x03) != 0x00
|| reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) {
dev_dbg(&adapter->dev,
"MAX1619 detection failed at 0x%02x.\n",
address);
goto exit_free;
}
}
if (kind <= 0) { /* identification */
man_id = i2c_smbus_read_byte_data(new_client,
MAX1619_REG_R_MAN_ID);
chip_id = i2c_smbus_read_byte_data(new_client,
MAX1619_REG_R_CHIP_ID);
if ((man_id == 0x4D) && (chip_id == 0x04)){
kind = max1619;
}
}
if (kind <= 0) { /* identification failed */
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).\n", man_id, chip_id);
goto exit_free;
}
if (kind == max1619){
name = "max1619";
}
/* We can fill in the remaining client fields */
strlcpy(new_client->name, name, I2C_NAME_SIZE);
new_client->id = max1619_id++;
data->valid = 0;
init_MUTEX(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the MAX1619 chip */
max1619_init_client(new_client);
/* Register sysfs hooks */
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp2_input);
device_create_file(&new_client->dev, &dev_attr_temp2_min);
device_create_file(&new_client->dev, &dev_attr_temp2_max);
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
exit_free:
kfree(data);
exit:
return err;
}
static void max1619_init_client(struct i2c_client *client)
{
u8 config;
/*
* Start the conversions.
*/
i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE,
5); /* 2 Hz */
config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
if (config & 0x40)
i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG,
config & 0xBF); /* run */
}
static int max1619_detach_client(struct i2c_client *client)
{
int err;
if ((err = i2c_detach_client(client))) {
dev_err(&client->dev, "Client deregistration failed, "
"client not detached.\n");
return err;
}
kfree(i2c_get_clientdata(client));
return 0;
}
static struct max1619_data *max1619_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max1619_data *data = i2c_get_clientdata(client);
down(&data->update_lock);
if ((jiffies - data->last_updated > HZ * 2) ||
(jiffies < data->last_updated) ||
!data->valid) {
dev_dbg(&client->dev, "Updating max1619 data.\n");
data->temp_input1 = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_LOCAL_TEMP);
data->temp_input2 = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_REMOTE_TEMP);
data->temp_high2 = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_REMOTE_HIGH);
data->temp_low2 = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_REMOTE_LOW);
data->temp_crit2 = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_REMOTE_CRIT);
data->temp_hyst2 = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_TCRIT_HYST);
data->alarms = i2c_smbus_read_byte_data(client,
MAX1619_REG_R_STATUS);
data->last_updated = jiffies;
data->valid = 1;
}
up(&data->update_lock);
return data;
}
static int __init sensors_max1619_init(void)
{
return i2c_add_driver(&max1619_driver);
}
static void __exit sensors_max1619_exit(void)
{
i2c_del_driver(&max1619_driver);
}
MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and"
"Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("MAX1619 sensor driver");
MODULE_LICENSE("GPL");
module_init(sensors_max1619_init);
module_exit(sensors_max1619_exit);
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/idr.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
static LIST_HEAD(adapters); static LIST_HEAD(adapters);
static LIST_HEAD(drivers); static LIST_HEAD(drivers);
static DECLARE_MUTEX(core_lists); static DECLARE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr);
int i2c_device_probe(struct device *dev) int i2c_device_probe(struct device *dev)
{ {
...@@ -113,13 +115,19 @@ static struct device_attribute dev_attr_client_name = { ...@@ -113,13 +115,19 @@ static struct device_attribute dev_attr_client_name = {
*/ */
int i2c_add_adapter(struct i2c_adapter *adap) int i2c_add_adapter(struct i2c_adapter *adap)
{ {
static int nr = 0; int id, res = 0;
struct list_head *item; struct list_head *item;
struct i2c_driver *driver; struct i2c_driver *driver;
down(&core_lists); down(&core_lists);
adap->nr = nr++; if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
res = -ENOMEM;
goto out_unlock;
}
id = idr_get_new(&i2c_adapter_idr, NULL);
adap->nr = id & MAX_ID_MASK;
init_MUTEX(&adap->bus_lock); init_MUTEX(&adap->bus_lock);
init_MUTEX(&adap->clist_lock); init_MUTEX(&adap->clist_lock);
list_add_tail(&adap->list,&adapters); list_add_tail(&adap->list,&adapters);
...@@ -151,10 +159,12 @@ int i2c_add_adapter(struct i2c_adapter *adap) ...@@ -151,10 +159,12 @@ int i2c_add_adapter(struct i2c_adapter *adap)
/* We ignore the return code; if it fails, too bad */ /* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap); driver->attach_adapter(adap);
} }
up(&core_lists);
dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr); dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
return 0;
out_unlock:
up(&core_lists);
return res;
} }
...@@ -208,6 +218,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) ...@@ -208,6 +218,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
wait_for_completion(&adap->dev_released); wait_for_completion(&adap->dev_released);
wait_for_completion(&adap->class_dev_released); wait_for_completion(&adap->class_dev_released);
/* free dynamically allocated bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
dev_dbg(&adap->dev, "adapter unregistered\n"); dev_dbg(&adap->dev, "adapter unregistered\n");
out_unlock: out_unlock:
......
...@@ -520,7 +520,7 @@ static struct vortex_chip_info { ...@@ -520,7 +520,7 @@ static struct vortex_chip_info {
{"3c905B-FX Cyclone 100baseFx", {"3c905B-FX Cyclone 100baseFx",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c905C Tornado", {"3c905C Tornado",
PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
{"3c980 Cyclone", {"3c980 Cyclone",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c980C Python-T", {"3c980C Python-T",
......
...@@ -226,11 +226,21 @@ extern struct usb_driver usblp_driver; ...@@ -226,11 +226,21 @@ extern struct usb_driver usblp_driver;
static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
{ {
int retval = usb_control_msg(usblp->dev, int retval;
int index = usblp->ifnum;
/* High byte has the interface index.
Low byte has the alternate setting.
*/
if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) {
index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
}
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT); request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d", dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, len, retval); request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0; return retval < 0 ? retval : 0;
} }
...@@ -440,6 +450,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -440,6 +450,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
goto done; goto done;
} }
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
switch (_IOC_NR(cmd)) { switch (_IOC_NR(cmd)) {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
usbcore-objs := usb.o hub.o hcd.o urb.o message.o \ usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
config.o file.o buffer.o driverfs.o config.o file.o buffer.o sysfs.o
ifeq ($(CONFIG_PCI),y) ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o usbcore-objs += hcd-pci.o
......
...@@ -465,23 +465,24 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -465,23 +465,24 @@ int usb_get_configuration(struct usb_device *dev)
goto err2; goto err2;
memset(dev->rawdescriptors, 0, length); memset(dev->rawdescriptors, 0, length);
buffer = kmalloc(8, GFP_KERNEL); buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
if (!buffer) if (!buffer)
goto err2; goto err2;
desc = (struct usb_config_descriptor *)buffer; desc = (struct usb_config_descriptor *)buffer;
for (cfgno = 0; cfgno < ncfg; cfgno++) { for (cfgno = 0; cfgno < ncfg; cfgno++) {
/* We grab the first 8 bytes so we know how long the whole */ /* We grab just the first descriptor so we know how long
/* configuration is */ * the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, 8); buffer, USB_DT_CONFIG_SIZE);
if (result < 0) { if (result < 0) {
dev_err(ddev, "unable to read config index %d " dev_err(ddev, "unable to read config index %d "
"descriptor\n", cfgno); "descriptor/%s\n", cfgno, "start");
goto err; goto err;
} else if (result < 8) { } else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short " dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, 8, result); "(expected %i, got %i)\n", cfgno,
USB_DT_CONFIG_SIZE, result);
result = -EINVAL; result = -EINVAL;
goto err; goto err;
} }
...@@ -498,7 +499,7 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -498,7 +499,7 @@ int usb_get_configuration(struct usb_device *dev)
bigbuffer, length); bigbuffer, length);
if (result < 0) { if (result < 0) {
dev_err(ddev, "unable to read config index %d " dev_err(ddev, "unable to read config index %d "
"descriptor\n", cfgno); "descriptor/%s\n", cfgno, "all");
kfree(bigbuffer); kfree(bigbuffer);
goto err; goto err;
} }
......
...@@ -243,13 +243,13 @@ extern void usb_hc_died (struct usb_hcd *hcd); ...@@ -243,13 +243,13 @@ extern void usb_hc_died (struct usb_hcd *hcd);
extern struct usb_device *usb_alloc_dev(struct usb_device *parent, extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *, unsigned port); struct usb_bus *, unsigned port);
extern int usb_new_device(struct usb_device *dev); extern int usb_new_device(struct usb_device *dev);
extern void usb_choose_address(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **); extern void usb_disconnect(struct usb_device **);
extern void usb_choose_address(struct usb_device *dev);
extern void usb_release_address(struct usb_device *dev);
/* exported to hub driver ONLY to support usb_reset_device () */ /* exported to hub driver ONLY to support usb_reset_device () */
extern int usb_get_configuration(struct usb_device *dev); extern int usb_get_configuration(struct usb_device *dev);
extern void usb_destroy_configuration(struct usb_device *dev); extern void usb_destroy_configuration(struct usb_device *dev);
extern int usb_set_address(struct usb_device *dev);
/* use these only before the device's address has been set */ /* use these only before the device's address has been set */
#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30)) #define usb_snddefctrl(dev) ((PIPE_CONTROL << 30))
......
...@@ -65,15 +65,15 @@ static inline char *portspeed (int portstatus) ...@@ -65,15 +65,15 @@ static inline char *portspeed (int portstatus)
#endif #endif
/* for dev_info, dev_dbg, etc */ /* for dev_info, dev_dbg, etc */
static inline struct device *hubdev (struct usb_device *dev) static inline struct device *hubdev (struct usb_device *hdev)
{ {
return &dev->actconfig->interface[0]->dev; return &hdev->actconfig->interface[0]->dev;
} }
/* USB 2.0 spec Section 11.24.4.5 */ /* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *dev, void *data, int size) static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
{ {
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT); USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT);
} }
...@@ -81,27 +81,27 @@ static int get_hub_descriptor(struct usb_device *dev, void *data, int size) ...@@ -81,27 +81,27 @@ static int get_hub_descriptor(struct usb_device *dev, void *data, int size)
/* /*
* USB 2.0 spec Section 11.24.2.1 * USB 2.0 spec Section 11.24.2.1
*/ */
static int clear_hub_feature(struct usb_device *dev, int feature) static int clear_hub_feature(struct usb_device *hdev, int feature)
{ {
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ); USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
} }
/* /*
* USB 2.0 spec Section 11.24.2.2 * USB 2.0 spec Section 11.24.2.2
*/ */
static int clear_port_feature(struct usb_device *dev, int port, int feature) static int clear_port_feature(struct usb_device *hdev, int port, int feature)
{ {
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
} }
/* /*
* USB 2.0 spec Section 11.24.2.13 * USB 2.0 spec Section 11.24.2.13
*/ */
static int set_port_feature(struct usb_device *dev, int port, int feature) static int set_port_feature(struct usb_device *hdev, int port, int feature)
{ {
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
} }
...@@ -110,16 +110,15 @@ static int set_port_feature(struct usb_device *dev, int port, int feature) ...@@ -110,16 +110,15 @@ static int set_port_feature(struct usb_device *dev, int port, int feature)
* for info about using port indicators * for info about using port indicators
*/ */
static void set_port_led( static void set_port_led(
struct usb_device *dev, struct usb_device *hdev,
struct usb_hub *hub,
int port, int port,
int selector int selector
) )
{ {
int status = set_port_feature(dev, (selector << 8) | port, int status = set_port_feature(hdev, (selector << 8) | port,
USB_PORT_FEAT_INDICATOR); USB_PORT_FEAT_INDICATOR);
if (status < 0) if (status < 0)
dev_dbg (&hub->intf->dev, dev_dbg (hubdev (hdev),
"port %d indicator %s status %d\n", "port %d indicator %s status %d\n",
port, port,
({ char *s; switch (selector) { ({ char *s; switch (selector) {
...@@ -137,12 +136,12 @@ static void set_port_led( ...@@ -137,12 +136,12 @@ static void set_port_led(
static void led_work (void *__hub) static void led_work (void *__hub)
{ {
struct usb_hub *hub = __hub; struct usb_hub *hub = __hub;
struct usb_device *dev = interface_to_usbdev (hub->intf); struct usb_device *hdev = interface_to_usbdev (hub->intf);
unsigned i; unsigned i;
unsigned changed = 0; unsigned changed = 0;
int cursor = -1; int cursor = -1;
if (dev->state != USB_STATE_CONFIGURED) if (hdev->state != USB_STATE_CONFIGURED)
return; return;
for (i = 0; i < hub->descriptor->bNbrPorts; i++) { for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
...@@ -189,13 +188,13 @@ static void led_work (void *__hub) ...@@ -189,13 +188,13 @@ static void led_work (void *__hub)
} }
if (selector != HUB_LED_AUTO) if (selector != HUB_LED_AUTO)
changed = 1; changed = 1;
set_port_led(dev, hub, i + 1, selector); set_port_led(hdev, i + 1, selector);
hub->indicator[i] = mode; hub->indicator[i] = mode;
} }
if (!changed && blinkenlights) { if (!changed && blinkenlights) {
cursor++; cursor++;
cursor %= hub->descriptor->bNbrPorts; cursor %= hub->descriptor->bNbrPorts;
set_port_led(dev, hub, cursor + 1, HUB_LED_GREEN); set_port_led(hdev, cursor + 1, HUB_LED_GREEN);
hub->indicator[cursor] = INDICATOR_CYCLE; hub->indicator[cursor] = INDICATOR_CYCLE;
changed++; changed++;
} }
...@@ -206,10 +205,10 @@ static void led_work (void *__hub) ...@@ -206,10 +205,10 @@ static void led_work (void *__hub)
/* /*
* USB 2.0 spec Section 11.24.2.6 * USB 2.0 spec Section 11.24.2.6
*/ */
static int get_hub_status(struct usb_device *dev, static int get_hub_status(struct usb_device *hdev,
struct usb_hub_status *data) struct usb_hub_status *data)
{ {
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
} }
...@@ -217,10 +216,10 @@ static int get_hub_status(struct usb_device *dev, ...@@ -217,10 +216,10 @@ static int get_hub_status(struct usb_device *dev,
/* /*
* USB 2.0 spec Section 11.24.2.7 * USB 2.0 spec Section 11.24.2.7
*/ */
static int get_port_status(struct usb_device *dev, int port, static int get_port_status(struct usb_device *hdev, int port,
struct usb_port_status *data) struct usb_port_status *data)
{ {
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
} }
...@@ -278,9 +277,9 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs) ...@@ -278,9 +277,9 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
/* USB 2.0 spec Section 11.24.2.3 */ /* USB 2.0 spec Section 11.24.2.3 */
static inline int static inline int
hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt) hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
{ {
return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0), return usb_control_msg (hdev, usb_rcvctrlpipe (hdev, 0),
HUB_CLEAR_TT_BUFFER, USB_RT_PORT, HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
devinfo, tt, 0, 0, HZ); devinfo, tt, 0, 0, HZ);
} }
...@@ -300,7 +299,7 @@ static void hub_tt_kevent (void *arg) ...@@ -300,7 +299,7 @@ static void hub_tt_kevent (void *arg)
while (!list_empty (&hub->tt.clear_list)) { while (!list_empty (&hub->tt.clear_list)) {
struct list_head *temp; struct list_head *temp;
struct usb_tt_clear *clear; struct usb_tt_clear *clear;
struct usb_device *dev; struct usb_device *hdev;
int status; int status;
temp = hub->tt.clear_list.next; temp = hub->tt.clear_list.next;
...@@ -309,12 +308,13 @@ static void hub_tt_kevent (void *arg) ...@@ -309,12 +308,13 @@ static void hub_tt_kevent (void *arg)
/* drop lock so HCD can concurrently report other TT errors */ /* drop lock so HCD can concurrently report other TT errors */
spin_unlock_irqrestore (&hub->tt.lock, flags); spin_unlock_irqrestore (&hub->tt.lock, flags);
dev = interface_to_usbdev (hub->intf); hdev = interface_to_usbdev (hub->intf);
status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt); status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
spin_lock_irqsave (&hub->tt.lock, flags); spin_lock_irqsave (&hub->tt.lock, flags);
if (status) if (status)
dev_err (&dev->dev, "clear tt %d (%04x) error %d\n", dev_err (&hdev->dev,
"clear tt %d (%04x) error %d\n",
clear->tt, clear->devinfo, status); clear->tt, clear->devinfo, status);
kfree (clear); kfree (clear);
} }
...@@ -334,9 +334,9 @@ static void hub_tt_kevent (void *arg) ...@@ -334,9 +334,9 @@ static void hub_tt_kevent (void *arg)
* It may not be possible for that hub to handle additional full (or low) * It may not be possible for that hub to handle additional full (or low)
* speed transactions until that state is fully cleared out. * speed transactions until that state is fully cleared out.
*/ */
void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
{ {
struct usb_tt *tt = dev->tt; struct usb_tt *tt = udev->tt;
unsigned long flags; unsigned long flags;
struct usb_tt_clear *clear; struct usb_tt_clear *clear;
...@@ -345,15 +345,15 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) ...@@ -345,15 +345,15 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
* there can be many TTs per hub). even if they're uncommon. * there can be many TTs per hub). even if they're uncommon.
*/ */
if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) { if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {
dev_err (&dev->dev, "can't save CLEAR_TT_BUFFER state\n"); dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
/* FIXME recover somehow ... RESET_TT? */ /* FIXME recover somehow ... RESET_TT? */
return; return;
} }
/* info that CLEAR_TT_BUFFER needs */ /* info that CLEAR_TT_BUFFER needs */
clear->tt = tt->multi ? dev->ttport : 1; clear->tt = tt->multi ? udev->ttport : 1;
clear->devinfo = usb_pipeendpoint (pipe); clear->devinfo = usb_pipeendpoint (pipe);
clear->devinfo |= dev->devnum << 4; clear->devinfo |= udev->devnum << 4;
clear->devinfo |= usb_pipecontrol (pipe) clear->devinfo |= usb_pipecontrol (pipe)
? (USB_ENDPOINT_XFER_CONTROL << 11) ? (USB_ENDPOINT_XFER_CONTROL << 11)
: (USB_ENDPOINT_XFER_BULK << 11); : (USB_ENDPOINT_XFER_BULK << 11);
...@@ -369,15 +369,15 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) ...@@ -369,15 +369,15 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
static void hub_power_on(struct usb_hub *hub) static void hub_power_on(struct usb_hub *hub)
{ {
struct usb_device *dev; struct usb_device *hdev;
int i; int i;
/* if hub supports power switching, enable power on each port */ /* if hub supports power switching, enable power on each port */
if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
dev_dbg(&hub->intf->dev, "enabling power on all ports\n"); dev_dbg(&hub->intf->dev, "enabling power on all ports\n");
dev = interface_to_usbdev(hub->intf); hdev = interface_to_usbdev(hub->intf);
for (i = 0; i < hub->descriptor->bNbrPorts; i++) for (i = 0; i < hub->descriptor->bNbrPorts; i++)
set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); set_port_feature(hdev, i + 1, USB_PORT_FEAT_POWER);
} }
/* Wait for power to be enabled */ /* Wait for power to be enabled */
...@@ -387,12 +387,12 @@ static void hub_power_on(struct usb_hub *hub) ...@@ -387,12 +387,12 @@ static void hub_power_on(struct usb_hub *hub)
static int hub_hub_status(struct usb_hub *hub, static int hub_hub_status(struct usb_hub *hub,
u16 *status, u16 *change) u16 *status, u16 *change)
{ {
struct usb_device *dev = interface_to_usbdev (hub->intf); struct usb_device *hdev = interface_to_usbdev (hub->intf);
int ret; int ret;
ret = get_hub_status(dev, &hub->status->hub); ret = get_hub_status(hdev, &hub->status->hub);
if (ret < 0) if (ret < 0)
dev_err (hubdev (dev), dev_err (&hub->intf->dev,
"%s failed (err = %d)\n", __FUNCTION__, ret); "%s failed (err = %d)\n", __FUNCTION__, ret);
else { else {
*status = le16_to_cpu(hub->status->hub.wHubStatus); *status = le16_to_cpu(hub->status->hub.wHubStatus);
...@@ -405,14 +405,14 @@ static int hub_hub_status(struct usb_hub *hub, ...@@ -405,14 +405,14 @@ static int hub_hub_status(struct usb_hub *hub,
static int hub_configure(struct usb_hub *hub, static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint) struct usb_endpoint_descriptor *endpoint)
{ {
struct usb_device *dev = interface_to_usbdev (hub->intf); struct usb_device *hdev = interface_to_usbdev (hub->intf);
struct device *hub_dev; struct device *hub_dev = &hub->intf->dev;
u16 hubstatus, hubchange; u16 hubstatus, hubchange;
unsigned int pipe; unsigned int pipe;
int maxp, ret; int maxp, ret;
char *message; char *message;
hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL, hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
&hub->buffer_dma); &hub->buffer_dma);
if (!hub->buffer) { if (!hub->buffer) {
message = "can't allocate hub irq buffer"; message = "can't allocate hub irq buffer";
...@@ -438,7 +438,7 @@ static int hub_configure(struct usb_hub *hub, ...@@ -438,7 +438,7 @@ static int hub_configure(struct usb_hub *hub,
* hub->descriptor can handle USB_MAXCHILDREN ports, * hub->descriptor can handle USB_MAXCHILDREN ports,
* but the hub can/will return fewer bytes here. * but the hub can/will return fewer bytes here.
*/ */
ret = get_hub_descriptor(dev, hub->descriptor, ret = get_hub_descriptor(hdev, hub->descriptor,
sizeof(*hub->descriptor)); sizeof(*hub->descriptor));
if (ret < 0) { if (ret < 0) {
message = "can't read hub descriptor"; message = "can't read hub descriptor";
...@@ -449,10 +449,9 @@ static int hub_configure(struct usb_hub *hub, ...@@ -449,10 +449,9 @@ static int hub_configure(struct usb_hub *hub,
goto fail; goto fail;
} }
hub_dev = hubdev(dev); hdev->maxchild = hub->descriptor->bNbrPorts;
dev->maxchild = hub->descriptor->bNbrPorts; dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
dev_info (hub_dev, "%d port%s detected\n", dev->maxchild, (hdev->maxchild == 1) ? "" : "s");
(dev->maxchild == 1) ? "" : "s");
le16_to_cpus(&hub->descriptor->wHubCharacteristics); le16_to_cpus(&hub->descriptor->wHubCharacteristics);
...@@ -460,11 +459,11 @@ static int hub_configure(struct usb_hub *hub, ...@@ -460,11 +459,11 @@ static int hub_configure(struct usb_hub *hub,
int i; int i;
char portstr [USB_MAXCHILDREN + 1]; char portstr [USB_MAXCHILDREN + 1];
for (i = 0; i < dev->maxchild; i++) for (i = 0; i < hdev->maxchild; i++)
portstr[i] = hub->descriptor->DeviceRemovable portstr[i] = hub->descriptor->DeviceRemovable
[((i + 1) / 8)] & (1 << ((i + 1) % 8)) [((i + 1) / 8)] & (1 << ((i + 1) % 8))
? 'F' : 'R'; ? 'F' : 'R';
portstr[dev->maxchild] = 0; portstr[hdev->maxchild] = 0;
dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr); dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
} else } else
dev_dbg(hub_dev, "standalone hub\n"); dev_dbg(hub_dev, "standalone hub\n");
...@@ -498,32 +497,32 @@ static int hub_configure(struct usb_hub *hub, ...@@ -498,32 +497,32 @@ static int hub_configure(struct usb_hub *hub,
spin_lock_init (&hub->tt.lock); spin_lock_init (&hub->tt.lock);
INIT_LIST_HEAD (&hub->tt.clear_list); INIT_LIST_HEAD (&hub->tt.clear_list);
INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub); INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub);
switch (dev->descriptor.bDeviceProtocol) { switch (hdev->descriptor.bDeviceProtocol) {
case 0: case 0:
break; break;
case 1: case 1:
dev_dbg(hub_dev, "Single TT\n"); dev_dbg(hub_dev, "Single TT\n");
hub->tt.hub = dev; hub->tt.hub = hdev;
break; break;
case 2: case 2:
ret = usb_set_interface(dev, 0, 1); ret = usb_set_interface(hdev, 0, 1);
if (ret == 0) { if (ret == 0) {
dev_dbg(hub_dev, "TT per port\n"); dev_dbg(hub_dev, "TT per port\n");
hub->tt.multi = 1; hub->tt.multi = 1;
} else } else
dev_err(hub_dev, "Using single TT (err %d)\n", dev_err(hub_dev, "Using single TT (err %d)\n",
ret); ret);
hub->tt.hub = dev; hub->tt.hub = hdev;
break; break;
default: default:
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
dev->descriptor.bDeviceProtocol); hdev->descriptor.bDeviceProtocol);
break; break;
} }
switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
case 0x00: case 0x00:
if (dev->descriptor.bDeviceProtocol != 0) if (hdev->descriptor.bDeviceProtocol != 0)
dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n"); dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n");
break; break;
case 0x20: case 0x20:
...@@ -549,9 +548,9 @@ static int hub_configure(struct usb_hub *hub, ...@@ -549,9 +548,9 @@ static int hub_configure(struct usb_hub *hub,
/* power budgeting mostly matters with bus-powered hubs, /* power budgeting mostly matters with bus-powered hubs,
* and battery-powered root hubs (may provide just 8 mA). * and battery-powered root hubs (may provide just 8 mA).
*/ */
ret = usb_get_status(dev, USB_RECIP_DEVICE, 0, &hubstatus); ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
if (ret < 0) { if (ret < 0) {
message = "can't get hubdev status"; message = "can't get hub status";
goto fail; goto fail;
} }
cpu_to_le16s(&hubstatus); cpu_to_le16s(&hubstatus);
...@@ -572,7 +571,7 @@ static int hub_configure(struct usb_hub *hub, ...@@ -572,7 +571,7 @@ static int hub_configure(struct usb_hub *hub,
} }
/* local power status reports aren't always correct */ /* local power status reports aren't always correct */
if (dev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER) if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
dev_dbg(hub_dev, "local power source is %s\n", dev_dbg(hub_dev, "local power source is %s\n",
(hubstatus & HUB_STATUS_LOCAL_POWER) (hubstatus & HUB_STATUS_LOCAL_POWER)
? "lost (inactive)" : "good"); ? "lost (inactive)" : "good");
...@@ -582,8 +581,8 @@ static int hub_configure(struct usb_hub *hub, ...@@ -582,8 +581,8 @@ static int hub_configure(struct usb_hub *hub,
(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
/* Start the interrupt endpoint */ /* Start the interrupt endpoint */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
if (maxp > sizeof(*hub->buffer)) if (maxp > sizeof(*hub->buffer))
maxp = sizeof(*hub->buffer); maxp = sizeof(*hub->buffer);
...@@ -595,7 +594,7 @@ static int hub_configure(struct usb_hub *hub, ...@@ -595,7 +594,7 @@ static int hub_configure(struct usb_hub *hub,
goto fail; goto fail;
} }
usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq, usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval); hub, endpoint->bInterval);
hub->urb->transfer_dma = hub->buffer_dma; hub->urb->transfer_dma = hub->buffer_dma;
hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
...@@ -611,7 +610,7 @@ static int hub_configure(struct usb_hub *hub, ...@@ -611,7 +610,7 @@ static int hub_configure(struct usb_hub *hub,
/* maybe start cycling the hub leds */ /* maybe start cycling the hub leds */
if (hub->has_indicators && blinkenlights) { if (hub->has_indicators && blinkenlights) {
set_port_led(dev, hub, 1, HUB_LED_GREEN); set_port_led(hdev, 1, HUB_LED_GREEN);
hub->indicator [0] = INDICATOR_CYCLE; hub->indicator [0] = INDICATOR_CYCLE;
schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
} }
...@@ -621,7 +620,7 @@ static int hub_configure(struct usb_hub *hub, ...@@ -621,7 +620,7 @@ static int hub_configure(struct usb_hub *hub,
return 0; return 0;
fail: fail:
dev_err (&hub->intf->dev, "config failed, %s (err %d)\n", dev_err (hub_dev, "config failed, %s (err %d)\n",
message, ret); message, ret);
/* hub_disconnect() frees urb and descriptor */ /* hub_disconnect() frees urb and descriptor */
return ret; return ret;
...@@ -693,19 +692,21 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -693,19 +692,21 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{ {
struct usb_host_interface *desc; struct usb_host_interface *desc;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct usb_device *dev; struct usb_device *hdev;
struct usb_hub *hub; struct usb_hub *hub;
struct device *hub_dev;
unsigned long flags; unsigned long flags;
desc = intf->cur_altsetting; desc = intf->cur_altsetting;
dev = interface_to_usbdev(intf); hdev = interface_to_usbdev(intf);
hub_dev = &intf->dev;
/* Some hubs have a subclass of 1, which AFAICT according to the */ /* Some hubs have a subclass of 1, which AFAICT according to the */
/* specs is not defined, but it works */ /* specs is not defined, but it works */
if ((desc->desc.bInterfaceSubClass != 0) && if ((desc->desc.bInterfaceSubClass != 0) &&
(desc->desc.bInterfaceSubClass != 1)) { (desc->desc.bInterfaceSubClass != 1)) {
descriptor_error: descriptor_error:
dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); dev_err (hub_dev, "bad descriptor, ignoring hub\n");
return -EIO; return -EIO;
} }
...@@ -729,11 +730,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -729,11 +730,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
} }
/* We found a hub */ /* We found a hub */
dev_info (hubdev (dev), "USB hub found\n"); dev_info (hub_dev, "USB hub found\n");
hub = kmalloc(sizeof(*hub), GFP_KERNEL); hub = kmalloc(sizeof(*hub), GFP_KERNEL);
if (!hub) { if (!hub) {
dev_dbg (hubdev(dev), "couldn't kmalloc hub struct\n"); dev_dbg (hub_dev, "couldn't kmalloc hub struct\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -752,7 +753,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -752,7 +753,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_set_intfdata (intf, hub); usb_set_intfdata (intf, hub);
if (dev->speed == USB_SPEED_HIGH) if (hdev->speed == USB_SPEED_HIGH)
highspeed_hubs++; highspeed_hubs++;
if (hub_configure(hub, endpoint) >= 0) if (hub_configure(hub, endpoint) >= 0)
...@@ -765,7 +766,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -765,7 +766,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
static int static int
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{ {
struct usb_device *hub = interface_to_usbdev (intf); struct usb_device *hdev = interface_to_usbdev (intf);
/* assert ifno == 0 (part of hub spec) */ /* assert ifno == 0 (part of hub spec) */
switch (code) { switch (code) {
...@@ -775,16 +776,16 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) ...@@ -775,16 +776,16 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
int i; int i;
spin_lock_irqsave(&hub_event_lock, flags); spin_lock_irqsave(&hub_event_lock, flags);
if (hub->devnum <= 0) if (hdev->devnum <= 0)
info->nports = 0; info->nports = 0;
else { else {
info->nports = hub->maxchild; info->nports = hdev->maxchild;
for (i = 0; i < info->nports; i++) { for (i = 0; i < info->nports; i++) {
if (hub->children[i] == NULL) if (hdev->children[i] == NULL)
info->port[i] = 0; info->port[i] = 0;
else else
info->port[i] = info->port[i] =
hub->children[i]->devnum; hdev->children[i]->devnum;
} }
} }
spin_unlock_irqrestore(&hub_event_lock, flags); spin_unlock_irqrestore(&hub_event_lock, flags);
...@@ -799,13 +800,13 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) ...@@ -799,13 +800,13 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
static int hub_reset(struct usb_hub *hub) static int hub_reset(struct usb_hub *hub)
{ {
struct usb_device *dev = interface_to_usbdev(hub->intf); struct usb_device *hdev = interface_to_usbdev(hub->intf);
int i; int i;
/* Disconnect any attached devices */ /* Disconnect any attached devices */
for (i = 0; i < hub->descriptor->bNbrPorts; i++) { for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
if (dev->children[i]) if (hdev->children[i])
usb_disconnect(&dev->children[i]); usb_disconnect(&hdev->children[i]);
} }
/* Attempt to reset the hub */ /* Attempt to reset the hub */
...@@ -814,10 +815,10 @@ static int hub_reset(struct usb_hub *hub) ...@@ -814,10 +815,10 @@ static int hub_reset(struct usb_hub *hub)
else else
return -1; return -1;
if (usb_reset_device(dev)) if (usb_reset_device(hdev))
return -1; return -1;
hub->urb->dev = dev; hub->urb->dev = hdev;
if (usb_submit_urb(hub->urb, GFP_KERNEL)) if (usb_submit_urb(hub->urb, GFP_KERNEL))
return -1; return -1;
...@@ -826,36 +827,36 @@ static int hub_reset(struct usb_hub *hub) ...@@ -826,36 +827,36 @@ static int hub_reset(struct usb_hub *hub)
return 0; return 0;
} }
static void hub_start_disconnect(struct usb_device *dev) static void hub_start_disconnect(struct usb_device *hdev)
{ {
struct usb_device *parent = dev->parent; struct usb_device *parent = hdev->parent;
int i; int i;
/* Find the device pointer to disconnect */ /* Find the device pointer to disconnect */
if (parent) { if (parent) {
for (i = 0; i < parent->maxchild; i++) { for (i = 0; i < parent->maxchild; i++) {
if (parent->children[i] == dev) { if (parent->children[i] == hdev) {
usb_disconnect(&parent->children[i]); usb_disconnect(&parent->children[i]);
return; return;
} }
} }
} }
dev_err(&dev->dev, "cannot disconnect hub!\n"); dev_err(&hdev->dev, "cannot disconnect hub!\n");
} }
static int hub_port_status(struct usb_device *dev, int port, static int hub_port_status(struct usb_device *hdev, int port,
u16 *status, u16 *change) u16 *status, u16 *change)
{ {
struct usb_hub *hub = usb_get_intfdata(dev->actconfig->interface[0]); struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
int ret; int ret;
if (!hub) if (!hub)
return -ENODEV; return -ENODEV;
ret = get_port_status(dev, port + 1, &hub->status->port); ret = get_port_status(hdev, port + 1, &hub->status->port);
if (ret < 0) if (ret < 0)
dev_err (hubdev (dev), dev_err (&hub->intf->dev,
"%s failed (err = %d)\n", __FUNCTION__, ret); "%s failed (err = %d)\n", __FUNCTION__, ret);
else { else {
*status = le16_to_cpu(hub->status->port.wPortStatus); *status = le16_to_cpu(hub->status->port.wPortStatus);
...@@ -875,9 +876,8 @@ static int hub_port_status(struct usb_device *dev, int port, ...@@ -875,9 +876,8 @@ static int hub_port_status(struct usb_device *dev, int port,
#define HUB_LONG_RESET_TIME 200 #define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 500 #define HUB_RESET_TIMEOUT 500
/* return: -1 on error, 0 on success, 1 on disconnect. */ static int hub_port_wait_reset(struct usb_device *hdev, int port,
static int hub_port_wait_reset(struct usb_device *hub, int port, struct usb_device *udev, unsigned int delay)
struct usb_device *dev, unsigned int delay)
{ {
int delay_time, ret; int delay_time, ret;
u16 portstatus; u16 portstatus;
...@@ -890,28 +890,27 @@ static int hub_port_wait_reset(struct usb_device *hub, int port, ...@@ -890,28 +890,27 @@ static int hub_port_wait_reset(struct usb_device *hub, int port,
msleep(delay); msleep(delay);
/* read and decode port status */ /* read and decode port status */
ret = hub_port_status(hub, port, &portstatus, &portchange); ret = hub_port_status(hdev, port, &portstatus, &portchange);
if (ret < 0) { if (ret < 0)
return -1; return ret;
}
/* Device went away? */ /* Device went away? */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) if (!(portstatus & USB_PORT_STAT_CONNECTION))
return 1; return -ENOTCONN;
/* bomb out completely if something weird happened */ /* bomb out completely if something weird happened */
if ((portchange & USB_PORT_STAT_C_CONNECTION)) if ((portchange & USB_PORT_STAT_C_CONNECTION))
return -1; return -EINVAL;
/* if we`ve finished resetting, then break out of the loop */ /* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) && if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) { (portstatus & USB_PORT_STAT_ENABLE)) {
if (portstatus & USB_PORT_STAT_HIGH_SPEED) if (portstatus & USB_PORT_STAT_HIGH_SPEED)
dev->speed = USB_SPEED_HIGH; udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED) else if (portstatus & USB_PORT_STAT_LOW_SPEED)
dev->speed = USB_SPEED_LOW; udev->speed = USB_SPEED_LOW;
else else
dev->speed = USB_SPEED_FULL; udev->speed = USB_SPEED_FULL;
return 0; return 0;
} }
...@@ -919,55 +918,55 @@ static int hub_port_wait_reset(struct usb_device *hub, int port, ...@@ -919,55 +918,55 @@ static int hub_port_wait_reset(struct usb_device *hub, int port,
if (delay_time >= 2 * HUB_SHORT_RESET_TIME) if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
delay = HUB_LONG_RESET_TIME; delay = HUB_LONG_RESET_TIME;
dev_dbg (hubdev (hub), dev_dbg (hubdev (hdev),
"port %d not reset yet, waiting %dms\n", "port %d not reset yet, waiting %dms\n",
port + 1, delay); port + 1, delay);
} }
return -1; return -EBUSY;
} }
/* return: -1 on error, 0 on success, 1 on disconnect. */ static int hub_port_reset(struct usb_device *hdev, int port,
static int hub_port_reset(struct usb_device *hub, int port, struct usb_device *udev, unsigned int delay)
struct usb_device *dev, unsigned int delay)
{ {
int i, status; int i, status;
struct device *hub_dev = hubdev (hdev);
/* Reset the port */ /* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) { for (i = 0; i < PORT_RESET_TRIES; i++) {
set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); set_port_feature(hdev, port + 1, USB_PORT_FEAT_RESET);
/* return on disconnect or reset */ /* return on disconnect or reset */
status = hub_port_wait_reset(hub, port, dev, delay); status = hub_port_wait_reset(hdev, port, udev, delay);
if (status != -1) { if (status == -ENOTCONN || status == 0) {
clear_port_feature(hub, clear_port_feature(hdev,
port + 1, USB_PORT_FEAT_C_RESET); port + 1, USB_PORT_FEAT_C_RESET);
dev->state = status udev->state = status
? USB_STATE_NOTATTACHED ? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT; : USB_STATE_DEFAULT;
return status; return status;
} }
dev_dbg (hubdev (hub), dev_dbg (hub_dev,
"port %d not enabled, trying reset again...\n", "port %d not enabled, trying reset again...\n",
port + 1); port + 1);
delay = HUB_LONG_RESET_TIME; delay = HUB_LONG_RESET_TIME;
} }
dev_err (hubdev (hub), dev_err (hub_dev,
"Cannot enable port %i. Maybe the USB cable is bad?\n", "Cannot enable port %i. Maybe the USB cable is bad?\n",
port + 1); port + 1);
return -1; return status;
} }
static int hub_port_disable(struct usb_device *hub, int port) static int hub_port_disable(struct usb_device *hdev, int port)
{ {
int ret; int ret;
ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); ret = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_ENABLE);
if (ret) if (ret)
dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n", dev_err(hubdev(hdev), "cannot disable port %d (err = %d)\n",
port + 1, ret); port + 1, ret);
return ret; return ret;
...@@ -991,8 +990,7 @@ static int hub_port_disable(struct usb_device *hub, int port) ...@@ -991,8 +990,7 @@ static int hub_port_disable(struct usb_device *hub, int port)
#define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 4 #define HUB_DEBOUNCE_STABLE 4
/* return: -1 on error, 0 on success, 1 on disconnect. */ static int hub_port_debounce(struct usb_device *hdev, int port)
static int hub_port_debounce(struct usb_device *hub, int port)
{ {
int ret; int ret;
int delay_time, stable_count; int delay_time, stable_count;
...@@ -1004,9 +1002,9 @@ static int hub_port_debounce(struct usb_device *hub, int port) ...@@ -1004,9 +1002,9 @@ static int hub_port_debounce(struct usb_device *hub, int port)
for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) { for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
msleep(HUB_DEBOUNCE_STEP); msleep(HUB_DEBOUNCE_STEP);
ret = hub_port_status(hub, port, &portstatus, &portchange); ret = hub_port_status(hdev, port, &portstatus, &portchange);
if (ret < 0) if (ret < 0)
return -1; return ret;
if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) { if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) {
if (connection) { if (connection) {
...@@ -1019,15 +1017,32 @@ static int hub_port_debounce(struct usb_device *hub, int port) ...@@ -1019,15 +1017,32 @@ static int hub_port_debounce(struct usb_device *hub, int port)
connection = portstatus & USB_PORT_STAT_CONNECTION; connection = portstatus & USB_PORT_STAT_CONNECTION;
if ((portchange & USB_PORT_STAT_C_CONNECTION)) { if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); clear_port_feature(hdev, port+1, USB_PORT_FEAT_C_CONNECTION);
} }
} }
dev_dbg (hubdev (hub), dev_dbg (hubdev (hdev),
"debounce: port %d: delay %dms stable %d status 0x%x\n", "debounce: port %d: delay %dms stable %d status 0x%x\n",
port + 1, delay_time, stable_count, portstatus); port + 1, delay_time, stable_count, portstatus);
return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; return (portstatus & USB_PORT_STAT_CONNECTION) ? 0 : -ENOTCONN;
}
static int hub_set_address(struct usb_device *udev)
{
int retval;
if (udev->devnum == 0)
return -EINVAL;
if (udev->state != USB_STATE_DEFAULT &&
udev->state != USB_STATE_ADDRESS)
return -EINVAL;
retval = usb_control_msg(udev, usb_snddefctrl(udev),
USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval == 0)
udev->state = USB_STATE_ADDRESS;
return retval;
} }
/* reset device, (re)assign address, get device descriptor. /* reset device, (re)assign address, get device descriptor.
...@@ -1039,18 +1054,18 @@ static int hub_port_debounce(struct usb_device *hub, int port) ...@@ -1039,18 +1054,18 @@ static int hub_port_debounce(struct usb_device *hub, int port)
* config changes and disconnect processing. * config changes and disconnect processing.
*/ */
static int static int
hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
{ {
static DECLARE_MUTEX(usb_address0_sem); static DECLARE_MUTEX(usb_address0_sem);
int i, j, retval = -ENODEV; int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME; unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = dev->speed; enum usb_device_speed oldspeed = udev->speed;
/* root hub ports have a slightly longer reset period /* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5) * (from USB 2.0 spec, section 7.1.7.5)
*/ */
if (!hub->parent) if (!hdev->parent)
delay = HUB_ROOT_RESET_TIME; delay = HUB_ROOT_RESET_TIME;
/* Some low speed devices have problems with the quick delay, so */ /* Some low speed devices have problems with the quick delay, so */
...@@ -1061,24 +1076,21 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) ...@@ -1061,24 +1076,21 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
down(&usb_address0_sem); down(&usb_address0_sem);
/* Reset the device; full speed may morph to high speed */ /* Reset the device; full speed may morph to high speed */
switch (hub_port_reset(hub, port, dev, delay)) { retval = hub_port_reset(hdev, port, udev, delay);
case 0: /* success, speed is known */ if (retval < 0) /* error or disconnect */
break;
case 1: /* disconnect, give to companion */
retval = -EBUSY;
/* FALL THROUGH */
default: /* error */
goto fail; goto fail;
} /* success, speed is known */
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != dev->speed) { retval = -ENODEV;
dev_dbg(&dev->dev, "device reset changed speed!\n");
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail; goto fail;
} }
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices. * it's fixed size except for full speed devices.
*/ */
switch (dev->speed) { switch (udev->speed) {
case USB_SPEED_HIGH: /* fixed at 64 */ case USB_SPEED_HIGH: /* fixed at 64 */
i = 64; i = 64;
break; break;
...@@ -1094,43 +1106,43 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) ...@@ -1094,43 +1106,43 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
default: default:
goto fail; goto fail;
} }
dev->epmaxpacketin [0] = i; udev->epmaxpacketin [0] = i;
dev->epmaxpacketout[0] = i; udev->epmaxpacketout[0] = i;
/* set the address */ /* set the address */
if (dev->devnum <= 0) { if (udev->devnum <= 0) {
usb_choose_address(dev); usb_choose_address(udev);
if (dev->devnum <= 0) if (udev->devnum <= 0)
goto fail; goto fail;
/* Set up TT records, if needed */ /* Set up TT records, if needed */
if (hub->tt) { if (hdev->tt) {
dev->tt = hub->tt; udev->tt = hdev->tt;
dev->ttport = hub->ttport; udev->ttport = hdev->ttport;
} else if (dev->speed != USB_SPEED_HIGH } else if (udev->speed != USB_SPEED_HIGH
&& hub->speed == USB_SPEED_HIGH) { && hdev->speed == USB_SPEED_HIGH) {
struct usb_hub *hubstate; struct usb_hub *hub;
hubstate = usb_get_intfdata (hub->actconfig hub = usb_get_intfdata (hdev->actconfig
->interface[0]); ->interface[0]);
dev->tt = &hubstate->tt; udev->tt = &hub->tt;
dev->ttport = port + 1; udev->ttport = port + 1;
} }
/* force the right log message (below) at low speed */ /* force the right log message (below) at low speed */
oldspeed = USB_SPEED_UNKNOWN; oldspeed = USB_SPEED_UNKNOWN;
} }
dev_info (&dev->dev, dev_info (&udev->dev,
"%s %s speed USB device using address %d\n", "%s %s speed USB device using address %d\n",
(oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset", (oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset",
({ char *speed; switch (dev->speed) { ({ char *speed; switch (udev->speed) {
case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break; case USB_SPEED_HIGH: speed = "high"; break;
default: speed = "?"; break; default: speed = "?"; break;
}; speed;}), }; speed;}),
dev->devnum); udev->devnum);
/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
* Because device hardware and firmware is sometimes buggy in * Because device hardware and firmware is sometimes buggy in
...@@ -1143,20 +1155,19 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) ...@@ -1143,20 +1155,19 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
*/ */
for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) { for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) {
for (j = 0; j < SET_ADDRESS_TRIES; ++j) { for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = usb_set_address(dev); retval = hub_set_address(udev);
if (retval >= 0) if (retval >= 0)
break; break;
msleep(200); msleep(200);
} }
if (retval < 0) { if (retval < 0) {
dev_err(&dev->dev, dev_err(&udev->dev,
"device not accepting address %d, error %d\n", "device not accepting address %d, error %d\n",
dev->devnum, retval); udev->devnum, retval);
fail: fail:
hub_port_disable(hub, port); hub_port_disable(hdev, port);
clear_bit(dev->devnum, dev->bus->devmap.devicemap); usb_release_address(udev);
dev->devnum = -1; usb_put_dev(udev);
usb_put_dev(dev);
up(&usb_address0_sem); up(&usb_address0_sem);
return retval; return retval;
} }
...@@ -1166,31 +1177,31 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) ...@@ -1166,31 +1177,31 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
* - read ep0 maxpacket even for high and low speed, * - read ep0 maxpacket even for high and low speed,
*/ */
msleep(10); msleep(10);
retval = usb_get_device_descriptor(dev, 8); retval = usb_get_device_descriptor(udev, 8);
if (retval >= 8) if (retval >= 8)
break; break;
msleep(100); msleep(100);
} }
if (retval != 8) { if (retval != 8) {
dev_err(&dev->dev, "device descriptor read/%s, error %d\n", dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
"8", retval); "8", retval);
if (retval >= 0) if (retval >= 0)
retval = -EMSGSIZE; retval = -EMSGSIZE;
goto fail; goto fail;
} }
if (dev->speed == USB_SPEED_FULL if (udev->speed == USB_SPEED_FULL
&& (dev->epmaxpacketin [0] && (udev->epmaxpacketin [0]
!= dev->descriptor.bMaxPacketSize0)) { != udev->descriptor.bMaxPacketSize0)) {
usb_disable_endpoint(dev, 0); usb_disable_endpoint(udev, 0);
usb_endpoint_running(dev, 0, 1); usb_endpoint_running(udev, 0, 1);
usb_endpoint_running(dev, 0, 0); usb_endpoint_running(udev, 0, 0);
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0;
} }
retval = usb_get_device_descriptor(dev, USB_DT_DEVICE_SIZE); retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (retval < (signed)sizeof(dev->descriptor)) { if (retval < (signed)sizeof(udev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/%s, error %d\n", dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
"all", retval); "all", retval);
if (retval >= 0) if (retval >= 0)
retval = -ENOMSG; retval = -ENOMSG;
...@@ -1198,14 +1209,14 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port) ...@@ -1198,14 +1209,14 @@ hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
} }
/* now dev is visible to other tasks */ /* now dev is visible to other tasks */
hub->children[port] = dev; hdev->children[port] = udev;
up(&usb_address0_sem); up(&usb_address0_sem);
return 0; return 0;
} }
static void static void
check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port) check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port)
{ {
struct usb_qualifier_descriptor *qual; struct usb_qualifier_descriptor *qual;
int status; int status;
...@@ -1214,10 +1225,10 @@ check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port) ...@@ -1214,10 +1225,10 @@ check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port)
if (qual == 0) if (qual == 0)
return; return;
status = usb_get_descriptor (dev, USB_DT_DEVICE_QUALIFIER, 0, status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0,
qual, sizeof *qual); qual, sizeof *qual);
if (status == sizeof *qual) { if (status == sizeof *qual) {
dev_info(&dev->dev, "not running at top speed; " dev_info(&udev->dev, "not running at top speed; "
"connect to a high speed hub\n"); "connect to a high speed hub\n");
/* hub LEDs are probably harder to miss than syslog */ /* hub LEDs are probably harder to miss than syslog */
if (hub->has_indicators) { if (hub->has_indicators) {
...@@ -1229,31 +1240,31 @@ check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port) ...@@ -1229,31 +1240,31 @@ check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port)
} }
static unsigned static unsigned
hub_power_remaining (struct usb_hub *hubstate, struct usb_device *hub) hub_power_remaining (struct usb_hub *hub, struct usb_device *hdev)
{ {
int remaining; int remaining;
unsigned i; unsigned i;
remaining = hubstate->power_budget; remaining = hub->power_budget;
if (!remaining) /* self-powered */ if (!remaining) /* self-powered */
return 0; return 0;
for (i = 0; i < hub->maxchild; i++) { for (i = 0; i < hdev->maxchild; i++) {
struct usb_device *dev = hub->children[i]; struct usb_device *udev = hdev->children[i];
int delta; int delta;
if (!dev) if (!udev)
continue; continue;
if (dev->actconfig) if (udev->actconfig)
delta = dev->actconfig->desc.bMaxPower; delta = udev->actconfig->desc.bMaxPower;
else else
delta = 50; delta = 50;
// dev_dbg(&dev->dev, "budgeted %dmA\n", 2 * delta); // dev_dbg(&udev->dev, "budgeted %dmA\n", 2 * delta);
remaining -= delta; remaining -= delta;
} }
if (remaining < 0) { if (remaining < 0) {
dev_warn(&hubstate->intf->dev, dev_warn(&hub->intf->dev,
"%dmA over power budget!\n", "%dmA over power budget!\n",
-2 * remaining); -2 * remaining);
remaining = 0; remaining = 0;
...@@ -1261,73 +1272,74 @@ hub_power_remaining (struct usb_hub *hubstate, struct usb_device *hub) ...@@ -1261,73 +1272,74 @@ hub_power_remaining (struct usb_hub *hubstate, struct usb_device *hub)
return remaining; return remaining;
} }
static void hub_port_connect_change(struct usb_hub *hubstate, int port, static void hub_port_connect_change(struct usb_hub *hub, int port,
u16 portstatus, u16 portchange) u16 portstatus, u16 portchange)
{ {
struct usb_device *hub = interface_to_usbdev(hubstate->intf); struct usb_device *hdev = interface_to_usbdev(hub->intf);
struct device *hub_dev = &hub->intf->dev;
int status, i; int status, i;
dev_dbg (&hubstate->intf->dev, dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n", "port %d, status %04x, change %04x, %s\n",
port + 1, portstatus, portchange, portspeed (portstatus)); port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */ /* Clear the connection change status */
clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_CONNECTION);
if (hubstate->has_indicators) { if (hub->has_indicators) {
set_port_led(hub, hubstate, port + 1, HUB_LED_AUTO); set_port_led(hdev, port + 1, HUB_LED_AUTO);
hubstate->indicator[port] = INDICATOR_AUTO; hub->indicator[port] = INDICATOR_AUTO;
} }
/* Disconnect any existing devices under this port */ /* Disconnect any existing devices under this port */
if (hub->children[port]) if (hdev->children[port])
usb_disconnect(&hub->children[port]); usb_disconnect(&hdev->children[port]);
/* Return now if nothing is connected */ /* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) { if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
/* maybe switch power back on (e.g. root hub was reset) */ /* maybe switch power back on (e.g. root hub was reset) */
if ((hubstate->descriptor->wHubCharacteristics if ((hub->descriptor->wHubCharacteristics
& HUB_CHAR_LPSM) < 2 & HUB_CHAR_LPSM) < 2
&& !(portstatus & (1 << USB_PORT_FEAT_POWER))) && !(portstatus & (1 << USB_PORT_FEAT_POWER)))
set_port_feature(hub, port + 1, USB_PORT_FEAT_POWER); set_port_feature(hdev, port + 1, USB_PORT_FEAT_POWER);
if (portstatus & USB_PORT_STAT_ENABLE) if (portstatus & USB_PORT_STAT_ENABLE)
goto done; goto done;
return; return;
} }
if (hub_port_debounce(hub, port)) { if (hub_port_debounce(hdev, port)) {
dev_err (&hubstate->intf->dev, dev_err (hub_dev,
"connect-debounce failed, port %d disabled\n", "connect-debounce failed, port %d disabled\n",
port+1); port+1);
goto done; goto done;
} }
for (i = 0; i < SET_CONFIG_TRIES; i++) { for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *dev; struct usb_device *udev;
/* reallocate for each attempt, since references /* reallocate for each attempt, since references
* to the previous one can escape in various ways * to the previous one can escape in various ways
*/ */
dev = usb_alloc_dev(hub, hub->bus, port); udev = usb_alloc_dev(hdev, hdev->bus, port);
if (!dev) { if (!udev) {
dev_err (&hubstate->intf->dev, dev_err (hub_dev,
"couldn't allocate port %d usb_device\n", port+1); "couldn't allocate port %d usb_device\n", port+1);
goto done; goto done;
} }
dev->state = USB_STATE_POWERED; udev->state = USB_STATE_POWERED;
/* hub can tell if it's lowspeed already: D- pullup (not D+) */ /* hub can tell if it's lowspeed already: D- pullup (not D+) */
if (portstatus & USB_PORT_STAT_LOW_SPEED) if (portstatus & USB_PORT_STAT_LOW_SPEED)
dev->speed = USB_SPEED_LOW; udev->speed = USB_SPEED_LOW;
else else
dev->speed = USB_SPEED_UNKNOWN; udev->speed = USB_SPEED_UNKNOWN;
/* reset, set address, get descriptor, add to hub's children */ /* reset, set address, get descriptor, add to hub's children */
down (&dev->serialize); down (&udev->serialize);
status = hub_port_init(hub, dev, port); status = hub_port_init(hdev, udev, port);
if (status == -EBUSY) if (status == -ENOTCONN)
break; break;
if (status < 0) if (status < 0)
continue; continue;
...@@ -1338,50 +1350,50 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -1338,50 +1350,50 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
* (without reading syslog), even without per-port LEDs * (without reading syslog), even without per-port LEDs
* on the parent. * on the parent.
*/ */
if (dev->descriptor.bDeviceClass == USB_CLASS_HUB if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
&& hubstate->power_budget) { && hub->power_budget) {
u16 devstat; u16 devstat;
status = usb_get_status(dev, USB_RECIP_DEVICE, 0, status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
&devstat); &devstat);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "get status %d ?\n", status); dev_dbg(&udev->dev, "get status %d ?\n", status);
continue; continue;
} }
cpu_to_le16s(&devstat); cpu_to_le16s(&devstat);
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) { if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_err(&dev->dev, dev_err(&udev->dev,
"can't connect bus-powered hub " "can't connect bus-powered hub "
"to this port\n"); "to this port\n");
if (hubstate->has_indicators) { if (hub->has_indicators) {
hubstate->indicator[port] = hub->indicator[port] =
INDICATOR_AMBER_BLINK; INDICATOR_AMBER_BLINK;
schedule_work (&hubstate->leds); schedule_work (&hub->leds);
} }
hub->children[port] = NULL; hdev->children[port] = NULL;
usb_put_dev(dev); usb_put_dev(udev);
hub_port_disable(hub, port); hub_port_disable(hdev, port);
return; return;
} }
} }
/* check for devices running slower than they could */ /* check for devices running slower than they could */
if (dev->descriptor.bcdUSB >= 0x0200 if (udev->descriptor.bcdUSB >= 0x0200
&& dev->speed == USB_SPEED_FULL && udev->speed == USB_SPEED_FULL
&& highspeed_hubs != 0) && highspeed_hubs != 0)
check_highspeed (hubstate, dev, port); check_highspeed (hub, udev, port);
/* Run it through the hoops (find a driver, etc) */ /* Run it through the hoops (find a driver, etc) */
status = usb_new_device(dev); status = usb_new_device(udev);
if (status != 0) { if (status != 0) {
hub->children[port] = NULL; hdev->children[port] = NULL;
continue; continue;
} }
up (&dev->serialize); up (&udev->serialize);
status = hub_power_remaining(hubstate, hub); status = hub_power_remaining(hub, hdev);
if (status) if (status)
dev_dbg(&hubstate->intf->dev, dev_dbg(hub_dev,
"%dmA power budget left\n", "%dmA power budget left\n",
2 * status); 2 * status);
...@@ -1389,15 +1401,16 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -1389,15 +1401,16 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
} }
done: done:
hub_port_disable(hub, port); hub_port_disable(hdev, port);
} }
static void hub_events(void) static void hub_events(void)
{ {
unsigned long flags; unsigned long flags;
struct list_head *tmp; struct list_head *tmp;
struct usb_device *dev; struct usb_device *hdev;
struct usb_hub *hub; struct usb_hub *hub;
struct device *hub_dev;
u16 hubstatus; u16 hubstatus;
u16 hubchange; u16 hubchange;
u16 portstatus; u16 portstatus;
...@@ -1420,7 +1433,8 @@ static void hub_events(void) ...@@ -1420,7 +1433,8 @@ static void hub_events(void)
tmp = hub_event_list.next; tmp = hub_event_list.next;
hub = list_entry(tmp, struct usb_hub, event_list); hub = list_entry(tmp, struct usb_hub, event_list);
dev = interface_to_usbdev(hub->intf); hdev = interface_to_usbdev(hub->intf);
hub_dev = &hub->intf->dev;
list_del_init(tmp); list_del_init(tmp);
...@@ -1430,14 +1444,14 @@ static void hub_events(void) ...@@ -1430,14 +1444,14 @@ static void hub_events(void)
spin_unlock_irqrestore(&hub_event_lock, flags); spin_unlock_irqrestore(&hub_event_lock, flags);
if (hub->error) { if (hub->error) {
dev_dbg (&hub->intf->dev, "resetting for error %d\n", dev_dbg (hub_dev, "resetting for error %d\n",
hub->error); hub->error);
if (hub_reset(hub)) { if (hub_reset(hub)) {
dev_dbg (&hub->intf->dev, dev_dbg (hub_dev,
"can't reset; disconnecting\n"); "can't reset; disconnecting\n");
up(&hub->khubd_sem); up(&hub->khubd_sem);
hub_start_disconnect(dev); hub_start_disconnect(hdev);
continue; continue;
} }
...@@ -1446,7 +1460,7 @@ static void hub_events(void) ...@@ -1446,7 +1460,7 @@ static void hub_events(void)
} }
for (i = 0; i < hub->descriptor->bNbrPorts; i++) { for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
ret = hub_port_status(dev, i, &portstatus, &portchange); ret = hub_port_status(hdev, i, &portstatus, &portchange);
if (ret < 0) { if (ret < 0) {
continue; continue;
} }
...@@ -1454,10 +1468,10 @@ static void hub_events(void) ...@@ -1454,10 +1468,10 @@ static void hub_events(void)
if (portchange & USB_PORT_STAT_C_CONNECTION) { if (portchange & USB_PORT_STAT_C_CONNECTION) {
hub_port_connect_change(hub, i, portstatus, portchange); hub_port_connect_change(hub, i, portstatus, portchange);
} else if (portchange & USB_PORT_STAT_C_ENABLE) { } else if (portchange & USB_PORT_STAT_C_ENABLE) {
dev_dbg (hubdev (dev), dev_dbg (hub_dev,
"port %d enable change, status %08x\n", "port %d enable change, status %08x\n",
i + 1, portstatus); i + 1, portstatus);
clear_port_feature(dev, clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_ENABLE); i + 1, USB_PORT_FEAT_C_ENABLE);
/* /*
...@@ -1468,8 +1482,8 @@ static void hub_events(void) ...@@ -1468,8 +1482,8 @@ static void hub_events(void)
*/ */
if (!(portstatus & USB_PORT_STAT_ENABLE) if (!(portstatus & USB_PORT_STAT_ENABLE)
&& (portstatus & USB_PORT_STAT_CONNECTION) && (portstatus & USB_PORT_STAT_CONNECTION)
&& (dev->children[i])) { && (hdev->children[i])) {
dev_err (&hub->intf->dev, dev_err (hub_dev,
"port %i " "port %i "
"disabled by hub (EMI?), " "disabled by hub (EMI?), "
"re-enabling...", "re-enabling...",
...@@ -1480,43 +1494,43 @@ static void hub_events(void) ...@@ -1480,43 +1494,43 @@ static void hub_events(void)
} }
if (portchange & USB_PORT_STAT_C_SUSPEND) { if (portchange & USB_PORT_STAT_C_SUSPEND) {
dev_dbg (&hub->intf->dev, dev_dbg (hub_dev,
"suspend change on port %d\n", "suspend change on port %d\n",
i + 1); i + 1);
clear_port_feature(dev, clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_SUSPEND); i + 1, USB_PORT_FEAT_C_SUSPEND);
} }
if (portchange & USB_PORT_STAT_C_OVERCURRENT) { if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
dev_err (&hub->intf->dev, dev_err (hub_dev,
"over-current change on port %d\n", "over-current change on port %d\n",
i + 1); i + 1);
clear_port_feature(dev, clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_OVER_CURRENT); i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
hub_power_on(hub); hub_power_on(hub);
} }
if (portchange & USB_PORT_STAT_C_RESET) { if (portchange & USB_PORT_STAT_C_RESET) {
dev_dbg (&hub->intf->dev, dev_dbg (hub_dev,
"reset change on port %d\n", "reset change on port %d\n",
i + 1); i + 1);
clear_port_feature(dev, clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_RESET); i + 1, USB_PORT_FEAT_C_RESET);
} }
} /* end for i */ } /* end for i */
/* deal with hub status changes */ /* deal with hub status changes */
if (hub_hub_status(hub, &hubstatus, &hubchange) < 0) if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
dev_err (&hub->intf->dev, "get_hub_status failed\n"); dev_err (hub_dev, "get_hub_status failed\n");
else { else {
if (hubchange & HUB_CHANGE_LOCAL_POWER) { if (hubchange & HUB_CHANGE_LOCAL_POWER) {
dev_dbg (&hub->intf->dev, "power change\n"); dev_dbg (hub_dev, "power change\n");
clear_hub_feature(dev, C_HUB_LOCAL_POWER); clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
} }
if (hubchange & HUB_CHANGE_OVERCURRENT) { if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (&hub->intf->dev, "overcurrent change\n"); dev_dbg (hub_dev, "overcurrent change\n");
msleep(500); /* Cool down */ msleep(500); /* Cool down */
clear_hub_feature(dev, C_HUB_OVER_CURRENT); clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
hub_power_on(hub); hub_power_on(hub);
} }
} }
...@@ -1526,7 +1540,7 @@ static void hub_events(void) ...@@ -1526,7 +1540,7 @@ static void hub_events(void)
spin_unlock_irqrestore(&hub_event_lock, flags); spin_unlock_irqrestore(&hub_event_lock, flags);
} }
static int hub_thread(void *__hub) static int hub_thread(void *__unused)
{ {
/* /*
* This thread doesn't need any user-level access, * This thread doesn't need any user-level access,
...@@ -1614,36 +1628,36 @@ void usb_hub_cleanup(void) ...@@ -1614,36 +1628,36 @@ void usb_hub_cleanup(void)
} /* usb_hub_cleanup() */ } /* usb_hub_cleanup() */
static int config_descriptors_changed(struct usb_device *dev) static int config_descriptors_changed(struct usb_device *udev)
{ {
unsigned index; unsigned index;
unsigned len = 0; unsigned len = 0;
struct usb_config_descriptor *buf; struct usb_config_descriptor *buf;
for (index = 0; index < dev->descriptor.bNumConfigurations; index++) { for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
if (len < dev->config[index].desc.wTotalLength) if (len < udev->config[index].desc.wTotalLength)
len = dev->config[index].desc.wTotalLength; len = udev->config[index].desc.wTotalLength;
} }
buf = kmalloc (len, SLAB_KERNEL); buf = kmalloc (len, SLAB_KERNEL);
if (buf == 0) { if (buf == 0) {
dev_err(&dev->dev, "no mem to re-read configs after reset\n"); dev_err(&udev->dev, "no mem to re-read configs after reset\n");
/* assume the worst */ /* assume the worst */
return 1; return 1;
} }
for (index = 0; index < dev->descriptor.bNumConfigurations; index++) { for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
int length; int length;
int old_length = dev->config[index].desc.wTotalLength; int old_length = udev->config[index].desc.wTotalLength;
length = usb_get_descriptor(dev, USB_DT_CONFIG, index, buf, length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
old_length); old_length);
if (length < old_length) { if (length < old_length) {
dev_dbg(&dev->dev, "config index %d, error %d\n", dev_dbg(&udev->dev, "config index %d, error %d\n",
index, length); index, length);
break; break;
} }
if (memcmp (buf, dev->rawdescriptors[index], old_length) if (memcmp (buf, udev->rawdescriptors[index], old_length)
!= 0) { != 0) {
dev_dbg(&dev->dev, "config index %d changed (#%d)\n", dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
index, buf->bConfigurationValue); index, buf->bConfigurationValue);
/* FIXME enable this when we can re-enumerate after reset; /* FIXME enable this when we can re-enumerate after reset;
* until then DFU-ish drivers need this and other workarounds * until then DFU-ish drivers need this and other workarounds
...@@ -1652,7 +1666,7 @@ static int config_descriptors_changed(struct usb_device *dev) ...@@ -1652,7 +1666,7 @@ static int config_descriptors_changed(struct usb_device *dev)
} }
} }
kfree(buf); kfree(buf);
return index != dev->descriptor.bNumConfigurations; return index != udev->descriptor.bNumConfigurations;
} }
/* /*
...@@ -1664,22 +1678,22 @@ static int config_descriptors_changed(struct usb_device *dev) ...@@ -1664,22 +1678,22 @@ static int config_descriptors_changed(struct usb_device *dev)
* already holds dev->serialize. For example, it's safe to use * already holds dev->serialize. For example, it's safe to use
* this from a driver probe() routine after downloading new firmware. * this from a driver probe() routine after downloading new firmware.
*/ */
int __usb_reset_device(struct usb_device *dev) int __usb_reset_device(struct usb_device *udev)
{ {
struct usb_device *parent = dev->parent; struct usb_device *parent = udev->parent;
struct usb_device_descriptor descriptor = dev->descriptor; struct usb_device_descriptor descriptor = udev->descriptor;
int i, ret, port = -1; int i, ret, port = -1;
if (dev->maxchild) { if (udev->maxchild) {
/* this requires hub- or hcd-specific logic; /* this requires hub- or hcd-specific logic;
* see hub_reset() and OHCI hc_restart() * see hub_reset() and OHCI hc_restart()
*/ */
dev_dbg(&dev->dev, "%s for hub!\n", __FUNCTION__); dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__);
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < parent->maxchild; i++) for (i = 0; i < parent->maxchild; i++)
if (parent->children[i] == dev) { if (parent->children[i] == udev) {
port = i; port = i;
break; break;
} }
...@@ -1687,45 +1701,45 @@ int __usb_reset_device(struct usb_device *dev) ...@@ -1687,45 +1701,45 @@ int __usb_reset_device(struct usb_device *dev)
if (port < 0) if (port < 0)
return -ENOENT; return -ENOENT;
ret = hub_port_init(parent, dev, port); ret = hub_port_init(parent, udev, port);
if (ret < 0) if (ret < 0)
goto re_enumerate; goto re_enumerate;
/* Device might have changed firmware (DFU or similar) */ /* Device might have changed firmware (DFU or similar) */
if (memcmp(&dev->descriptor, &descriptor, sizeof descriptor) if (memcmp(&udev->descriptor, &descriptor, sizeof descriptor)
|| config_descriptors_changed (dev)) { || config_descriptors_changed (udev)) {
dev_info(&dev->dev, "device firmware changed\n"); dev_info(&udev->dev, "device firmware changed\n");
dev->descriptor = descriptor; /* for disconnect() calls */ udev->descriptor = descriptor; /* for disconnect() calls */
goto re_enumerate; goto re_enumerate;
} }
if (!dev->actconfig) if (!udev->actconfig)
return 0; return 0;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_CONFIGURATION, 0, USB_REQ_SET_CONFIGURATION, 0,
dev->actconfig->desc.bConfigurationValue, 0, udev->actconfig->desc.bConfigurationValue, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (ret < 0) { if (ret < 0) {
dev_err(&dev->dev, dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n", "can't restore configuration #%d (error=%d)\n",
dev->actconfig->desc.bConfigurationValue, ret); udev->actconfig->desc.bConfigurationValue, ret);
goto re_enumerate; goto re_enumerate;
} }
dev->state = USB_STATE_CONFIGURED; udev->state = USB_STATE_CONFIGURED;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf = dev->actconfig->interface[i]; struct usb_interface *intf = udev->actconfig->interface[i];
struct usb_interface_descriptor *desc; struct usb_interface_descriptor *desc;
/* set_interface resets host side toggle and halt status even /* set_interface resets host side toggle and halt status even
* for altsetting zero. the interface may have no driver. * for altsetting zero. the interface may have no driver.
*/ */
desc = &intf->cur_altsetting->desc; desc = &intf->cur_altsetting->desc;
ret = usb_set_interface(dev, desc->bInterfaceNumber, ret = usb_set_interface(udev, desc->bInterfaceNumber,
desc->bAlternateSetting); desc->bAlternateSetting);
if (ret < 0) { if (ret < 0) {
dev_err(&dev->dev, "failed to restore interface %d " dev_err(&udev->dev, "failed to restore interface %d "
"altsetting %d (error=%d)\n", "altsetting %d (error=%d)\n",
desc->bInterfaceNumber, desc->bInterfaceNumber,
desc->bAlternateSetting, desc->bAlternateSetting,
...@@ -1738,7 +1752,7 @@ int __usb_reset_device(struct usb_device *dev) ...@@ -1738,7 +1752,7 @@ int __usb_reset_device(struct usb_device *dev)
re_enumerate: re_enumerate:
/* FIXME make some task re-enumerate; don't just mark unusable */ /* FIXME make some task re-enumerate; don't just mark unusable */
dev->state = USB_STATE_NOTATTACHED; udev->state = USB_STATE_NOTATTACHED;
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL(__usb_reset_device); EXPORT_SYMBOL(__usb_reset_device);
......
...@@ -1252,7 +1252,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1252,7 +1252,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
ret); ret);
continue; continue;
} }
usb_create_driverfs_intf_files (intf); usb_create_sysfs_intf_files (intf);
} }
} }
......
/* /*
* drivers/usb/core/driverfs.c * drivers/usb/core/sysfs.c
* *
* (C) Copyright 2002 David Brownell * (C) Copyright 2002 David Brownell
* (C) Copyright 2002 Greg Kroah-Hartman * (C) Copyright 2002 Greg Kroah-Hartman
* (C) Copyright 2002 IBM Corp. * (C) Copyright 2002 IBM Corp.
* *
* All of the driverfs file attributes for usb devices and interfaces. * All of the sysfs file attributes for usb devices and interfaces.
* *
*/ */
...@@ -163,7 +163,7 @@ usb_descriptor_attr (bDeviceProtocol, "%02x\n") ...@@ -163,7 +163,7 @@ usb_descriptor_attr (bDeviceProtocol, "%02x\n")
usb_descriptor_attr (bNumConfigurations, "%d\n") usb_descriptor_attr (bNumConfigurations, "%d\n")
void usb_create_driverfs_dev_files (struct usb_device *udev) void usb_create_sysfs_dev_files (struct usb_device *udev)
{ {
struct device *dev = &udev->dev; struct device *dev = &udev->dev;
...@@ -217,7 +217,7 @@ usb_intf_attr (bInterfaceSubClass, "%02x\n") ...@@ -217,7 +217,7 @@ usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n")
usb_intf_attr (iInterface, "%02x\n") usb_intf_attr (iInterface, "%02x\n")
void usb_create_driverfs_intf_files (struct usb_interface *intf) void usb_create_sysfs_intf_files (struct usb_interface *intf)
{ {
device_create_file (&intf->dev, &dev_attr_bInterfaceNumber); device_create_file (&intf->dev, &dev_attr_bInterfaceNumber);
device_create_file (&intf->dev, &dev_attr_bAlternateSetting); device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
......
...@@ -998,12 +998,10 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -998,12 +998,10 @@ void usb_disconnect(struct usb_device **pdev)
*/ */
usb_disable_device(dev, 0); usb_disable_device(dev, 0);
dev_dbg (&dev->dev, "unregistering device\n");
/* Free the device number and remove the /proc/bus/usb entry */ /* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) { dev_dbg (&dev->dev, "unregistering device\n");
clear_bit(dev->devnum, dev->bus->devmap.devicemap); usb_release_address(dev);
usbfs_remove_device(dev); usbfs_remove_device(dev);
}
up(&dev->serialize); up(&dev->serialize);
device_unregister(&dev->dev); device_unregister(&dev->dev);
} }
...@@ -1038,24 +1036,23 @@ void usb_choose_address(struct usb_device *dev) ...@@ -1038,24 +1036,23 @@ void usb_choose_address(struct usb_device *dev)
} }
} }
/**
// hub-only!! ... and only exported for reset/reinit path. * usb_release_address - deallocate device address (usbcore-internal)
// otherwise used internally, for usb_new_device() * @dev: newly removed device
int usb_set_address(struct usb_device *dev) *
* Removes and deallocates the address assigned to a device.
* Only hub drivers (but not virtual root hub drivers for host
* controllers) should ever call this.
*/
void usb_release_address(struct usb_device *dev)
{ {
int retval; if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
if (dev->devnum == 0) dev->devnum = -1;
return -EINVAL; }
if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
return -EINVAL;
retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval == 0)
dev->state = USB_STATE_ADDRESS;
return retval;
} }
static inline void usb_show_string(struct usb_device *dev, char *id, int index) static inline void usb_show_string(struct usb_device *dev, char *id, int index)
{ {
char *buf; char *buf;
...@@ -1069,6 +1066,37 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) ...@@ -1069,6 +1066,37 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
kfree(buf); kfree(buf);
} }
static int usb_choose_configuration(struct usb_device *dev)
{
int c, i;
c = dev->config[0].desc.bConfigurationValue;
if (dev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue;
c = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
c, dev->descriptor.bNumConfigurations);
}
return c;
}
/* /*
* usb_new_device - perform initial device setup (usbcore-internal) * usb_new_device - perform initial device setup (usbcore-internal)
* @dev: newly addressed device (in ADDRESS state) * @dev: newly addressed device (in ADDRESS state)
...@@ -1090,8 +1118,7 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) ...@@ -1090,8 +1118,7 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
int usb_new_device(struct usb_device *dev) int usb_new_device(struct usb_device *dev)
{ {
int err; int err;
int i; int c;
int config;
err = usb_get_configuration(dev); err = usb_get_configuration(dev);
if (err < 0) { if (err < 0) {
...@@ -1119,41 +1146,16 @@ int usb_new_device(struct usb_device *dev) ...@@ -1119,41 +1146,16 @@ int usb_new_device(struct usb_device *dev)
dev_err(&dev->dev, "can't device_add, error %d\n", err); dev_err(&dev->dev, "can't device_add, error %d\n", err);
goto fail; goto fail;
} }
usb_create_driverfs_dev_files (dev); usb_create_sysfs_dev_files (dev);
/* choose and set the configuration. that registers the interfaces /* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them. * with the driver core, and lets usb device drivers bind to them.
* NOTE: should interact with hub power budgeting. * NOTE: should interact with hub power budgeting.
*/ */
config = dev->config[0].desc.bConfigurationValue; c = usb_choose_configuration(dev);
if (dev->descriptor.bNumConfigurations != 1) { err = usb_set_configuration(dev, c);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue;
config = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
config,
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev, config);
if (err) { if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n", dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err);
config, err);
device_del(&dev->dev); device_del(&dev->dev);
goto fail; goto fail;
} }
...@@ -1166,8 +1168,7 @@ int usb_new_device(struct usb_device *dev) ...@@ -1166,8 +1168,7 @@ int usb_new_device(struct usb_device *dev)
return 0; return 0;
fail: fail:
dev->state = USB_STATE_NOTATTACHED; dev->state = USB_STATE_NOTATTACHED;
clear_bit(dev->devnum, dev->bus->devmap.devicemap); usb_release_address(dev);
dev->devnum = -1;
usb_put_dev(dev); usb_put_dev(dev);
return err; return err;
} }
......
/* Functions local to drivers/usb/core/ */ /* Functions local to drivers/usb/core/ */
extern void usb_create_driverfs_dev_files (struct usb_device *dev); extern void usb_create_sysfs_dev_files (struct usb_device *dev);
extern void usb_create_driverfs_intf_files (struct usb_interface *intf); extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
extern int usb_probe_interface (struct device *dev); extern int usb_probe_interface (struct device *dev);
extern int usb_unbind_interface (struct device *dev); extern int usb_unbind_interface (struct device *dev);
......
...@@ -95,6 +95,7 @@ config USB_PXA2XX ...@@ -95,6 +95,7 @@ config USB_PXA2XX
config USB_PXA2XX_SMALL config USB_PXA2XX_SMALL
depends on USB_GADGET_PXA2XX depends on USB_GADGET_PXA2XX
bool bool
default n if USB_ETH_RNDIS
default y if USB_ZERO default y if USB_ZERO
default y if USB_ETH default y if USB_ETH
default y if USB_G_SERIAL default y if USB_G_SERIAL
......
...@@ -96,7 +96,8 @@ ep_matches ( ...@@ -96,7 +96,8 @@ ep_matches (
/* for now, avoid PXA "interrupt-in"; /* for now, avoid PXA "interrupt-in";
* it's documented as never using DATA1. * it's documented as never using DATA1.
*/ */
if (gadget_is_pxa (gadget)) if (gadget_is_pxa (gadget)
&& 'i' == tmp [1])
return 0; return 0;
break; break;
case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_BULK:
......
...@@ -154,14 +154,9 @@ do { \ ...@@ -154,14 +154,9 @@ do { \
#define GS_CLOSE_TIMEOUT 15 #define GS_CLOSE_TIMEOUT 15
/* debug macro */ /* debug settings */
#if G_SERIAL_DEBUG #if G_SERIAL_DEBUG
static int debug = G_SERIAL_DEBUG; static int debug = G_SERIAL_DEBUG;
#else
static int debug = 0;
#endif
#if G_SERIAL_DEBUG
#define gs_debug(format, arg...) \ #define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
...@@ -598,8 +593,10 @@ MODULE_DESCRIPTION(GS_LONG_NAME); ...@@ -598,8 +593,10 @@ MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers"); MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#if G_SERIAL_DEBUG
MODULE_PARM(debug, "i"); MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
MODULE_PARM(read_q_size, "i"); MODULE_PARM(read_q_size, "i");
MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32"); MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
......
...@@ -95,6 +95,10 @@ static kmem_cache_t *uhci_up_cachep; /* urb_priv */ ...@@ -95,6 +95,10 @@ static kmem_cache_t *uhci_up_cachep; /* urb_priv */
static int uhci_get_current_frame_number(struct uhci_hcd *uhci); static int uhci_get_current_frame_number(struct uhci_hcd *uhci);
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs);
static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
static void uhci_free_pending_tds(struct uhci_hcd *uhci);
static void hc_state_transitions(struct uhci_hcd *uhci); static void hc_state_transitions(struct uhci_hcd *uhci);
...@@ -373,6 +377,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -373,6 +377,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{ {
struct uhci_qh *pqh; struct uhci_qh *pqh;
u32 newlink; u32 newlink;
unsigned int age;
if (!qh) if (!qh)
return; return;
...@@ -425,6 +430,12 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -425,6 +430,12 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
list_del_init(&qh->urbp->queue_list); list_del_init(&qh->urbp->queue_list);
qh->urbp = NULL; qh->urbp = NULL;
age = uhci_get_current_frame_number(uhci);
if (age != uhci->qh_remove_age) {
uhci_free_pending_qhs(uhci);
uhci->qh_remove_age = age;
}
/* Check to see if the remove list is empty. Set the IOC bit */ /* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the QH */ /* to force an interrupt so we can remove the QH */
if (list_empty(&uhci->qh_remove_list)) if (list_empty(&uhci->qh_remove_list))
...@@ -628,6 +639,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -628,6 +639,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
{ {
struct list_head *head, *tmp; struct list_head *head, *tmp;
struct urb_priv *urbp; struct urb_priv *urbp;
unsigned int age;
urbp = (struct urb_priv *)urb->hcpriv; urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp) if (!urbp)
...@@ -637,6 +649,12 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -637,6 +649,12 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
"or uhci->remove_list!\n", urb); "or uhci->remove_list!\n", urb);
age = uhci_get_current_frame_number(uhci);
if (age != uhci->td_remove_age) {
uhci_free_pending_tds(uhci);
uhci->td_remove_age = age;
}
/* Check to see if the remove list is empty. Set the IOC bit */ /* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the TD's*/ /* to force an interrupt so we can remove the TD's*/
if (list_empty(&uhci->td_remove_list)) if (list_empty(&uhci->td_remove_list))
...@@ -1512,6 +1530,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1512,6 +1530,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags; unsigned long flags;
struct urb_priv *urbp; struct urb_priv *urbp;
unsigned int age;
spin_lock_irqsave(&uhci->schedule_lock, flags); spin_lock_irqsave(&uhci->schedule_lock, flags);
urbp = urb->hcpriv; urbp = urb->hcpriv;
...@@ -1521,6 +1540,12 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1521,6 +1540,12 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
uhci_unlink_generic(uhci, urb); uhci_unlink_generic(uhci, urb);
age = uhci_get_current_frame_number(uhci);
if (age != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci);
uhci->urb_remove_age = age;
}
/* If we're the first, set the next interrupt bit */ /* If we're the first, set the next interrupt bit */
if (list_empty(&uhci->urb_remove_list)) if (list_empty(&uhci->urb_remove_list))
uhci_set_next_interrupt(uhci); uhci_set_next_interrupt(uhci);
...@@ -1590,6 +1615,12 @@ static void stall_callback(unsigned long ptr) ...@@ -1590,6 +1615,12 @@ static void stall_callback(unsigned long ptr)
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
spin_lock_irqsave(&uhci->schedule_lock, flags); spin_lock_irqsave(&uhci->schedule_lock, flags);
if (!list_empty(&uhci->urb_remove_list) &&
uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci);
uhci_finish_completion(hcd, NULL);
}
head = &uhci->urb_list; head = &uhci->urb_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -1728,6 +1759,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1728,6 +1759,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
unsigned short status; unsigned short status;
struct list_head *tmp, *head; struct list_head *tmp, *head;
unsigned int age;
/* /*
* Read the interrupt status, and write it back to clear the * Read the interrupt status, and write it back to clear the
...@@ -1758,11 +1790,20 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1758,11 +1790,20 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
spin_lock(&uhci->schedule_lock); spin_lock(&uhci->schedule_lock);
uhci_free_pending_qhs(uhci); age = uhci_get_current_frame_number(uhci);
uhci_free_pending_tds(uhci); if (age != uhci->qh_remove_age)
uhci_remove_pending_urbps(uhci); uhci_free_pending_qhs(uhci);
if (age != uhci->td_remove_age)
uhci_clear_next_interrupt(uhci); uhci_free_pending_tds(uhci);
if (age != uhci->urb_remove_age)
uhci_remove_pending_urbps(uhci);
if (list_empty(&uhci->urb_remove_list) &&
list_empty(&uhci->td_remove_list) &&
list_empty(&uhci->qh_remove_list))
uhci_clear_next_interrupt(uhci);
else
uhci_set_next_interrupt(uhci);
/* Walk the list of pending URB's to see which ones completed */ /* Walk the list of pending URB's to see which ones completed */
head = &uhci->urb_list; head = &uhci->urb_list;
......
...@@ -357,12 +357,15 @@ struct uhci_hcd { ...@@ -357,12 +357,15 @@ struct uhci_hcd {
/* List of QH's that are done, but waiting to be unlinked (race) */ /* List of QH's that are done, but waiting to be unlinked (race) */
struct list_head qh_remove_list; /* P: uhci->schedule_lock */ struct list_head qh_remove_list; /* P: uhci->schedule_lock */
unsigned int qh_remove_age; /* Age in frames */
/* List of TD's that are done, but waiting to be freed (race) */ /* List of TD's that are done, but waiting to be freed (race) */
struct list_head td_remove_list; /* P: uhci->schedule_lock */ struct list_head td_remove_list; /* P: uhci->schedule_lock */
unsigned int td_remove_age; /* Age in frames */
/* List of asynchronously unlinked URB's */ /* List of asynchronously unlinked URB's */
struct list_head urb_remove_list; /* P: uhci->schedule_lock */ struct list_head urb_remove_list; /* P: uhci->schedule_lock */
unsigned int urb_remove_age; /* Age in frames */
/* List of URB's awaiting completion callback */ /* List of URB's awaiting completion callback */
struct list_head complete_list; /* P: uhci->schedule_lock */ struct list_head complete_list; /* P: uhci->schedule_lock */
......
...@@ -232,7 +232,7 @@ static int hiddev_fasync(int fd, struct file *file, int on) ...@@ -232,7 +232,7 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static struct usb_class_driver hiddev_class; static struct usb_class_driver hiddev_class;
static void hiddev_cleanup(struct hiddev *hiddev) static void hiddev_cleanup(struct hiddev *hiddev)
{ {
hiddev_table[hiddev->hid->minor] = NULL; hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(hiddev->hid->intf, &hiddev_class); usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
kfree(hiddev); kfree(hiddev);
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/usb.h> #include <linux/usb.h>
#define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */
...@@ -67,7 +68,7 @@ struct powermate_device { ...@@ -67,7 +68,7 @@ struct powermate_device {
dma_addr_t configcr_dma; dma_addr_t configcr_dma;
struct usb_device *udev; struct usb_device *udev;
struct input_dev input; struct input_dev input;
struct semaphore lock; spinlock_t lock;
int static_brightness; int static_brightness;
int pulse_speed; int pulse_speed;
int pulse_table; int pulse_table;
...@@ -116,7 +117,7 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) ...@@ -116,7 +117,7 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs)
__FUNCTION__, retval); __FUNCTION__, retval);
} }
/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
static void powermate_sync_state(struct powermate_device *pm) static void powermate_sync_state(struct powermate_device *pm)
{ {
if (pm->requires_update == 0) if (pm->requires_update == 0)
...@@ -194,19 +195,22 @@ static void powermate_sync_state(struct powermate_device *pm) ...@@ -194,19 +195,22 @@ static void powermate_sync_state(struct powermate_device *pm)
static void powermate_config_complete(struct urb *urb, struct pt_regs *regs) static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
{ {
struct powermate_device *pm = urb->context; struct powermate_device *pm = urb->context;
unsigned long flags;
if (urb->status) if (urb->status)
printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
down(&pm->lock); spin_lock_irqsave(&pm->lock, flags);
powermate_sync_state(pm); powermate_sync_state(pm);
up(&pm->lock); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Set the LED up as described and begin the sync with the hardware if required */ /* Set the LED up as described and begin the sync with the hardware if required */
static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
int pulse_table, int pulse_asleep, int pulse_awake) int pulse_table, int pulse_asleep, int pulse_awake)
{ {
unsigned long flags;
if (pulse_speed < 0) if (pulse_speed < 0)
pulse_speed = 0; pulse_speed = 0;
if (pulse_table < 0) if (pulse_table < 0)
...@@ -219,7 +223,8 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne ...@@ -219,7 +223,8 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
pulse_asleep = !!pulse_asleep; pulse_asleep = !!pulse_asleep;
pulse_awake = !!pulse_awake; pulse_awake = !!pulse_awake;
down(&pm->lock);
spin_lock_irqsave(&pm->lock, flags);
/* mark state updates which are required */ /* mark state updates which are required */
if (static_brightness != pm->static_brightness){ if (static_brightness != pm->static_brightness){
...@@ -242,7 +247,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne ...@@ -242,7 +247,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
powermate_sync_state(pm); powermate_sync_state(pm);
up(&pm->lock); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Callback from the Input layer when an event arrives from userspace to configure the LED */ /* Callback from the Input layer when an event arrives from userspace to configure the LED */
...@@ -344,7 +349,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -344,7 +349,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
return -ENOMEM; return -ENOMEM;
} }
init_MUTEX(&pm->lock); pm->lock = SPIN_LOCK_UNLOCKED;
init_input_dev(&pm->input); init_input_dev(&pm->input);
/* get a handle to the interrupt data pipe */ /* get a handle to the interrupt data pipe */
...@@ -411,7 +416,6 @@ static void powermate_disconnect(struct usb_interface *intf) ...@@ -411,7 +416,6 @@ static void powermate_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (pm) { if (pm) {
down(&pm->lock);
pm->requires_update = 0; pm->requires_update = 0;
usb_unlink_urb(pm->irq); usb_unlink_urb(pm->irq);
input_unregister_device(&pm->input); input_unregister_device(&pm->input);
......
...@@ -1240,20 +1240,21 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) ...@@ -1240,20 +1240,21 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
init_waitqueue_head(&awd.wqh); init_waitqueue_head(&awd.wqh);
awd.done = 0; awd.done = 0;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait); add_wait_queue(&awd.wqh, &wait);
urb->context = &awd; urb->context = &awd;
status = usb_submit_urb(urb, GFP_ATOMIC); status = usb_submit_urb(urb, GFP_NOIO);
if (status) { if (status) {
// something went wrong // something went wrong
usb_free_urb(urb); usb_free_urb(urb);
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait); remove_wait_queue(&awd.wqh, &wait);
return status; return status;
} }
while (timeout && !awd.done) set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && !awd.done) {
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
set_current_state(TASK_UNINTERRUPTIBLE);
}
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait); remove_wait_queue(&awd.wqh, &wait);
......
...@@ -136,6 +136,7 @@ struct usb_eth_dev { ...@@ -136,6 +136,7 @@ struct usb_eth_dev {
#define VENDOR_LANEED 0x056e #define VENDOR_LANEED 0x056e
#define VENDOR_LINKSYS 0x066b #define VENDOR_LINKSYS 0x066b
#define VENDOR_MELCO 0x0411 #define VENDOR_MELCO 0x0411
#define VENDOR_MICROSOFT 0x045e
#define VENDOR_MOBILITY 0x1342 #define VENDOR_MOBILITY 0x1342
#define VENDOR_NETGEAR 0x0846 #define VENDOR_NETGEAR 0x0846
#define VENDOR_OCT 0x0b39 #define VENDOR_OCT 0x0b39
...@@ -265,6 +266,8 @@ PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, ...@@ -265,6 +266,8 @@ PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009, PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020, PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
......
...@@ -314,8 +314,8 @@ config USB_SERIAL_KLSI ...@@ -314,8 +314,8 @@ config USB_SERIAL_KLSI
module will be called kl5kusb105. module will be called kl5kusb105.
config USB_SERIAL_KOBIL_SCT config USB_SERIAL_KOBIL_SCT
tristate "USB KOBIL chipcard reader (EXPERIMENTAL)" tristate "USB KOBIL chipcard reader"
depends on USB_SERIAL && EXPERIMENTAL depends on USB_SERIAL
---help--- ---help---
Say Y here if you want to use one of the following KOBIL USB chipcard Say Y here if you want to use one of the following KOBIL USB chipcard
readers: readers:
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation * and extra documentation
* *
* (27/May/2004) Ian Abbott
* Improved throttling code, mostly stolen from the WhiteHEAT driver.
*
* (26/Mar/2004) Jan Capek * (26/Mar/2004) Jan Capek
* Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc. * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
* *
...@@ -584,6 +587,10 @@ static struct usb_driver ftdi_driver = { ...@@ -584,6 +587,10 @@ static struct usb_driver ftdi_driver = {
#define BUFSZ 512 #define BUFSZ 512
#define PKTSZ 64 #define PKTSZ 64
/* rx_flags */
#define THROTTLED 0x01
#define ACTUALLY_THROTTLED 0x02
struct ftdi_private { struct ftdi_private {
ftdi_chip_type_t chip_type; ftdi_chip_type_t chip_type;
/* type of the device, either SIO or FT8U232AM */ /* type of the device, either SIO or FT8U232AM */
...@@ -598,6 +605,8 @@ struct ftdi_private { ...@@ -598,6 +605,8 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */ unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */ char prev_status, diff_status; /* Used for TIOCMIWAIT */
__u8 rx_flags; /* receive state flags (throttling) */
spinlock_t rx_lock; /* spinlock for receive state */
int force_baud; /* if non-zero, force the baud rate to this value */ int force_baud; /* if non-zero, force the baud rate to this value */
int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
...@@ -625,6 +634,7 @@ static int ftdi_write_room (struct usb_serial_port *port); ...@@ -625,6 +634,7 @@ static int ftdi_write_room (struct usb_serial_port *port);
static int ftdi_chars_in_buffer (struct usb_serial_port *port); static int ftdi_chars_in_buffer (struct usb_serial_port *port);
static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs); static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs); static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_process_read (struct usb_serial_port *port);
static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file);
static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
...@@ -1110,6 +1120,7 @@ static int ftdi_common_startup (struct usb_serial *serial) ...@@ -1110,6 +1120,7 @@ static int ftdi_common_startup (struct usb_serial *serial)
} }
memset(priv, 0, sizeof(*priv)); memset(priv, 0, sizeof(*priv));
spin_lock_init(&priv->rx_lock);
init_waitqueue_head(&priv->delta_msr_wait); init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather /* This will push the characters through immediately rather
than queue a task to deliver them */ than queue a task to deliver them */
...@@ -1273,8 +1284,8 @@ static void ftdi_shutdown (struct usb_serial *serial) ...@@ -1273,8 +1284,8 @@ static void ftdi_shutdown (struct usb_serial *serial)
*/ */
if (priv) { if (priv) {
kfree(priv);
usb_set_serial_port_data(port, NULL); usb_set_serial_port_data(port, NULL);
kfree(priv);
} }
} /* ftdi_shutdown */ } /* ftdi_shutdown */
...@@ -1284,6 +1295,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) ...@@ -1284,6 +1295,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
struct termios tmp_termios; struct termios tmp_termios;
struct usb_device *dev = port->serial->dev; struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
int result = 0; int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */ char buf[1]; /* Needed for the usb_control_msg I think */
...@@ -1317,6 +1329,11 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) ...@@ -1317,6 +1329,11 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
err("%s Error from RTS HIGH urb", __FUNCTION__); err("%s Error from RTS HIGH urb", __FUNCTION__);
} }
/* Not throttled */
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
spin_unlock_irqrestore(&priv->rx_lock, flags);
/* Start reading from the device */ /* Start reading from the device */
usb_fill_bulk_urb(port->read_urb, dev, usb_fill_bulk_urb(port->read_urb, dev,
usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress), usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
...@@ -1370,7 +1387,12 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) ...@@ -1370,7 +1387,12 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
/* shutdown our bulk read */ /* shutdown our bulk read */
if (port->read_urb) { if (port->read_urb) {
if (usb_unlink_urb (port->read_urb) < 0) { if (usb_unlink_urb (port->read_urb) < 0) {
err("Error unlinking read urb"); /* Generally, this isn't an error. If the previous
read bulk callback occurred (or is about to occur)
while the port was being closed or was throtted
(and is still throttled), the read urb will not
have been submitted. */
dbg("%s - failed to unlink read urb (generally not an error)", __FUNCTION__);
} }
} }
} /* ftdi_close */ } /* ftdi_close */
...@@ -1546,13 +1568,6 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1546,13 +1568,6 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty; struct tty_struct *tty;
struct ftdi_private *priv; struct ftdi_private *priv;
char error_flag;
unsigned char *data = urb->transfer_buffer;
int i;
int result;
int need_flip;
int packet_offset;
if (urb->number_of_packets > 0) { if (urb->number_of_packets > 0) {
err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
...@@ -1560,7 +1575,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1560,7 +1575,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags ); err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags );
} }
dbg("%s", __FUNCTION__); dbg("%s - port %d", __FUNCTION__, port->number);
if (port->open_count <= 0) if (port->open_count <= 0)
return; return;
...@@ -1572,6 +1587,14 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1572,6 +1587,14 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
} }
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
return;
}
if (urb != port->read_urb) {
err("%s - Not my urb!", __FUNCTION__);
}
if (urb->status) { if (urb->status) {
/* This will happen at close every time so it is a dbg not an err */ /* This will happen at close every time so it is a dbg not an err */
...@@ -1579,6 +1602,59 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1579,6 +1602,59 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return; return;
} }
/* If throttled, delay receive processing until unthrottled. */
spin_lock(&priv->rx_lock);
if (priv->rx_flags & THROTTLED) {
dbg("Deferring read urb processing until unthrottled");
priv->rx_flags |= ACTUALLY_THROTTLED;
spin_unlock(&priv->rx_lock);
return;
}
spin_unlock(&priv->rx_lock);
ftdi_process_read(port);
} /* ftdi_read_bulk_callback */
static void ftdi_process_read (struct usb_serial_port *port)
{ /* ftdi_process_read */
struct urb *urb;
struct tty_struct *tty;
struct ftdi_private *priv;
char error_flag;
unsigned char *data;
int i;
int result;
int need_flip;
int packet_offset;
dbg("%s - port %d", __FUNCTION__, port->number);
if (port->open_count <= 0)
return;
tty = port->tty;
if (!tty) {
dbg("%s - bad tty pointer - exiting",__FUNCTION__);
return;
}
priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
return;
}
urb = port->read_urb;
if (!urb) {
dbg("%s - bad read_urb pointer - exiting", __FUNCTION__);
return;
}
data = urb->transfer_buffer;
/* The first two bytes of every read packet are status */ /* The first two bytes of every read packet are status */
if (urb->actual_length > 2) { if (urb->actual_length > 2) {
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
...@@ -1683,7 +1759,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1683,7 +1759,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
} }
return; return;
} /* ftdi_read_bulk_callback */ } /* ftdi_process_read */
static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
...@@ -2073,27 +2149,32 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne ...@@ -2073,27 +2149,32 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
static void ftdi_throttle (struct usb_serial_port *port) static void ftdi_throttle (struct usb_serial_port *port)
{ {
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
usb_unlink_urb (port->read_urb);
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags |= THROTTLED;
spin_unlock_irqrestore(&priv->rx_lock, flags);
} }
static void ftdi_unthrottle (struct usb_serial_port *port) static void ftdi_unthrottle (struct usb_serial_port *port)
{ {
int result; struct ftdi_private *priv = usb_get_serial_port_data(port);
int actually_throttled;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
port->read_urb->dev = port->serial->dev; spin_lock_irqsave(&priv->rx_lock, flags);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
usb_fill_bulk_urb(port->read_urb, port->serial->dev, priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), spin_unlock_irqrestore(&priv->rx_lock, flags);
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (actually_throttled)
if (result) ftdi_process_read(port);
err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
} }
static int __init ftdi_init (void) static int __init ftdi_init (void)
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
* Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
* (Adapter K), B1 Professional and KAAN Professional (Adapter B) * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
* *
* (21/05/2004) tw
* Fix bug with P'n'P readers
*
* (28/05/2003) tw * (28/05/2003) tw
* Add support for KAAN SIM * Add support for KAAN SIM
* *
...@@ -59,7 +62,7 @@ ...@@ -59,7 +62,7 @@
#include "usb-serial.h" #include "usb-serial.h"
/* Version Information */ /* Version Information */
#define DRIVER_VERSION "28/05/2003" #define DRIVER_VERSION "21/05/2004"
#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)" #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
...@@ -339,6 +342,12 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) ...@@ -339,6 +342,12 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
); );
dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
} }
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
// start reading (Adapter B 'cause PNP string)
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC );
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
}
kfree(transfer_buffer); kfree(transfer_buffer);
return 0; return 0;
...@@ -456,6 +465,11 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -456,6 +465,11 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) ||
((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) { ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
// stop reading (except TWIN and KAAN SIM)
if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
usb_unlink_urb( port->interrupt_in_urb );
}
todo = priv->filled - priv->cur_pos; todo = priv->filled - priv->cur_pos;
while(todo > 0) { while(todo > 0) {
...@@ -463,25 +477,23 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -463,25 +477,23 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
length = (todo < 8) ? todo : 8; length = (todo < 8) ? todo : 8;
// copy data to transfer buffer // copy data to transfer buffer
memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length ); memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
usb_fill_int_urb( port->write_urb,
usb_fill_bulk_urb( port->write_urb, port->serial->dev,
port->serial->dev, usb_sndintpipe(port->serial->dev, priv->write_int_endpoint_address),
usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address), port->write_urb->transfer_buffer,
port->write_urb->transfer_buffer, length,
length, kobil_write_callback,
kobil_write_callback, port,
port 8
); );
priv->cur_pos = priv->cur_pos + length; priv->cur_pos = priv->cur_pos + length;
result = usb_submit_urb( port->write_urb, GFP_ATOMIC ); result = usb_submit_urb( port->write_urb, GFP_NOIO );
dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
todo = priv->filled - priv->cur_pos; todo = priv->filled - priv->cur_pos;
if (todo > 0) { if (todo > 0) {
//mdelay(16); msleep(24);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(24 * HZ / 1000);
} }
} // end while } // end while
...@@ -492,9 +504,14 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -492,9 +504,14 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
// someone sets the dev to 0 if the close method has been called // someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
// start reading // start reading (except TWIN and KAAN SIM)
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result); // someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb( port->interrupt_in_urb, GFP_NOIO );
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
}
} }
return count; return count;
} }
......
...@@ -680,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -680,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
char *string; char *string;
int retval = 0; int retval = 0;
int i; int i;
int num_ports; int num_ports = 0;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
...@@ -702,41 +702,50 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -702,41 +702,50 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
__FUNCTION__, retval); __FUNCTION__, retval);
goto exit; goto exit;
} }
connection_info = (struct visor_connection_info *)transfer_buffer;
le16_to_cpus(&connection_info->num_ports);
num_ports = connection_info->num_ports;
/* handle devices that report invalid stuff here */
if (num_ports > 2)
num_ports = 2;
dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
connection_info->num_ports);
for (i = 0; i < num_ports; ++i) { if (retval == sizeof(*connection_info)) {
switch (connection_info->connections[i].port_function_id) { connection_info = (struct visor_connection_info *)transfer_buffer;
case VISOR_FUNCTION_GENERIC:
string = "Generic"; le16_to_cpus(&connection_info->num_ports);
break; num_ports = connection_info->num_ports;
case VISOR_FUNCTION_DEBUGGER:
string = "Debugger"; for (i = 0; i < num_ports; ++i) {
break; switch (connection_info->connections[i].port_function_id) {
case VISOR_FUNCTION_HOTSYNC: case VISOR_FUNCTION_GENERIC:
string = "HotSync"; string = "Generic";
break; break;
case VISOR_FUNCTION_CONSOLE: case VISOR_FUNCTION_DEBUGGER:
string = "Console"; string = "Debugger";
break; break;
case VISOR_FUNCTION_REMOTE_FILE_SYS: case VISOR_FUNCTION_HOTSYNC:
string = "Remote File System"; string = "HotSync";
break; break;
default: case VISOR_FUNCTION_CONSOLE:
string = "unknown"; string = "Console";
break; break;
case VISOR_FUNCTION_REMOTE_FILE_SYS:
string = "Remote File System";
break;
default:
string = "unknown";
break;
}
dev_info(dev, "%s: port %d, is for %s use\n",
serial->type->name,
connection_info->connections[i].port, string);
} }
dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
connection_info->connections[i].port, string);
} }
/*
* Handle devices that report invalid stuff here.
*/
if (num_ports == 0 || num_ports > 2) {
dev_warn (dev, "%s: No valid connect info available\n",
serial->type->name);
num_ports = 2;
}
dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
num_ports);
/* /*
* save off our num_ports info so that we can use it in the * save off our num_ports info so that we can use it in the
...@@ -868,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial) ...@@ -868,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
static int treo_attach (struct usb_serial *serial) static int treo_attach (struct usb_serial *serial)
{ {
struct usb_serial_port *port; struct usb_serial_port *swap_port;
int i;
/* Only do this endpoint hack for the Handspring devices with /* Only do this endpoint hack for the Handspring devices with
* interrupt in endpoints, which for now are the Treo devices. */ * interrupt in endpoints, which for now are the Treo devices. */
...@@ -879,31 +887,28 @@ static int treo_attach (struct usb_serial *serial) ...@@ -879,31 +887,28 @@ static int treo_attach (struct usb_serial *serial)
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
/* Ok, this is pretty ugly, but these devices want to use the /*
* interrupt endpoint as paired up with a bulk endpoint for a * It appears that Treos want to use the 1st interrupt endpoint to
* "virtual serial port". So let's force the endpoints to be * communicate with the 2nd bulk out endpoint, so let's swap the 1st
* where we want them to be. */ * and 2nd bulk in and interrupt endpoints. Note that swapping the
for (i = serial->num_bulk_in; i < serial->num_ports; ++i) { * bulk out endpoints would break lots of apps that want to communicate
port = serial->port[i]; * on the second port.
port->read_urb = serial->port[0]->read_urb; */
port->bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress; #define COPY_PORT(dest, src) \
port->bulk_in_buffer = serial->port[0]->bulk_in_buffer; dest->read_urb = src->read_urb; \
} dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress; \
dest->bulk_in_buffer = src->bulk_in_buffer; \
for (i = serial->num_bulk_out; i < serial->num_ports; ++i) { dest->interrupt_in_urb = src->interrupt_in_urb; \
port = serial->port[i]; dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress; \
port->write_urb = serial->port[0]->write_urb; dest->interrupt_in_buffer = src->interrupt_in_buffer;
port->bulk_out_size = serial->port[0]->bulk_out_size;
port->bulk_out_endpointAddress = serial->port[0]->bulk_out_endpointAddress; swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
port->bulk_out_buffer = serial->port[0]->bulk_out_buffer; if (!swap_port)
} return -ENOMEM;
COPY_PORT(swap_port, serial->port[0]);
for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) { COPY_PORT(serial->port[0], serial->port[1]);
port = serial->port[i]; COPY_PORT(serial->port[1], swap_port);
port->interrupt_in_urb = serial->port[0]->interrupt_in_urb; kfree(swap_port);
port->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
port->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
}
return 0; return 0;
} }
......
...@@ -1112,8 +1112,7 @@ static int usb_stor_reset_common(struct us_data *us, ...@@ -1112,8 +1112,7 @@ static int usb_stor_reset_common(struct us_data *us,
/* long wait for reset, so unlock to allow disconnects */ /* long wait for reset, so unlock to allow disconnects */
up(&us->dev_semaphore); up(&us->dev_semaphore);
set_current_state(TASK_UNINTERRUPTIBLE); msleep(6000);
schedule_timeout(HZ*6);
down(&us->dev_semaphore); down(&us->dev_semaphore);
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("Reset interrupted by disconnect\n"); US_DEBUGP("Reset interrupted by disconnect\n");
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include "sysfs.h" #include "sysfs.h"
DECLARE_RWSEM(sysfs_rename_sem);
static int init_dir(struct inode * inode) static int init_dir(struct inode * inode)
{ {
inode->i_op = &simple_dir_inode_operations; inode->i_op = &simple_dir_inode_operations;
...@@ -134,8 +136,14 @@ void sysfs_remove_dir(struct kobject * kobj) ...@@ -134,8 +136,14 @@ void sysfs_remove_dir(struct kobject * kobj)
/** /**
* Unlink and unhash. * Unlink and unhash.
*/ */
__d_drop(d);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
d_delete(d); /* release the target kobject in case of
* a symlink
*/
if (S_ISLNK(d->d_inode->i_mode))
kobject_put(d->d_fsdata);
simple_unlink(dentry->d_inode,d); simple_unlink(dentry->d_inode,d);
dput(d); dput(d);
pr_debug(" done\n"); pr_debug(" done\n");
...@@ -165,6 +173,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) ...@@ -165,6 +173,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
if (!kobj->parent) if (!kobj->parent)
return -EINVAL; return -EINVAL;
down_write(&sysfs_rename_sem);
parent = kobj->parent->dentry; parent = kobj->parent->dentry;
down(&parent->d_inode->i_sem); down(&parent->d_inode->i_sem);
...@@ -179,6 +188,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) ...@@ -179,6 +188,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
dput(new_dentry); dput(new_dentry);
} }
up(&parent->d_inode->i_sem); up(&parent->d_inode->i_sem);
up_write(&sysfs_rename_sem);
return error; return error;
} }
......
...@@ -96,7 +96,12 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name) ...@@ -96,7 +96,12 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name)
pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name, pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name,
atomic_read(&victim->d_count)); atomic_read(&victim->d_count));
d_delete(victim); d_drop(victim);
/* release the target kobject in case of
* a symlink
*/
if (S_ISLNK(victim->d_inode->i_mode))
kobject_put(victim->d_fsdata);
simple_unlink(dir->d_inode,victim); simple_unlink(dir->d_inode,victim);
} }
/* /*
......
...@@ -8,27 +8,17 @@ ...@@ -8,27 +8,17 @@
#include "sysfs.h" #include "sysfs.h"
static struct inode_operations sysfs_symlink_inode_operations = {
.readlink = sysfs_readlink,
.follow_link = sysfs_follow_link,
};
static int init_symlink(struct inode * inode) static int init_symlink(struct inode * inode)
{ {
inode->i_op = &page_symlink_inode_operations; inode->i_op = &sysfs_symlink_inode_operations;
return 0; return 0;
} }
static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
{
int error;
error = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
if (!error) {
int l = strlen(symname)+1;
error = page_symlink(dentry->d_inode, symname, l);
if (error)
iput(dentry->d_inode);
}
return error;
}
static int object_depth(struct kobject * kobj) static int object_depth(struct kobject * kobj)
{ {
struct kobject * p = kobj; struct kobject * p = kobj;
...@@ -74,37 +64,20 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * nam ...@@ -74,37 +64,20 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * nam
struct dentry * dentry = kobj->dentry; struct dentry * dentry = kobj->dentry;
struct dentry * d; struct dentry * d;
int error = 0; int error = 0;
int size;
int depth;
char * path;
char * s;
depth = object_depth(kobj);
size = object_path_length(target) + depth * 3 - 1;
if (size > PATH_MAX)
return -ENAMETOOLONG;
pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
path = kmalloc(size,GFP_KERNEL);
if (!path)
return -ENOMEM;
memset(path,0,size);
for (s = path; depth--; s += 3)
strcpy(s,"../");
fill_object_path(target,path,size);
pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
down(&dentry->d_inode->i_sem); down(&dentry->d_inode->i_sem);
d = sysfs_get_dentry(dentry,name); d = sysfs_get_dentry(dentry,name);
if (!IS_ERR(d)) if (!IS_ERR(d)) {
error = sysfs_symlink(dentry->d_inode,d,path); error = sysfs_create(d, S_IFLNK|S_IRWXUGO, init_symlink);
else if (!error)
/*
* associate the link dentry with the target kobject
*/
d->d_fsdata = kobject_get(target);
dput(d);
} else
error = PTR_ERR(d); error = PTR_ERR(d);
dput(d);
up(&dentry->d_inode->i_sem); up(&dentry->d_inode->i_sem);
kfree(path);
return error; return error;
} }
...@@ -120,6 +93,86 @@ void sysfs_remove_link(struct kobject * kobj, char * name) ...@@ -120,6 +93,86 @@ void sysfs_remove_link(struct kobject * kobj, char * name)
sysfs_hash_and_remove(kobj->dentry,name); sysfs_hash_and_remove(kobj->dentry,name);
} }
static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
char *path)
{
char * s;
int depth, size;
depth = object_depth(kobj);
size = object_path_length(target) + depth * 3 - 1;
if (size > PATH_MAX)
return -ENAMETOOLONG;
pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
for (s = path; depth--; s += 3)
strcpy(s,"../");
fill_object_path(target, path, size);
pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
return 0;
}
static int sysfs_getlink(struct dentry *dentry, char * path)
{
struct kobject *kobj, *target_kobj;
int error = 0;
kobj = sysfs_get_kobject(dentry->d_parent);
if (!kobj)
return -EINVAL;
target_kobj = sysfs_get_kobject(dentry);
if (!target_kobj) {
kobject_put(kobj);
return -EINVAL;
}
down_read(&sysfs_rename_sem);
error = sysfs_get_target_path(kobj, target_kobj, path);
up_read(&sysfs_rename_sem);
kobject_put(kobj);
kobject_put(target_kobj);
return error;
}
int sysfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
int error = 0;
unsigned long page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
error = sysfs_getlink(dentry, (char *) page);
if (!error)
error = vfs_readlink(dentry, buffer, buflen, (char *) page);
free_page(page);
return error;
}
int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int error = 0;
unsigned long page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
error = sysfs_getlink(dentry, (char *) page);
if (!error)
error = vfs_follow_link(nd, (char *) page);
free_page(page);
return error;
}
EXPORT_SYMBOL(sysfs_create_link); EXPORT_SYMBOL(sysfs_create_link);
EXPORT_SYMBOL(sysfs_remove_link); EXPORT_SYMBOL(sysfs_remove_link);
......
...@@ -12,15 +12,18 @@ extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); ...@@ -12,15 +12,18 @@ extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
extern void sysfs_remove_subdir(struct dentry *); extern void sysfs_remove_subdir(struct dentry *);
extern int sysfs_readlink(struct dentry *, char __user *, int );
extern int sysfs_follow_link(struct dentry *, struct nameidata *);
extern struct rw_semaphore sysfs_rename_sem;
static inline struct kobject *sysfs_get_kobject(struct dentry *dentry) static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)
{ {
struct kobject * kobj = NULL; struct kobject * kobj = NULL;
spin_lock(&dentry->d_lock); spin_lock(&dcache_lock);
if (!d_unhashed(dentry)) if (!d_unhashed(dentry))
kobj = kobject_get(dentry->d_fsdata); kobj = kobject_get(dentry->d_fsdata);
spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock);
return kobj; return kobj;
} }
...@@ -231,6 +231,7 @@ struct device; ...@@ -231,6 +231,7 @@ struct device;
struct dev_pm_info { struct dev_pm_info {
u32 power_state; u32 power_state;
#ifdef CONFIG_PM #ifdef CONFIG_PM
u32 prev_state;
u8 * saved_state; u8 * saved_state;
atomic_t pm_users; atomic_t pm_users;
struct device * pm_parent; struct device * pm_parent;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment