Hi,
here's my little usb story...

Well, I'm using a laptop. I'm using a port replicator for this laptop. I have a
usb keyboard with a hub to which a usb wheel mouse is connected. This
combination is connected to the port replicator of the laptop. So I patched
my 2.2.15 kernel with usb-2.3.99-pre7-1-for-2.2.14.diff.gz from suse.cz.

I was happy that everything worked fine. Until I did a suspend/resume cycle
which caused usb to stop working. Well, no problem I thought, this is
development code so let's have a look.

Hmm, there was power management functionality included, so I added a kernel
message to the power management function to see what's happening and surprise:
it was never even called.

So I started a search for pm_register which resulted in:
#define pm_register 0

So power management, though included, is effectively disabled in the 2.2.x
kernels with the current usb back port patch. Now this is something that
shouldn't happen. I do perfectly understand that usb is under development and
that this development is done in the 2.3.x series. But if there are 'official'
back ports to the 2.2.x kernels there should be at least some functional checks
of the back port. It doesn't help if a back port is functionally crippled and
thus doesn't work on those systems which do really require it.

Ok, I'll stop ranting here. That's because of the quick hack below. It is
really not nice and only tested in usb-uhci.c, but nevertheless usb now
survives suspend/resume cycles. If anybody got the same problem as me, find the
source code for the usb driver you need, insert the code below before the first
function in the usb driver source, rebuild kernel or modules according to your
personal configuration and try.

And for the back porting people: please include the usual apm callback
functionality in the back ports, this will save the mailing list quite some
problem reports.

------------------ cut here ------------------

#ifdef CONFIG_APM
#ifdef pm_register
#undef pm_register
#ifdef pm_unregister_all
#undef pm_unregister_all
#else
#error "Hmm, pm register defined, pm_unregister_all not"
#endif
#ifdef PM_PCI_DEV
#undef PM_PCI_DEV
#endif
#define PM_PCI_DEV 0
#ifdef PM_PCI_ID
#undef PM_PCI_ID
#endif
#define PM_PCI_ID(a) a
#ifndef APM_SUCCESS
#include <linux/apm_bios.h>
#endif
static struct {
        int used;
        int (*handler)(struct pm_dev *,pm_request_t,void *);
        struct pci_dev *b;
        struct pm_dev dev;
} fake[10]=
{
{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}
};
static int fakeinit=0;
static int fakepm(apm_event_t event)
{
int i;
switch(event)
{
case APM_SYS_SUSPEND:
case APM_CRITICAL_SUSPEND:
case APM_USER_SUSPEND:
        for(i=0;i<10;i++)
          if(fake[i].used)
            fake[i].handler(&fake[i].dev,PM_SUSPEND,NULL);
                break;
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
        for(i=0;i<10;i++)
          if(fake[i].used)
            fake[i].handler(&fake[i].dev,PM_RESUME,NULL);
                break;
}
return APM_SUCCESS;
}
static struct pm_dev *pm_register(int a,struct pci_dev *b,
  int (*handle_pm_event)(struct pm_dev *, pm_request_t, void *))
{
int i;
for(i=0;i<10;i++)if(fake[i].used&&fake[i].b==b)return NULL;
for(i=0;i<10;i++)if(!fake[i].used)
{
fake[i].handler=handle_pm_event;
fake[i].b=b;
fake[i].used=1;
if(!fakeinit)
{
        if(apm_register_callback(fakepm)==APM_SUCCESS)fakeinit=1;
}
return &fake[i].dev;
}
return NULL;
}
static void pm_unregister_all(
int (*handle_pm_event)(struct pm_dev *, pm_request_t, void *))
{
int i;
for(i=0;i<10;i++)
  if(fake[i].handler==handle_pm_event&&fake[i].used)
    fake[i].used=0;
for(i=0;i<10;i++)if(fake[i].used)return;
if(fakeinit)
{
        apm_unregister_callback(fakepm);
        fakeinit=0;
}
}
#endif
#endif


Andreas Steinmetz
D.O.M. Datenverarbeitung GmbH

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to