From 185849991d592497e43bcd264c6152af1261ffe2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 14 Aug 2006 23:11:06 -0700 Subject: PM: USB HCDs use PM_EVENT_PRETHAW This teaches several USB host controller drivers to treat PRETHAW as a chip reset since the controller, and all devices connected to it, are no longer in states compatible with how the snapshotted suspend() left them. Signed-off-by: David Brownell Cc: "Rafael J. Wysocki" Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 6 ++++++ drivers/usb/host/ohci-pci.c | 5 +++++ drivers/usb/host/sl811-hcd.c | 9 +++++++-- drivers/usb/host/uhci-hcd.c | 4 ++++ 4 files changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index cadffacd945..6967ab71e28 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -238,6 +238,12 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) writel (0, &ehci->regs->intr_enable); (void)readl(&ehci->regs->intr_enable); + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) { + ehci_halt(ehci); + ehci_reset(ehci); + } + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); bail: spin_unlock_irqrestore (&ehci->lock, flags); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index b268537e389..37e122812b6 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -135,6 +135,11 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); + + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + ohci_usb_reset(ohci); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); bail: spin_unlock_irqrestore (&ohci->lock, flags); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index fa34092bbcd..9de115d9db2 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1783,10 +1783,15 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state) struct sl811 *sl811 = hcd_to_sl811(hcd); int retval = 0; - if (state.event == PM_EVENT_FREEZE) + switch (state.event) { + case PM_EVENT_FREEZE: retval = sl811h_bus_suspend(hcd); - else if (state.event == PM_EVENT_SUSPEND) + break; + case PM_EVENT_SUSPEND: + case PM_EVENT_PRETHAW: /* explicitly discard hw state */ port_power(sl811, 0); + break; + } if (retval == 0) dev->dev.power.power_state = state; return retval; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4151f618602..b7402ceb3e9 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -734,6 +734,10 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) /* FIXME: Enable non-PME# remote wakeup? */ + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + uhci_hc_died(uhci); + done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); done: -- cgit v1.2.3-70-g09d2 From 1a1d92c10dd24bbdc28b3d6e2d03ec199dd3a65b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 27 Sep 2006 01:49:40 -0700 Subject: [PATCH] Really ignore kmem_cache_destroy return value * Rougly half of callers already do it by not checking return value * Code in drivers/acpi/osl.c does the following to be sure: (void)kmem_cache_destroy(cache); * Those who check it printk something, however, slab_error already printed the name of failed cache. * XFS BUGs on failed kmem_cache_destroy which is not the decision low-level filesystem driver should make. Converted to ignore. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/osl.c | 2 +- drivers/infiniband/core/mad.c | 5 +---- drivers/usb/host/uhci-hcd.c | 8 ++------ fs/adfs/super.c | 3 +-- fs/affs/super.c | 3 +-- fs/befs/linuxvfs.c | 4 +--- fs/bfs/inode.c | 3 +-- fs/cifs/cifsfs.c | 20 +++++--------------- fs/coda/inode.c | 3 +-- fs/efs/super.c | 3 +-- fs/ext2/super.c | 3 +-- fs/ext3/super.c | 3 +-- fs/fat/cache.c | 3 +-- fs/fat/inode.c | 3 +-- fs/hfs/super.c | 3 +-- fs/hfsplus/super.c | 3 +-- fs/hpfs/super.c | 3 +-- fs/isofs/inode.c | 4 +--- fs/minix/inode.c | 3 +-- fs/ncpfs/inode.c | 3 +-- fs/nfs/direct.c | 3 +-- fs/nfs/inode.c | 3 +-- fs/nfs/pagelist.c | 3 +-- fs/nfs/read.c | 3 +-- fs/nfs/write.c | 3 +-- fs/nfsd/nfs4state.c | 5 +---- fs/ntfs/super.c | 28 +++++----------------------- fs/ocfs2/dlm/dlmfs.c | 4 +--- fs/qnx4/inode.c | 4 +--- fs/reiserfs/super.c | 4 +--- fs/romfs/inode.c | 3 +-- fs/smbfs/inode.c | 3 +-- fs/smbfs/request.c | 3 +-- fs/udf/super.c | 3 +-- fs/ufs/super.c | 3 +-- fs/xfs/linux-2.6/kmem.h | 4 ++-- ipc/mqueue.c | 5 +---- mm/shmem.c | 3 +-- net/sunrpc/rpc_pipe.c | 3 +-- net/sunrpc/sched.c | 8 ++++---- 40 files changed, 53 insertions(+), 130 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 507f051d1ce..20beea778ea 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1079,7 +1079,7 @@ acpi_status acpi_os_purge_cache(acpi_cache_t * cache) acpi_status acpi_os_delete_cache(acpi_cache_t * cache) { - (void)kmem_cache_destroy(cache); + kmem_cache_destroy(cache); return (AE_OK); } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 082f03c158f..493f4c65c7a 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2987,10 +2987,7 @@ error1: static void __exit ib_mad_cleanup_module(void) { ib_unregister_client(&mad_client); - - if (kmem_cache_destroy(ib_mad_cache)) { - printk(KERN_DEBUG PFX "Failed to destroy ib_mad cache\n"); - } + kmem_cache_destroy(ib_mad_cache); } module_init(ib_mad_init_module); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index b7402ceb3e9..eb4eab98e8b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -913,8 +913,7 @@ static int __init uhci_hcd_init(void) return 0; init_failed: - if (kmem_cache_destroy(uhci_up_cachep)) - warn("not all urb_privs were freed!"); + kmem_cache_destroy(uhci_up_cachep); up_failed: debugfs_remove(uhci_debugfs_root); @@ -930,10 +929,7 @@ errbuf_failed: static void __exit uhci_hcd_cleanup(void) { pci_unregister_driver(&uhci_pci_driver); - - if (kmem_cache_destroy(uhci_up_cachep)) - warn("not all urb_privs were freed!"); - + kmem_cache_destroy(uhci_up_cachep); debugfs_remove(uhci_debugfs_root); kfree(errbuf); } diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 959dbf1f8e6..9ade139086f 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -251,8 +251,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(adfs_inode_cachep)) - printk(KERN_INFO "adfs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(adfs_inode_cachep); } static struct super_operations adfs_sops = { diff --git a/fs/affs/super.c b/fs/affs/super.c index b35f514479b..5ea72c3a16c 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -109,8 +109,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(affs_inode_cachep)) - printk(KERN_INFO "affs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(affs_inode_cachep); } static struct super_operations affs_sops = { diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 50cfca5c7ef..f6676fbe948 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -446,9 +446,7 @@ befs_init_inodecache(void) static void befs_destroy_inodecache(void) { - if (kmem_cache_destroy(befs_inode_cachep)) - printk(KERN_ERR "befs_destroy_inodecache: " - "not all structures were freed\n"); + kmem_cache_destroy(befs_inode_cachep); } /* diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 3e4d6c767b9..8fc2e8e49db 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -268,8 +268,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(bfs_inode_cachep)) - printk(KERN_INFO "bfs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(bfs_inode_cachep); } static struct super_operations bfs_sops = { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c3ef1c0d0e6..4197a5043f1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -699,8 +699,7 @@ cifs_init_inodecache(void) static void cifs_destroy_inodecache(void) { - if (kmem_cache_destroy(cifs_inode_cachep)) - printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); + kmem_cache_destroy(cifs_inode_cachep); } static int @@ -778,13 +777,9 @@ static void cifs_destroy_request_bufs(void) { mempool_destroy(cifs_req_poolp); - if (kmem_cache_destroy(cifs_req_cachep)) - printk(KERN_WARNING - "cifs_destroy_request_cache: error not all structures were freed\n"); + kmem_cache_destroy(cifs_req_cachep); mempool_destroy(cifs_sm_req_poolp); - if (kmem_cache_destroy(cifs_sm_req_cachep)) - printk(KERN_WARNING - "cifs_destroy_request_cache: cifs_small_rq free error\n"); + kmem_cache_destroy(cifs_sm_req_cachep); } static int @@ -819,13 +814,8 @@ static void cifs_destroy_mids(void) { mempool_destroy(cifs_mid_poolp); - if (kmem_cache_destroy(cifs_mid_cachep)) - printk(KERN_WARNING - "cifs_destroy_mids: error not all structures were freed\n"); - - if (kmem_cache_destroy(cifs_oplock_cachep)) - printk(KERN_WARNING - "error not all oplock structures were freed\n"); + kmem_cache_destroy(cifs_mid_cachep); + kmem_cache_destroy(cifs_oplock_cachep); } static int cifs_oplock_thread(void * dummyarg) diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 87f1dc8aa24..88d12332116 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -80,8 +80,7 @@ int coda_init_inodecache(void) void coda_destroy_inodecache(void) { - if (kmem_cache_destroy(coda_inode_cachep)) - printk(KERN_INFO "coda_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(coda_inode_cachep); } static int coda_remount(struct super_block *sb, int *flags, char *data) diff --git a/fs/efs/super.c b/fs/efs/super.c index 7089269ee9a..b3f50651eb6 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -90,8 +90,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(efs_inode_cachep)) - printk(KERN_INFO "efs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(efs_inode_cachep); } static void efs_put_super(struct super_block *s) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 69435fbe53f..513cd421ac0 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -184,8 +184,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(ext2_inode_cachep)) - printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(ext2_inode_cachep); } static void ext2_clear_inode(struct inode *inode) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 09b4b313ca0..8bfd56ef18c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -491,8 +491,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(ext3_inode_cachep)) - printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(ext3_inode_cachep); } static void ext3_clear_inode(struct inode *inode) diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 97b967b84fc..82cc4f59e3b 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -58,8 +58,7 @@ int __init fat_cache_init(void) void fat_cache_destroy(void) { - if (kmem_cache_destroy(fat_cache_cachep)) - printk(KERN_INFO "fat_cache: not all structures were freed\n"); + kmem_cache_destroy(fat_cache_cachep); } static inline struct fat_cache *fat_cache_alloc(struct inode *inode) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index bc4da3a48c8..d3015119043 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -528,8 +528,7 @@ static int __init fat_init_inodecache(void) static void __exit fat_destroy_inodecache(void) { - if (kmem_cache_destroy(fat_inode_cachep)) - printk(KERN_INFO "fat_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(fat_inode_cachep); } static int fat_remount(struct super_block *sb, int *flags, char *data) diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 05dffff1a37..d43b4fcc8ad 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -454,8 +454,7 @@ static int __init init_hfs_fs(void) static void __exit exit_hfs_fs(void) { unregister_filesystem(&hfs_fs_type); - if (kmem_cache_destroy(hfs_inode_cachep)) - printk(KERN_ERR "hfs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(hfs_inode_cachep); } module_init(init_hfs_fs) diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index d279d5924f2..194eede52fa 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -493,8 +493,7 @@ static int __init init_hfsplus_fs(void) static void __exit exit_hfsplus_fs(void) { unregister_filesystem(&hfsplus_fs_type); - if (kmem_cache_destroy(hfsplus_inode_cachep)) - printk(KERN_ERR "hfsplus_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(hfsplus_inode_cachep); } module_init(init_hfsplus_fs) diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index b76d6083237..450b5e0b478 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -203,8 +203,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(hpfs_inode_cachep)) - printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(hpfs_inode_cachep); } /* diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index ab15e907215..10e47897bac 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -96,9 +96,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(isofs_inode_cachep)) - printk(KERN_INFO "iso_inode_cache: not all structures were " - "freed\n"); + kmem_cache_destroy(isofs_inode_cachep); } static int isofs_remount(struct super_block *sb, int *flags, char *data) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index e24be7fc065..826b9d83065 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -90,8 +90,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(minix_inode_cachep)) - printk(KERN_INFO "minix_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(minix_inode_cachep); } static struct super_operations minix_sops = { diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 752f02e43ab..8244710e97d 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -81,8 +81,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(ncp_inode_cachep)) - printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(ncp_inode_cachep); } static int ncp_remount(struct super_block *sb, int *flags, char* data) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 76ca1cbc38f..377839bed17 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -855,6 +855,5 @@ int __init nfs_init_directcache(void) */ void nfs_destroy_directcache(void) { - if (kmem_cache_destroy(nfs_direct_cachep)) - printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n"); + kmem_cache_destroy(nfs_direct_cachep); } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a9d0f71eb5f..931f52a1957 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1134,8 +1134,7 @@ static int __init nfs_init_inodecache(void) static void nfs_destroy_inodecache(void) { - if (kmem_cache_destroy(nfs_inode_cachep)) - printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(nfs_inode_cachep); } /* diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 36e902a88ca..829af323f28 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -392,7 +392,6 @@ int __init nfs_init_nfspagecache(void) void nfs_destroy_nfspagecache(void) { - if (kmem_cache_destroy(nfs_page_cachep)) - printk(KERN_INFO "nfs_page: not all structures were freed\n"); + kmem_cache_destroy(nfs_page_cachep); } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 69f1549da2b..c2e49c397a2 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -737,6 +737,5 @@ int __init nfs_init_readpagecache(void) void nfs_destroy_readpagecache(void) { mempool_destroy(nfs_rdata_mempool); - if (kmem_cache_destroy(nfs_rdata_cachep)) - printk(KERN_INFO "nfs_read_data: not all structures were freed\n"); + kmem_cache_destroy(nfs_rdata_cachep); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index c12effb46fe..b674462793d 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1565,7 +1565,6 @@ void nfs_destroy_writepagecache(void) { mempool_destroy(nfs_commit_mempool); mempool_destroy(nfs_wdata_mempool); - if (kmem_cache_destroy(nfs_wdata_cachep)) - printk(KERN_INFO "nfs_write_data: not all structures were freed\n"); + kmem_cache_destroy(nfs_wdata_cachep); } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1a25c01ecdf..ebcf226a9e4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1005,13 +1005,10 @@ alloc_init_file(struct inode *ino) static void nfsd4_free_slab(kmem_cache_t **slab) { - int status; - if (*slab == NULL) return; - status = kmem_cache_destroy(*slab); + kmem_cache_destroy(*slab); *slab = NULL; - WARN_ON(status); } static void diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 74e0ee8fce7..6b2712f10dd 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3248,32 +3248,14 @@ ictx_err_out: static void __exit exit_ntfs_fs(void) { - int err = 0; - ntfs_debug("Unregistering NTFS driver."); unregister_filesystem(&ntfs_fs_type); - - if (kmem_cache_destroy(ntfs_big_inode_cache) && (err = 1)) - printk(KERN_CRIT "NTFS: Failed to destory %s.\n", - ntfs_big_inode_cache_name); - if (kmem_cache_destroy(ntfs_inode_cache) && (err = 1)) - printk(KERN_CRIT "NTFS: Failed to destory %s.\n", - ntfs_inode_cache_name); - if (kmem_cache_destroy(ntfs_name_cache) && (err = 1)) - printk(KERN_CRIT "NTFS: Failed to destory %s.\n", - ntfs_name_cache_name); - if (kmem_cache_destroy(ntfs_attr_ctx_cache) && (err = 1)) - printk(KERN_CRIT "NTFS: Failed to destory %s.\n", - ntfs_attr_ctx_cache_name); - if (kmem_cache_destroy(ntfs_index_ctx_cache) && (err = 1)) - printk(KERN_CRIT "NTFS: Failed to destory %s.\n", - ntfs_index_ctx_cache_name); - if (err) - printk(KERN_CRIT "NTFS: This causes memory to leak! There is " - "probably a BUG in the driver! Please report " - "you saw this message to " - "linux-ntfs-dev@lists.sourceforge.net\n"); + kmem_cache_destroy(ntfs_big_inode_cache); + kmem_cache_destroy(ntfs_inode_cache); + kmem_cache_destroy(ntfs_name_cache); + kmem_cache_destroy(ntfs_attr_ctx_cache); + kmem_cache_destroy(ntfs_index_ctx_cache); /* Unregister the ntfs sysctls. */ ntfs_sysctl(0); } diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 033ad170123..0ff0898a0b9 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -629,9 +629,7 @@ static void __exit exit_dlmfs_fs(void) flush_workqueue(user_dlm_worker); destroy_workqueue(user_dlm_worker); - if (kmem_cache_destroy(dlmfs_inode_cache)) - printk(KERN_INFO "dlmfs_inode_cache: not all structures " - "were freed\n"); + kmem_cache_destroy(dlmfs_inode_cache); } MODULE_AUTHOR("Oracle"); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 8497609f502..fddbd61c68d 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -556,9 +556,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(qnx4_inode_cachep)) - printk(KERN_INFO - "qnx4_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(qnx4_inode_cachep); } static int qnx4_get_sb(struct file_system_type *fs_type, diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5567328f104..1cd4d387f69 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -530,9 +530,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(reiserfs_inode_cachep)) - reiserfs_warning(NULL, - "reiserfs_inode_cache: not all structures were freed"); + kmem_cache_destroy(reiserfs_inode_cachep); } /* we don't mark inodes dirty, we just log them */ diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 22eed61ebf6..ddcd9e1ef28 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -589,8 +589,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(romfs_inode_cachep)) - printk(KERN_INFO "romfs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(romfs_inode_cachep); } static int romfs_remount(struct super_block *sb, int *flags, char *data) diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index a1ed657c3c8..92cf60aa612 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -89,8 +89,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(smb_inode_cachep)) - printk(KERN_INFO "smb_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(smb_inode_cachep); } static int smb_remount(struct super_block *sb, int *flags, char *data) diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index c8e96195b96..0fb74697abc 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -49,8 +49,7 @@ int smb_init_request_cache(void) void smb_destroy_request_cache(void) { - if (kmem_cache_destroy(req_cachep)) - printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n"); + kmem_cache_destroy(req_cachep); } /* diff --git a/fs/udf/super.c b/fs/udf/super.c index fcce1a21a51..5dd356cbbda 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -156,8 +156,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(udf_inode_cachep)) - printk(KERN_INFO "udf_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(udf_inode_cachep); } /* Superblock operations */ diff --git a/fs/ufs/super.c b/fs/ufs/super.c index ef910e78403..ec79e3091d1 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1244,8 +1244,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(ufs_inode_cachep)) - printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(ufs_inode_cachep); } #ifdef CONFIG_QUOTA diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index 939bd84bc7e..0e8293c5a32 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -91,8 +91,8 @@ kmem_zone_free(kmem_zone_t *zone, void *ptr) static inline void kmem_zone_destroy(kmem_zone_t *zone) { - if (zone && kmem_cache_destroy(zone)) - BUG(); + if (zone) + kmem_cache_destroy(zone); } extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 02e6f679897..f8381f0660b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1275,10 +1275,7 @@ out_filesystem: out_sysctl: if (mq_sysctl_table) unregister_sysctl_table(mq_sysctl_table); - if (kmem_cache_destroy(mqueue_inode_cachep)) { - printk(KERN_INFO - "mqueue_inode_cache: not all structures were freed\n"); - } + kmem_cache_destroy(mqueue_inode_cachep); return error; } diff --git a/mm/shmem.c b/mm/shmem.c index 8631be45b40..0a8e29cf87e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2157,8 +2157,7 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(shmem_inode_cachep)) - printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(shmem_inode_cachep); } static const struct address_space_operations shmem_aops = { diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index dfa504fe383..f65bea74734 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -858,7 +858,6 @@ int register_rpc_pipefs(void) void unregister_rpc_pipefs(void) { - if (kmem_cache_destroy(rpc_inode_cachep)) - printk(KERN_WARNING "RPC: unable to free inode cache\n"); + kmem_cache_destroy(rpc_inode_cachep); unregister_filesystem(&rpc_pipe_fs_type); } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 6390461a975..a1ab4eed41f 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -1059,10 +1059,10 @@ rpc_destroy_mempool(void) mempool_destroy(rpc_buffer_mempool); if (rpc_task_mempool) mempool_destroy(rpc_task_mempool); - if (rpc_task_slabp && kmem_cache_destroy(rpc_task_slabp)) - printk(KERN_INFO "rpc_task: not all structures were freed\n"); - if (rpc_buffer_slabp && kmem_cache_destroy(rpc_buffer_slabp)) - printk(KERN_INFO "rpc_buffers: not all structures were freed\n"); + if (rpc_task_slabp) + kmem_cache_destroy(rpc_task_slabp); + if (rpc_buffer_slabp) + kmem_cache_destroy(rpc_buffer_slabp); } int -- cgit v1.2.3-70-g09d2 From 8e18e2941c53416aa219708e7dcad21fb4bd6794 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:46 -0700 Subject: [PATCH] inode_diet: Replace inode.u.generic_ip with inode.i_private The following patches reduce the size of the VFS inode structure by 28 bytes on a UP x86. (It would be more on an x86_64 system). This is a 10% reduction in the inode size on a UP kernel that is configured in a production mode (i.e., with no spinlock or other debugging functions enabled; if you want to save memory taken up by in-core inodes, the first thing you should do is disable the debugging options; they are responsible for a huge amount of bloat in the VFS inode structure). This patch: The filesystem or device-specific pointer in the inode is inside a union, which is pretty pointless given that all 30+ users of this field have been using the void pointer. Get rid of the union and rename it to i_private, with a comment to explain who is allowed to use the void pointer. This is just a cleanup, but it allows us to reuse the union 'u' for something something where the union will actually be used. [judith@osdl.org: powerpc build fix] Signed-off-by: "Theodore Ts'o" Signed-off-by: Judith Lebzelter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/powerpc/platforms/pseries/hvCall_inst.c | 2 +- arch/s390/hypfs/inode.c | 6 ++--- arch/s390/kernel/debug.c | 2 +- block/blktrace.c | 2 +- drivers/i2c/chips/tps65010.c | 2 +- drivers/infiniband/hw/ipath/ipath_fs.c | 12 ++++----- drivers/infiniband/ulp/ipoib/ipoib_fs.c | 4 +-- drivers/misc/ibmasm/ibmasmfs.c | 16 ++++++------ drivers/net/irda/vlsi_ir.h | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 2 +- drivers/oprofile/oprofilefs.c | 10 ++++---- drivers/pci/hotplug/cpqphp_sysfs.c | 2 +- drivers/usb/core/devio.c | 2 +- drivers/usb/core/inode.c | 6 ++--- drivers/usb/gadget/inode.c | 6 ++--- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/uhci-debug.c | 2 +- drivers/usb/mon/mon_stat.c | 2 +- drivers/usb/mon/mon_text.c | 4 +-- fs/autofs/inode.c | 2 +- fs/autofs/symlink.c | 2 +- fs/binfmt_misc.c | 8 +++--- fs/debugfs/file.c | 4 +-- fs/debugfs/inode.c | 4 +-- fs/devpts/inode.c | 4 +-- fs/freevxfs/vxfs.h | 2 +- fs/freevxfs/vxfs_inode.c | 4 +-- fs/fuse/control.c | 6 ++--- fs/inode.c | 2 +- fs/jffs/inode-v23.c | 34 +++++++++++++------------- fs/libfs.c | 2 +- fs/ocfs2/dlmglue.c | 2 +- include/linux/fs.h | 4 +-- kernel/relay.c | 2 +- security/inode.c | 8 +++--- 36 files changed, 88 insertions(+), 90 deletions(-) (limited to 'drivers/usb/host') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7b4572805db..b837f12a84a 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -120,7 +120,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry, ret = 0; inode->i_op = &spufs_file_iops; inode->i_fop = fops; - inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); + inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); d_add(dentry, inode); out: return ret; diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 641e6511cf0..446e17d162a 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -85,7 +85,7 @@ static int hcall_inst_seq_open(struct inode *inode, struct file *file) rc = seq_open(file, &hcall_inst_seq_ops); seq = file->private_data; - seq->private = file->f_dentry->d_inode->u.generic_ip; + seq->private = file->f_dentry->d_inode->i_private; return rc; } diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index bdade5f2e32..8735024d235 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -104,13 +104,13 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode) static void hypfs_drop_inode(struct inode *inode) { - kfree(inode->u.generic_ip); + kfree(inode->i_private); generic_delete_inode(inode); } static int hypfs_open(struct inode *inode, struct file *filp) { - char *data = filp->f_dentry->d_inode->u.generic_ip; + char *data = filp->f_dentry->d_inode->i_private; struct hypfs_sb_info *fs_info; if (filp->f_mode & FMODE_WRITE) { @@ -352,7 +352,7 @@ static struct dentry *hypfs_create_file(struct super_block *sb, parent->d_inode->i_nlink++; } else BUG(); - inode->u.generic_ip = data; + inode->i_private = data; d_instantiate(dentry, inode); dget(dentry); return dentry; diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 7ba20922a53..43f3d0c7e13 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -603,7 +603,7 @@ debug_open(struct inode *inode, struct file *file) debug_info_t *debug_info, *debug_info_snapshot; down(&debug_lock); - debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip; + debug_info = file->f_dentry->d_inode->i_private; /* find debug view */ for (i = 0; i < DEBUG_MAX_VIEWS; i++) { if (!debug_info->views[i]) diff --git a/block/blktrace.c b/block/blktrace.c index 265f7a83061..2b4ef2b89b8 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -217,7 +217,7 @@ static int blk_trace_remove(request_queue_t *q) static int blk_dropped_open(struct inode *inode, struct file *filp) { - filp->private_data = inode->u.generic_ip; + filp->private_data = inode->i_private; return 0; } diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 0be6fd6a267..6a757821717 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -305,7 +305,7 @@ static int dbg_show(struct seq_file *s, void *_) static int dbg_tps_open(struct inode *inode, struct file *file) { - return single_open(file, dbg_show, inode->u.generic_ip); + return single_open(file, dbg_show, inode->i_private); } static struct file_operations debug_fops = { diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index a5eb30a06a5..055cdd089b2 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -64,7 +64,7 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry, inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->u.generic_ip = data; + inode->i_private = data; if ((mode & S_IFMT) == S_IFDIR) { inode->i_op = &simple_dir_inode_operations; inode->i_nlink++; @@ -119,7 +119,7 @@ static ssize_t atomic_counters_read(struct file *file, char __user *buf, u16 i; struct ipath_devdata *dd; - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; for (i = 0; i < NUM_COUNTERS; i++) counters[i] = ipath_snap_cntr(dd, i); @@ -139,7 +139,7 @@ static ssize_t atomic_node_info_read(struct file *file, char __user *buf, struct ipath_devdata *dd; u64 guid; - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; guid = be64_to_cpu(dd->ipath_guid); @@ -178,7 +178,7 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf, u32 tmp, tmp2; struct ipath_devdata *dd; - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; /* so we only initialize non-zero fields. */ memset(portinfo, 0, sizeof portinfo); @@ -325,7 +325,7 @@ static ssize_t flash_read(struct file *file, char __user *buf, goto bail; } - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; if (ipath_eeprom_read(dd, pos, tmp, count)) { ipath_dev_err(dd, "failed to read from flash\n"); ret = -ENXIO; @@ -381,7 +381,7 @@ static ssize_t flash_write(struct file *file, const char __user *buf, goto bail_tmp; } - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; if (ipath_eeprom_write(dd, pos, tmp, count)) { ret = -ENXIO; ipath_dev_err(dd, "failed to write to flash\n"); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 5dde380e8db..f1cb83688b3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -141,7 +141,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file) return ret; seq = file->private_data; - seq->private = inode->u.generic_ip; + seq->private = inode->i_private; return 0; } @@ -247,7 +247,7 @@ static int ipoib_path_open(struct inode *inode, struct file *file) return ret; seq = file->private_data; - seq->private = inode->u.generic_ip; + seq->private = inode->i_private; return 0; } diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 4a35caff5d0..0e909b61722 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -175,7 +175,7 @@ static struct dentry *ibmasmfs_create_file (struct super_block *sb, } inode->i_fop = fops; - inode->u.generic_ip = data; + inode->i_private = data; d_add(dentry, inode); return dentry; @@ -244,7 +244,7 @@ static int command_file_open(struct inode *inode, struct file *file) { struct ibmasmfs_command_data *command_data; - if (!inode->u.generic_ip) + if (!inode->i_private) return -ENODEV; command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL); @@ -252,7 +252,7 @@ static int command_file_open(struct inode *inode, struct file *file) return -ENOMEM; command_data->command = NULL; - command_data->sp = inode->u.generic_ip; + command_data->sp = inode->i_private; file->private_data = command_data; return 0; } @@ -351,10 +351,10 @@ static int event_file_open(struct inode *inode, struct file *file) struct ibmasmfs_event_data *event_data; struct service_processor *sp; - if (!inode->u.generic_ip) + if (!inode->i_private) return -ENODEV; - sp = inode->u.generic_ip; + sp = inode->i_private; event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL); if (!event_data) @@ -439,14 +439,14 @@ static int r_heartbeat_file_open(struct inode *inode, struct file *file) { struct ibmasmfs_heartbeat_data *rhbeat; - if (!inode->u.generic_ip) + if (!inode->i_private) return -ENODEV; rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL); if (!rhbeat) return -ENOMEM; - rhbeat->sp = (struct service_processor *)inode->u.generic_ip; + rhbeat->sp = inode->i_private; rhbeat->active = 0; ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat); file->private_data = rhbeat; @@ -508,7 +508,7 @@ static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, static int remote_settings_file_open(struct inode *inode, struct file *file) { - file->private_data = inode->u.generic_ip; + file->private_data = inode->i_private; return 0; } diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index a82a4ba8de4..c37f0bc4c7f 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -58,7 +58,7 @@ typedef void irqreturn_t; /* PDE() introduced in 2.5.4 */ #ifdef CONFIG_PROC_FS -#define PDE(inode) ((inode)->u.generic_ip) +#define PDE(inode) ((inode)->i_private) #endif /* irda crc16 calculation exported in 2.5.42 */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 923275ea078..b9df06a06ea 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -54,7 +54,7 @@ static ssize_t write_file_dummy(struct file *file, const char __user *buf, static int open_file_generic(struct inode *inode, struct file *file) { - file->private_data = inode->u.generic_ip; + file->private_data = inode->i_private; return 0; } diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 71c2da277d6..deb37354785 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -110,8 +110,8 @@ static ssize_t ulong_write_file(struct file * file, char const __user * buf, siz static int default_open(struct inode * inode, struct file * filp) { - if (inode->u.generic_ip) - filp->private_data = inode->u.generic_ip; + if (inode->i_private) + filp->private_data = inode->i_private; return 0; } @@ -158,7 +158,7 @@ int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, if (!d) return -EFAULT; - d->d_inode->u.generic_ip = val; + d->d_inode->i_private = val; return 0; } @@ -171,7 +171,7 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, if (!d) return -EFAULT; - d->d_inode->u.generic_ip = val; + d->d_inode->i_private = val; return 0; } @@ -197,7 +197,7 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, if (!d) return -EFAULT; - d->d_inode->u.generic_ip = val; + d->d_inode->i_private = val; return 0; } diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 8b3da007e85..5bab666cd67 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -140,7 +140,7 @@ struct ctrl_dbg { static int open(struct inode *inode, struct file *file) { - struct controller *ctrl = inode->u.generic_ip; + struct controller *ctrl = inode->i_private; struct ctrl_dbg *dbg; int retval = -ENOMEM; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 218621b9958..32e03000420 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -555,7 +555,7 @@ static int usbdev_open(struct inode *inode, struct file *file) if (imajor(inode) == USB_DEVICE_MAJOR) dev = usbdev_lookup_minor(iminor(inode)); if (!dev) - dev = inode->u.generic_ip; + dev = inode->i_private; if (!dev) { kfree(ps); goto out; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 3182c2224ba..482f253085e 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -402,8 +402,8 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) static int default_open (struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } @@ -509,7 +509,7 @@ static struct dentry *fs_create_file (const char *name, mode_t mode, } else { if (dentry->d_inode) { if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; if (fops) dentry->d_inode->i_fop = fops; dentry->d_inode->i_uid = uid; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3bdc5e3ba23..ffaa8c1afad 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -844,7 +844,7 @@ fail1: static int ep_open (struct inode *inode, struct file *fd) { - struct ep_data *data = inode->u.generic_ip; + struct ep_data *data = inode->i_private; int value = -EBUSY; if (down_interruptible (&data->lock) != 0) @@ -1909,7 +1909,7 @@ fail: static int dev_open (struct inode *inode, struct file *fd) { - struct dev_data *dev = inode->u.generic_ip; + struct dev_data *dev = inode->i_private; int value = -EBUSY; if (dev->state == STATE_DEV_DISABLED) { @@ -1970,7 +1970,7 @@ gadgetfs_make_inode (struct super_block *sb, inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->u.generic_ip = data; + inode->i_private = data; inode->i_fop = fops; } return inode; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5147ed4a666..8c6b38a0b5b 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1204,7 +1204,7 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused) static int isp116x_open_seq(struct inode *inode, struct file *file) { - return single_open(file, isp116x_show_dbg, inode->u.generic_ip); + return single_open(file, isp116x_show_dbg, inode->i_private); } static struct file_operations isp116x_debug_fops = { diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index dc286a48caf..d1372cb27f3 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -428,7 +428,7 @@ struct uhci_debug { static int uhci_debug_open(struct inode *inode, struct file *file) { - struct uhci_hcd *uhci = inode->u.generic_ip; + struct uhci_hcd *uhci = inode->i_private; struct uhci_debug *up; int ret = -ENOMEM; unsigned long flags; diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index 1fe01d994a7..86ad2b381c4 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -28,7 +28,7 @@ static int mon_stat_open(struct inode *inode, struct file *file) if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL) return -ENOMEM; - mbus = inode->u.generic_ip; + mbus = inode->i_private; sp->slen = snprintf(sp->str, STAT_BUF_SIZE, "nreaders %d events %u text_lost %u\n", diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index f961a770cee..2fd39b4fa16 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -238,7 +238,7 @@ static int mon_text_open(struct inode *inode, struct file *file) int rc; mutex_lock(&mon_lock); - mbus = inode->u.generic_ip; + mbus = inode->i_private; ubus = mbus->u_bus; rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL); @@ -401,7 +401,7 @@ static int mon_text_release(struct inode *inode, struct file *file) struct mon_event_text *ep; mutex_lock(&mon_lock); - mbus = inode->u.generic_ip; + mbus = inode->i_private; if (mbus->nreaders <= 0) { printk(KERN_ERR TAG ": consistency error on close\n"); diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index c81d6b8c282..d39d2acd9b3 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -241,7 +241,7 @@ static void autofs_read_inode(struct inode *inode) inode->i_op = &autofs_symlink_inode_operations; sl = &sbi->symlink[n]; - inode->u.generic_ip = sl; + inode->i_private = sl; inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = sl->mtime; inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c index 52e8772b066..c74f2eb6577 100644 --- a/fs/autofs/symlink.c +++ b/fs/autofs/symlink.c @@ -15,7 +15,7 @@ /* Nothing to release.. */ static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; + char *s=((struct autofs_symlink *)dentry->d_inode->i_private)->data; nd_set_link(nd, s); return NULL; } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 34ebbc191e4..6759b9839ce 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -517,7 +517,7 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode) static void bm_clear_inode(struct inode *inode) { - kfree(inode->u.generic_ip); + kfree(inode->i_private); } static void kill_node(Node *e) @@ -545,7 +545,7 @@ static void kill_node(Node *e) static ssize_t bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) { - Node *e = file->f_dentry->d_inode->u.generic_ip; + Node *e = file->f_dentry->d_inode->i_private; loff_t pos = *ppos; ssize_t res; char *page; @@ -579,7 +579,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct dentry *root; - Node *e = file->f_dentry->d_inode->u.generic_ip; + Node *e = file->f_dentry->d_inode->i_private; int res = parse_command(buffer, count); switch (res) { @@ -646,7 +646,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, } e->dentry = dget(dentry); - inode->u.generic_ip = e; + inode->i_private = e; inode->i_fop = &bm_entry_operations; d_instantiate(dentry, inode); diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index e4b430552c8..bf3901ab174 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -32,8 +32,8 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, static int default_open(struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 3ca268d2e5a..717f4821ed0 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -168,7 +168,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, * directory dentry if set. If this paramater is NULL, then the * file will be created in the root of the debugfs filesystem. * @data: a pointer to something that the caller will want to get to later - * on. The inode.u.generic_ip pointer will point to this value on + * on. The inode.i_private pointer will point to this value on * the open() call. * @fops: a pointer to a struct file_operations that should be used for * this file. @@ -209,7 +209,7 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, if (dentry->d_inode) { if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; if (fops) dentry->d_inode->i_fop = fops; } diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index f7aef5bb584..5bf06a10ddd 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -177,7 +177,7 @@ int devpts_pty_new(struct tty_struct *tty) inode->i_gid = config.setgid ? config.gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); - inode->u.generic_ip = tty; + inode->i_private = tty; dentry = get_node(number); if (!IS_ERR(dentry) && !dentry->d_inode) @@ -196,7 +196,7 @@ struct tty_struct *devpts_get_tty(int number) tty = NULL; if (!IS_ERR(dentry)) { if (dentry->d_inode) - tty = dentry->d_inode->u.generic_ip; + tty = dentry->d_inode->i_private; dput(dentry); } diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h index d35979a5874..c8a92652612 100644 --- a/fs/freevxfs/vxfs.h +++ b/fs/freevxfs/vxfs.h @@ -252,7 +252,7 @@ enum { * Get filesystem private data from VFS inode. */ #define VXFS_INO(ip) \ - ((struct vxfs_inode_info *)(ip)->u.generic_ip) + ((struct vxfs_inode_info *)(ip)->i_private) /* * Get filesystem private data from VFS superblock. diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index ca6a3971477..32a82ed108e 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -243,7 +243,7 @@ vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip) ip->i_blocks = vip->vii_blocks; ip->i_generation = vip->vii_gen; - ip->u.generic_ip = (void *)vip; + ip->i_private = vip; } @@ -338,5 +338,5 @@ vxfs_read_inode(struct inode *ip) void vxfs_clear_inode(struct inode *ip) { - kmem_cache_free(vxfs_inode_cachep, ip->u.generic_ip); + kmem_cache_free(vxfs_inode_cachep, ip->i_private); } diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 46fe60b2da2..79ec1f23d4d 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -23,7 +23,7 @@ static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file) { struct fuse_conn *fc; mutex_lock(&fuse_mutex); - fc = file->f_dentry->d_inode->u.generic_ip; + fc = file->f_dentry->d_inode->i_private; if (fc) fc = fuse_conn_get(fc); mutex_unlock(&fuse_mutex); @@ -98,7 +98,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, inode->i_op = iop; inode->i_fop = fop; inode->i_nlink = nlink; - inode->u.generic_ip = fc; + inode->i_private = fc; d_add(dentry, inode); return dentry; } @@ -150,7 +150,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) for (i = fc->ctl_ndents - 1; i >= 0; i--) { struct dentry *dentry = fc->ctl_dentry[i]; - dentry->d_inode->u.generic_ip = NULL; + dentry->d_inode->i_private = NULL; d_drop(dentry); dput(dentry); } diff --git a/fs/inode.c b/fs/inode.c index 0bf9f0444a9..77e25479202 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -163,7 +163,7 @@ static struct inode *alloc_inode(struct super_block *sb) bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; mapping->backing_dev_info = bdi; } - memset(&inode->u, 0, sizeof(inode->u)); + inode->i_private = 0; inode->i_mapping = mapping; } return inode; diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index b59553d28d1..7358ef87f16 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -369,7 +369,7 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, f = jffs_find_file(c, raw_inode->ino); - inode->u.generic_ip = (void *)f; + inode->i_private = (void *)f; insert_inode_hash(inode); return inode; @@ -442,7 +442,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, }); result = -ENOTDIR; - if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) { + if (!(old_dir_f = old_dir->i_private)) { D(printk("jffs_rename(): Old dir invalid.\n")); goto jffs_rename_end; } @@ -456,7 +456,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, /* Find the new directory. */ result = -ENOTDIR; - if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) { + if (!(new_dir_f = new_dir->i_private)) { D(printk("jffs_rename(): New dir invalid.\n")); goto jffs_rename_end; } @@ -593,7 +593,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) } else { ddino = ((struct jffs_file *) - inode->u.generic_ip)->pino; + inode->i_private)->pino; } D3(printk("jffs_readdir(): \"..\" %u\n", ddino)); if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) { @@ -604,7 +604,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) } filp->f_pos++; } - f = ((struct jffs_file *)inode->u.generic_ip)->children; + f = ((struct jffs_file *)inode->i_private)->children; j = 2; while(f && (f->deleted || j++ < filp->f_pos )) { @@ -668,7 +668,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) } r = -EACCES; - if (!(d = (struct jffs_file *)dir->u.generic_ip)) { + if (!(d = (struct jffs_file *)dir->i_private)) { D(printk("jffs_lookup(): No such inode! (%lu)\n", dir->i_ino)); goto jffs_lookup_end; @@ -739,7 +739,7 @@ jffs_do_readpage_nolock(struct file *file, struct page *page) unsigned long read_len; int result; struct inode *inode = (struct inode*)page->mapping->host; - struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip; + struct jffs_file *f = (struct jffs_file *)inode->i_private; struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info; int r; loff_t offset; @@ -828,7 +828,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) }); lock_kernel(); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; ASSERT(if (!dir_f) { printk(KERN_ERR "jffs_mkdir(): No reference to a " @@ -972,7 +972,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) kfree(_name); }); - dir_f = (struct jffs_file *) dir->u.generic_ip; + dir_f = dir->i_private; c = dir_f->c; result = -ENOENT; @@ -1082,7 +1082,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) if (!old_valid_dev(rdev)) return -EINVAL; lock_kernel(); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; c = dir_f->c; D3(printk (KERN_NOTICE "mknod(): down biglock\n")); @@ -1186,7 +1186,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) kfree(_symname); }); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; ASSERT(if (!dir_f) { printk(KERN_ERR "jffs_symlink(): No reference to a " "jffs_file struct in inode.\n"); @@ -1289,7 +1289,7 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode, kfree(s); }); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; ASSERT(if (!dir_f) { printk(KERN_ERR "jffs_create(): No reference to a " "jffs_file struct in inode.\n"); @@ -1403,9 +1403,9 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, goto out_isem; } - if (!(f = (struct jffs_file *)inode->u.generic_ip)) { - D(printk("jffs_file_write(): inode->u.generic_ip = 0x%p\n", - inode->u.generic_ip)); + if (!(f = inode->i_private)) { + D(printk("jffs_file_write(): inode->i_private = 0x%p\n", + inode->i_private)); goto out_isem; } @@ -1693,7 +1693,7 @@ jffs_read_inode(struct inode *inode) mutex_unlock(&c->fmc->biglock); return; } - inode->u.generic_ip = (void *)f; + inode->i_private = f; inode->i_mode = f->mode; inode->i_nlink = f->nlink; inode->i_uid = f->uid; @@ -1748,7 +1748,7 @@ jffs_delete_inode(struct inode *inode) lock_kernel(); inode->i_size = 0; inode->i_blocks = 0; - inode->u.generic_ip = NULL; + inode->i_private = NULL; clear_inode(inode); if (inode->i_nlink == 0) { c = (struct jffs_control *) inode->i_sb->s_fs_info; diff --git a/fs/libfs.c b/fs/libfs.c index ac02ea602c3..2751793beea 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -547,7 +547,7 @@ int simple_attr_open(struct inode *inode, struct file *file, attr->get = get; attr->set = set; - attr->data = inode->u.generic_ip; + attr->data = inode->i_private; attr->fmt = fmt; mutex_init(&attr->mutex); diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index de887063dcf..8801e41afe8 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -2052,7 +2052,7 @@ static int ocfs2_dlm_debug_open(struct inode *inode, struct file *file) mlog_errno(ret); goto out; } - osb = (struct ocfs2_super *) inode->u.generic_ip; + osb = inode->i_private; ocfs2_get_dlm_debug(osb->osb_dlm_debug); priv->p_dlm_debug = osb->osb_dlm_debug; INIT_LIST_HEAD(&priv->p_iter_res.l_debug_list); diff --git a/include/linux/fs.h b/include/linux/fs.h index 1d3e601ece7..4f77ec9c335 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -554,9 +554,7 @@ struct inode { atomic_t i_writecount; void *i_security; - union { - void *generic_ip; - } u; + void *i_private; /* fs or device private pointer */ #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; #endif diff --git a/kernel/relay.c b/kernel/relay.c index 33345e73485..85786ff2a4f 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -669,7 +669,7 @@ EXPORT_SYMBOL_GPL(relay_flush); */ static int relay_file_open(struct inode *inode, struct file *filp) { - struct rchan_buf *buf = inode->u.generic_ip; + struct rchan_buf *buf = inode->i_private; kref_get(&buf->kref); filp->private_data = buf; diff --git a/security/inode.c b/security/inode.c index 47eb63480da..176aacea8ca 100644 --- a/security/inode.c +++ b/security/inode.c @@ -44,8 +44,8 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, static int default_open(struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } @@ -194,7 +194,7 @@ static int create_by_name(const char *name, mode_t mode, * directory dentry if set. If this paramater is NULL, then the * file will be created in the root of the securityfs filesystem. * @data: a pointer to something that the caller will want to get to later - * on. The inode.u.generic_ip pointer will point to this value on + * on. The inode.i_private pointer will point to this value on * the open() call. * @fops: a pointer to a struct file_operations that should be used for * this file. @@ -240,7 +240,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode, if (fops) dentry->d_inode->i_fop = fops; if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; } exit: return dentry; -- cgit v1.2.3-70-g09d2 From d413984ae936fad46678403b38d79c595e5aaafe Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 4 Aug 2006 11:31:55 -0700 Subject: USB: OHCI avoids root hub timer polling This teaches OHCI to use the root hub status change (RHSC) IRQ, bypassing root hub timers most of the time and switching over to the "new" root hub polling scheme. It's complicated by the fact that implementations of OHCI trigger and ack that IRQ differently (the spec is vague there). Avoiding root hub timers helps mechanisms like "dynamic tick" leave the CPU in lowpower modes for longer intervals. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 2 +- drivers/usb/host/ohci-au1xxx.c | 5 +-- drivers/usb/host/ohci-dbg.c | 5 +++ drivers/usb/host/ohci-ep93xx.c | 1 + drivers/usb/host/ohci-hcd.c | 41 +++++++++++++++++++------ drivers/usb/host/ohci-hub.c | 67 ++++++++++++++++++++++++++++------------- drivers/usb/host/ohci-lh7a404.c | 5 +-- drivers/usb/host/ohci-omap.c | 5 ++- drivers/usb/host/ohci-pci.c | 5 ++- drivers/usb/host/ohci-ppc-soc.c | 1 + drivers/usb/host/ohci-pxa27x.c | 1 + drivers/usb/host/ohci-s3c2410.c | 1 + drivers/usb/host/ohci-sa1111.c | 5 +-- 13 files changed, 99 insertions(+), 45 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 85cc059705a..33b75087bc0 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -239,7 +239,7 @@ static const struct hc_driver ohci_at91_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index f7a975d5db0..44ed3a4c01e 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -268,10 +268,6 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { * basic lifecycle operations */ .start = ohci_au1xxx_start, -#ifdef CONFIG_PM - /* suspend: ohci_au1xxx_suspend, -- tbd */ - /* resume: ohci_au1xxx_resume, -- tbd */ -#endif /*CONFIG_PM*/ .stop = ohci_stop, /* @@ -291,6 +287,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 7bfffcbbd22..da52609a929 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -667,6 +667,11 @@ show_registers (struct class_device *class_dev, char *buf) size -= temp; next += temp; + temp = scnprintf (next, size, "hub poll timer %s\n", + ohci_to_hcd(ohci)->poll_rh ? "ON" : "off"); + size -= temp; + next += temp; + /* roothub */ ohci_dump_roothub (ohci, 1, &next, &size); diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 6531c4d2652..1a1d320b799 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -134,6 +134,7 @@ static struct hc_driver ohci_ep93xx_hc_driver = { .get_frame_number = ohci_get_frame, .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 94d8cf4b36c..0684f57c14a 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -101,7 +101,7 @@ #include "../core/hcd.h" -#define DRIVER_VERSION "2005 April 22" +#define DRIVER_VERSION "2006 August 04" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" @@ -110,9 +110,10 @@ #undef OHCI_VERBOSE_DEBUG /* not always helpful */ /* For initializing controller (mask in an HCFS mode too) */ -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR +#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR #define OHCI_INTR_INIT \ - (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH) + (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \ + | OHCI_INTR_RD | OHCI_INTR_WDH) #ifdef __hppa__ /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ @@ -128,6 +129,8 @@ static const char hcd_name [] = "ohci_hcd"; +#define STATECHANGE_DELAY msecs_to_jiffies(300) + #include "ohci.h" static void ohci_dump (struct ohci_hcd *ohci, int verbose); @@ -446,7 +449,6 @@ static int ohci_init (struct ohci_hcd *ohci) disable (ohci); ohci->regs = hcd->regs; - ohci->next_statechange = jiffies; /* REVISIT this BIOS handshake is now moved into PCI "quirks", and * was never needed for most non-PCI systems ... remove the code? @@ -637,10 +639,14 @@ retry: return -EOVERFLOW; } - /* start controller operations */ + /* use rhsc irqs after khubd is fully initialized */ + hcd->poll_rh = 1; + hcd->uses_new_polling = 1; + + /* start controller operations */ ohci->hc_control &= OHCI_CTRL_RWC; - ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); + ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); hcd->state = HC_STATE_RUNNING; /* wake on ConnectStatusChange, matching external hubs */ @@ -648,7 +654,7 @@ retry: /* Choose the interrupts we care about now, others later on demand */ mask = OHCI_INTR_INIT; - ohci_writel (ohci, mask, &ohci->regs->intrstatus); + ohci_writel (ohci, ~0, &ohci->regs->intrstatus); ohci_writel (ohci, mask, &ohci->regs->intrenable); /* handle root hub init quirks ... */ @@ -672,6 +678,7 @@ retry: // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); + ohci->next_statechange = jiffies + STATECHANGE_DELAY; spin_unlock_irq (&ohci->lock); // POTPGT delay is bits 24-31, in 2 ms units. @@ -709,7 +716,23 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) /* interrupt for some other device? */ } else if ((ints &= ohci_readl (ohci, ®s->intrenable)) == 0) { return IRQ_NOTMINE; - } + } + + /* NOTE: vendors didn't always make the same implementation + * choices for RHSC. Sometimes it triggers on an edge (like + * setting and maybe clearing a port status change bit); and + * it's level-triggered on other silicon, active until khubd + * clears all active port status change bits. Poll by timer + * til it's fully debounced and the difference won't matter. + */ + if (ints & OHCI_INTR_RHSC) { + ohci_vdbg (ohci, "rhsc\n"); + ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrdisable); + hcd->poll_rh = 1; + ohci->next_statechange = jiffies + STATECHANGE_DELAY; + ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); + usb_hcd_poll_rh_status(hcd); + } if (ints & OHCI_INTR_UE) { disable (ohci); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 5b0a23fd798..f1b1ed086bd 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -36,6 +36,14 @@ /*-------------------------------------------------------------------------*/ +/* hcd->hub_irq_enable() */ +static void ohci_rhsc_enable (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); +} + #ifdef CONFIG_PM #define OHCI_SCHED_ENABLES \ @@ -123,6 +131,9 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); + /* no timer polling */ + hcd->poll_rh = 0; + done: /* external suspend vs self autosuspend ... same effect */ if (status == 0) @@ -256,8 +267,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd) /* TRSMRCY */ msleep (10); - /* keep it alive for ~5x suspend + resume costs */ - ohci->next_statechange = jiffies + msecs_to_jiffies (250); + /* keep it alive for more than ~5x suspend + resume costs */ + ohci->next_statechange = jiffies + STATECHANGE_DELAY; /* maybe turn schedules back on */ enables = 0; @@ -302,9 +313,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; - int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); + int can_suspend; unsigned long flags; + can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); spin_lock_irqsave (&ohci->lock, flags); /* handle autosuspended root: finish resuming before @@ -339,6 +351,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); + /* can't autosuspend with active ports */ + if ((status & RH_PS_PES) && !(status & RH_PS_PSS)) + can_suspend = 0; + if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; @@ -348,32 +364,41 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) buf [1] |= 1 << (i - 7); continue; } + } - /* can suspend if no ports are enabled; or if all all - * enabled ports are suspended AND remote wakeup is on. - */ - if (!(status & RH_PS_CCS)) - continue; - if ((status & RH_PS_PSS) && can_suspend) - continue; + /* after root hub changes, stop polling after debouncing + * for a while and maybe kicking in autosuspend + */ + if (changed) { + ohci->next_statechange = jiffies + STATECHANGE_DELAY; can_suspend = 0; + } else if (time_before (jiffies, ohci->next_statechange)) { + can_suspend = 0; + } else { +#ifdef CONFIG_PM + can_suspend = can_suspend + && !ohci->ed_rm_list + && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) + & ohci->hc_control) + == OHCI_USB_OPER; +#endif + if (hcd->uses_new_polling) { + hcd->poll_rh = 0; + /* use INTR_RHSC iff INTR_RD won't apply */ + if (!can_suspend) + ohci_writel (ohci, OHCI_INTR_RHSC, + &ohci->regs->intrenable); + } } + done: spin_unlock_irqrestore (&ohci->lock, flags); -#ifdef CONFIG_PM - /* save power by suspending idle root hubs; +#ifdef CONFIG_PM + /* save power by autosuspending idle root hubs; * INTR_RD wakes us when there's work */ - if (can_suspend - && !changed - && !ohci->ed_rm_list - && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) - & ohci->hc_control) - == OHCI_USB_OPER - && time_after (jiffies, ohci->next_statechange) - && usb_trylock_device (hcd->self.root_hub) == 0 - ) { + if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 5602da9bd52..f2c9161d6d6 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -173,10 +173,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { * basic lifecycle operations */ .start = ohci_lh7a404_start, -#ifdef CONFIG_PM - /* suspend: ohci_lh7a404_suspend, -- tbd */ - /* resume: ohci_lh7a404_resume, -- tbd */ -#endif /*CONFIG_PM*/ .stop = ohci_stop, /* @@ -196,6 +192,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index c4c4babd476..47f1c9bbef8 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -382,8 +382,10 @@ ohci_omap_start (struct usb_hcd *hcd) int ret; config = hcd->self.controller->platform_data; - if (config->otg || config->rwc) + if (config->otg || config->rwc) { + ohci->hc_control = OHCI_CTRL_RWC; writel(OHCI_CTRL_RWC, &ohci->regs->control); + } if ((ret = ohci_run (ohci)) < 0) { dev_err(hcd->self.controller, "can't start\n"); @@ -429,6 +431,7 @@ static const struct hc_driver ohci_omap_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 37e122812b6..ef874443aa9 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -176,11 +176,13 @@ static const struct hc_driver ohci_pci_hc_driver = { */ .reset = ohci_pci_reset, .start = ohci_pci_start, + .stop = ohci_stop, + #ifdef CONFIG_PM + /* these suspend/resume entries are for upstream PCI glue ONLY */ .suspend = ohci_pci_suspend, .resume = ohci_pci_resume, #endif - .stop = ohci_stop, /* * managing i/o requests and associated device resources @@ -199,6 +201,7 @@ static const struct hc_driver ohci_pci_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 9fe56ff1615..270aaaad8c6 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -166,6 +166,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 6f559e10278..2752d36c2a7 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -288,6 +288,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index d2fc6969a9f..c4c77d26ca1 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -465,6 +465,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .hub_status_data = ohci_s3c2410_hub_status_data, .hub_control = ohci_s3c2410_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index ce3de106cad..71371de32ad 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -212,10 +212,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = { * basic lifecycle operations */ .start = ohci_sa1111_start, -#ifdef CONFIG_PM - /* suspend: ohci_sa1111_suspend, -- tbd */ - /* resume: ohci_sa1111_resume, -- tbd */ -#endif .stop = ohci_stop, /* @@ -235,6 +231,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, -- cgit v1.2.3-70-g09d2 From b2a8e097d0f3bbb7ef550103022db92fc3832842 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 26 Jun 2006 23:36:07 +0100 Subject: USB: ohci-s3c2410.c: clock now usb-bus-host With the newer Samsung S3C2412 and S3C2413 SoC devices, the 48MHz USB clock has been given an individual gate into the USB OHCI and gadget blocks. This clock is called usb-bus-clock, and we need to replace the old use of the USB PLL (upll) directly with the new usb-bus-host. The S3C2410 clock driver has been updated already to provide a virtual clock which is a child of the UPLL to maintain compatibility. The S3C2412 clock driver correctly enables the PLL when either usb-bus clock is active. Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-s3c2410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index c4c77d26ca1..cd37eddf7d4 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -370,7 +370,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver, goto err_mem; } - usb_clk = clk_get(&dev->dev, "upll"); + usb_clk = clk_get(&dev->dev, "usb-bus-host"); if (IS_ERR(usb_clk)) { dev_err(&dev->dev, "cannot get usb-host clock\n"); retval = -ENOENT; -- cgit v1.2.3-70-g09d2 From 60bbfc84b6d916f5a10127762d0dcb3f4726450d Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Thu, 29 Jun 2006 18:28:18 +0400 Subject: USB OHCI controller support for PNX4008 inlined is the patch that adds basic support for USB OHCI controller support for PNX4008 Philips PNX4008 ARM board. Due to HW design, it depends on I2C driver for PNX4008 which I've recetnly posted to LKML and i2c at lm-sensors. Signed-off-by: Vitaly Wool Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 1 + drivers/usb/host/Kconfig | 2 + drivers/usb/host/ohci-hcd.c | 5 + drivers/usb/host/ohci-pnx4008.c | 476 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 484 insertions(+) create mode 100644 drivers/usb/host/ohci-pnx4008.c (limited to 'drivers/usb/host') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 00504319752..f9b1719b9a3 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -25,6 +25,7 @@ config USB_ARCH_HAS_OHCI default y if PXA27x default y if ARCH_EP93XX default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261) + default y if ARCH_PNX4008 # PPC: default y if STB03xxx default y if PPC_MPC52xx diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b93d71d28db..77ba2b0bf0b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -83,6 +83,8 @@ config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB && USB_ARCH_HAS_OHCI select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 + select I2C if ARCH_PNX4008 + select I2C_PNX if ARCH_PNX4008 ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0684f57c14a..cbf38ae5ae7 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -940,6 +940,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-at91.c" #endif +#ifdef CONFIG_ARCH_PNX4008 +#include "ohci-pnx4008.c" +#endif + #if !(defined(CONFIG_PCI) \ || defined(CONFIG_SA1111) \ || defined(CONFIG_ARCH_S3C2410) \ @@ -951,6 +955,7 @@ MODULE_LICENSE ("GPL"); || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ || defined (CONFIG_ARCH_AT91RM9200) \ || defined (CONFIG_ARCH_AT91SAM9261) \ + || defined (CONFIG_ARCH_PNX4008) \ ) #error "missing bus glue for ohci-hcd" #endif diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c new file mode 100644 index 00000000000..82cb22f002e --- /dev/null +++ b/drivers/usb/host/ohci-pnx4008.c @@ -0,0 +1,476 @@ +/* + * drivers/usb/host/ohci-pnx4008.c + * + * driver for Philips PNX4008 USB Host + * + * Authors: Dmitry Chigirev + * Vitaly Wool + * + * register initialization is based on code examples provided by Philips + * Copyright (c) 2005 Koninklijke Philips Electronics N.V. + * + * NOTE: This driver does not have suspend/resume functionality + * This driver is intended for engineering development purposes only + * + * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64) + +/* USB_CTRL bit defines */ +#define USB_SLAVE_HCLK_EN (1 << 24) +#define USB_HOST_NEED_CLK_EN (1 << 21) + +#define USB_OTG_CLK_CTRL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4) +#define USB_OTG_CLK_STAT IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8) + +/* USB_OTG_CLK_CTRL bit defines */ +#define AHB_M_CLOCK_ON (1 << 4) +#define OTG_CLOCK_ON (1 << 3) +#define I2C_CLOCK_ON (1 << 2) +#define DEV_CLOCK_ON (1 << 1) +#define HOST_CLOCK_ON (1 << 0) + +#define USB_OTG_STAT_CONTROL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110) + +/* USB_OTG_STAT_CONTROL bit defines */ +#define TRANSPARENT_I2C_EN (1 << 7) +#define HOST_EN (1 << 0) + +/* ISP1301 USB transceiver I2C registers */ +#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ + +#define MC1_SPEED_REG (1 << 0) +#define MC1_SUSPEND_REG (1 << 1) +#define MC1_DAT_SE0 (1 << 2) +#define MC1_TRANSPARENT (1 << 3) +#define MC1_BDIS_ACON_EN (1 << 4) +#define MC1_OE_INT_EN (1 << 5) +#define MC1_UART_EN (1 << 6) +#define MC1_MASK 0x7f + +#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ + +#define MC2_GLOBAL_PWR_DN (1 << 0) +#define MC2_SPD_SUSP_CTRL (1 << 1) +#define MC2_BI_DI (1 << 2) +#define MC2_TRANSP_BDIR0 (1 << 3) +#define MC2_TRANSP_BDIR1 (1 << 4) +#define MC2_AUDIO_EN (1 << 5) +#define MC2_PSW_EN (1 << 6) +#define MC2_EN2V7 (1 << 7) + +#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ +# define OTG1_DP_PULLUP (1 << 0) +# define OTG1_DM_PULLUP (1 << 1) +# define OTG1_DP_PULLDOWN (1 << 2) +# define OTG1_DM_PULLDOWN (1 << 3) +# define OTG1_ID_PULLDOWN (1 << 4) +# define OTG1_VBUS_DRV (1 << 5) +# define OTG1_VBUS_DISCHRG (1 << 6) +# define OTG1_VBUS_CHRG (1 << 7) +#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ +# define OTG_B_SESS_END (1 << 6) +# define OTG_B_SESS_VLD (1 << 7) + +#define ISP1301_I2C_ADDR 0x2C + +#define ISP1301_I2C_MODE_CONTROL_1 0x4 +#define ISP1301_I2C_MODE_CONTROL_2 0x12 +#define ISP1301_I2C_OTG_CONTROL_1 0x6 +#define ISP1301_I2C_OTG_CONTROL_2 0x10 +#define ISP1301_I2C_INTERRUPT_SOURCE 0x8 +#define ISP1301_I2C_INTERRUPT_LATCH 0xA +#define ISP1301_I2C_INTERRUPT_FALLING 0xC +#define ISP1301_I2C_INTERRUPT_RISING 0xE +#define ISP1301_I2C_REG_CLEAR_ADDR 1 + +struct i2c_driver isp1301_driver; +struct i2c_client *isp1301_i2c_client; + +extern int usb_disabled(void); +extern int ocpi_enable(void); + +static struct clk *usb_clk; + +static int isp1301_probe(struct i2c_adapter *adap); +static int isp1301_detach(struct i2c_client *client); +static int isp1301_command(struct i2c_client *client, unsigned int cmd, + void *arg); + +static unsigned short normal_i2c[] = + { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END }; +static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_i2c, + .probe = dummy_i2c_addrlist, + .ignore = dummy_i2c_addrlist, +}; + +struct i2c_driver isp1301_driver = { + .id = I2C_DRIVERID_I2CDEV, /* Fake Id */ + .class = I2C_CLASS_HWMON, + .attach_adapter = isp1301_probe, + .detach_client = isp1301_detach, + .command = isp1301_command +}; + +static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct i2c_client *c; + + c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL); + + if (!c) + return -ENOMEM; + + strcpy(c->name, "isp1301"); + c->flags = 0; + c->addr = addr; + c->adapter = adap; + c->driver = &isp1301_driver; + + isp1301_i2c_client = c; + + return i2c_attach_client(c); +} + +static int isp1301_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, isp1301_attach); +} + +static int isp1301_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(isp1301_i2c_client); + return 0; +} + +/* No commands defined */ +static int isp1301_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + return 0; +} + +static void i2c_write(u8 buf, u8 subaddr) +{ + char tmpbuf[2]; + + tmpbuf[0] = subaddr; /*register number */ + tmpbuf[1] = buf; /*register data */ + i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2); +} + +static void isp1301_configure(void) +{ + /* PNX4008 only supports DAT_SE0 USB mode */ + /* PNX4008 R2A requires setting the MAX603 to output 3.6V */ + /* Power up externel charge-pump */ + + i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1); + i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG), + ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL, + ISP1301_I2C_MODE_CONTROL_2); + i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL), + ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN, + ISP1301_I2C_OTG_CONTROL_1); + i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN), + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(0xFF, + ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(0xFF, + ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(0xFF, + ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR); + +} + +static inline void isp1301_vbus_on(void) +{ + i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1); +} + +static inline void isp1301_vbus_off(void) +{ + i2c_write(OTG1_VBUS_DRV, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR); +} + +static void pnx4008_start_hc(void) +{ + unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN; + __raw_writel(tmp, USB_OTG_STAT_CONTROL); + isp1301_vbus_on(); +} + +static void pnx4008_stop_hc(void) +{ + unsigned long tmp; + isp1301_vbus_off(); + tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN; + __raw_writel(tmp, USB_OTG_STAT_CONTROL); +} + +static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + dev_err(hcd->self.controller, "can't start\n"); + ohci_stop(hcd); + return ret; + } + return 0; +} + +static const struct hc_driver ohci_pnx4008_hc_driver = { + .description = hcd_name, + .product_desc = "pnx4008 OHCI", + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + .hcd_priv_size = sizeof(struct ohci_hcd), + /* + * basic lifecycle operations + */ + .start = ohci_pnx4008_start, + .stop = ohci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + + .start_port_reset = ohci_start_port_reset, +}; + +#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON) + +static void pnx4008_set_usb_bits(void) +{ + start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N); + start_int_ack(SE_USB_OTG_ATX_INT_N); + start_int_umask(SE_USB_OTG_ATX_INT_N); + + start_int_set_rising_edge(SE_USB_OTG_TIMER_INT); + start_int_ack(SE_USB_OTG_TIMER_INT); + start_int_umask(SE_USB_OTG_TIMER_INT); + + start_int_set_rising_edge(SE_USB_I2C_INT); + start_int_ack(SE_USB_I2C_INT); + start_int_umask(SE_USB_I2C_INT); + + start_int_set_rising_edge(SE_USB_INT); + start_int_ack(SE_USB_INT); + start_int_umask(SE_USB_INT); + + start_int_set_rising_edge(SE_USB_NEED_CLK_INT); + start_int_ack(SE_USB_NEED_CLK_INT); + start_int_umask(SE_USB_NEED_CLK_INT); + + start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT); + start_int_ack(SE_USB_AHB_NEED_CLK_INT); + start_int_umask(SE_USB_AHB_NEED_CLK_INT); +} + +static void pnx4008_unset_usb_bits(void) +{ + start_int_mask(SE_USB_OTG_ATX_INT_N); + start_int_mask(SE_USB_OTG_TIMER_INT); + start_int_mask(SE_USB_I2C_INT); + start_int_mask(SE_USB_INT); + start_int_mask(SE_USB_NEED_CLK_INT); + start_int_mask(SE_USB_AHB_NEED_CLK_INT); +} + +static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; + const struct hc_driver *driver = &ohci_pnx4008_hc_driver; + + int ret = 0, irq; + + dev_dbg(&pdev->dev, "%s: " DRIVER_INFO " (pnx4008)\n", hcd_name); + if (usb_disabled()) { + err("USB is disabled"); + ret = -ENODEV; + goto out; + } + + if (pdev->num_resources != 2 + || pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_IRQ) { + err("Invalid resource configuration"); + ret = -ENODEV; + goto out; + } + + /* Enable AHB slave USB clock, needed for further USB clock control */ + __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL); + + ret = i2c_add_driver(&isp1301_driver); + if (ret < 0) { + err("failed to connect I2C to ISP1301 USB Transceiver"); + goto out; + } + + isp1301_configure(); + + /* Enable USB PLL */ + usb_clk = clk_get(&pdev->dev, "ck_pll5"); + if (IS_ERR(usb_clk)) { + err("failed to acquire USB PLL"); + ret = PTR_ERR(usb_clk); + goto out1; + } + + ret = clk_enable(usb_clk); + if (ret < 0) { + err("failed to start USB PLL"); + goto out2; + } + + ret = clk_set_rate(usb_clk, 48000); + if (ret < 0) { + err("failed to set USB clock rate"); + goto out3; + } + + __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL); + + /* Set to enable all needed USB clocks */ + __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL); + + while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) != + USB_CLOCK_MASK) ; + + hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + err("Failed to allocate HC buffer"); + ret = -ENOMEM; + goto out3; + } + + /* Set all USB bits in the Start Enable register */ + pnx4008_set_usb_bits(); + + hcd->rsrc_start = pdev->resource[0].start; + hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + ret = -ENOMEM; + goto out4; + } + hcd->regs = (void __iomem *)pdev->resource[0].start; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENXIO; + goto out4; + } + + hcd->self.hcpriv = (void *)hcd; + + pnx4008_start_hc(); + platform_set_drvdata(pdev, hcd); + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); + + dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); + ret = usb_add_hcd(hcd, irq, SA_INTERRUPT); + if (ret == 0) + return ret; + + pnx4008_stop_hc(); +out4: + pnx4008_unset_usb_bits(); + usb_put_hcd(hcd); +out3: + clk_disable(usb_clk); +out2: + clk_put(usb_clk); +out1: + i2c_del_driver(&isp1301_driver); +out: + return ret; +} + +static int usb_hcd_pnx4008_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + pnx4008_stop_hc(); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + pnx4008_unset_usb_bits(); + clk_disable(usb_clk); + clk_put(usb_clk); + i2c_del_driver(&isp1301_driver); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver usb_hcd_pnx4008_driver = { + .driver = { + .name = "usb-ohci", + }, + .probe = usb_hcd_pnx4008_probe, + .remove = usb_hcd_pnx4008_remove, +}; + +static int __init usb_hcd_pnx4008_init(void) +{ + return platform_driver_register(&usb_hcd_pnx4008_driver); +} + +static void __exit usb_hcd_pnx4008_cleanup(void) +{ + return platform_driver_unregister(&usb_hcd_pnx4008_driver); +} + +module_init(usb_hcd_pnx4008_init); +module_exit(usb_hcd_pnx4008_cleanup); -- cgit v1.2.3-70-g09d2 From 26facdff1d39c0028565137ad27e8bd5a5cafcf1 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 7 Jul 2006 00:11:45 -0700 Subject: USB: kill usb kconfig warning drivers/usb/host/Kconfig:87:warning: 'select' used by config symbol 'USB_OHCI_HCD' refer to undefined symbol 'I2C_PNX' Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 77ba2b0bf0b..4bd5cddae8a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -84,7 +84,6 @@ config USB_OHCI_HCD depends on USB && USB_ARCH_HAS_OHCI select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 select I2C if ARCH_PNX4008 - select I2C_PNX if ARCH_PNX4008 ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's -- cgit v1.2.3-70-g09d2 From 3a16f7b4a75d68364c3278523f51ac141a12758a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 29 Jun 2006 12:27:23 -0700 Subject: USB: move to Move to . Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/usb.c | 2 +- drivers/i2c/chips/isp1301_omap.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/host/ohci-hcd.c | 2 +- include/linux/usb/otg.h | 131 +++++++++++++++++++++++++++++++++++++++ include/linux/usb_otg.h | 131 --------------------------------------- 6 files changed, 135 insertions(+), 135 deletions(-) create mode 100644 include/linux/usb/otg.h delete mode 100644 include/linux/usb_otg.h (limited to 'drivers/usb/host') diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c index 9b815327b6a..7e8096809be 100644 --- a/arch/arm/plat-omap/usb.c +++ b/arch/arm/plat-omap/usb.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index f92505b94c6..182f0495346 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 2de9748ee67..81f0389fcc9 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index cbf38ae5ae7..7c3d8c60a60 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -88,7 +88,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h new file mode 100644 index 00000000000..9897f7a818c --- /dev/null +++ b/include/linux/usb/otg.h @@ -0,0 +1,131 @@ +// include/linux/usb/otg.h + +/* + * These APIs may be used between USB controllers. USB device drivers + * (for either host or peripheral roles) don't use these calls; they + * continue to use just usb_device and usb_gadget. + */ + + +/* OTG defines lots of enumeration states before device reset */ +enum usb_otg_state { + OTG_STATE_UNDEFINED = 0, + + /* single-role peripheral, and dual-role default-b */ + OTG_STATE_B_IDLE, + OTG_STATE_B_SRP_INIT, + OTG_STATE_B_PERIPHERAL, + + /* extra dual-role default-b states */ + OTG_STATE_B_WAIT_ACON, + OTG_STATE_B_HOST, + + /* dual-role default-a */ + OTG_STATE_A_IDLE, + OTG_STATE_A_WAIT_VRISE, + OTG_STATE_A_WAIT_BCON, + OTG_STATE_A_HOST, + OTG_STATE_A_SUSPEND, + OTG_STATE_A_PERIPHERAL, + OTG_STATE_A_WAIT_VFALL, + OTG_STATE_A_VBUS_ERR, +}; + +/* + * the otg driver needs to interact with both device side and host side + * usb controllers. it decides which controller is active at a given + * moment, using the transceiver, ID signal, HNP and sometimes static + * configuration information (including "board isn't wired for otg"). + */ +struct otg_transceiver { + struct device *dev; + const char *label; + + u8 default_a; + enum usb_otg_state state; + + struct usb_bus *host; + struct usb_gadget *gadget; + + /* to pass extra port status to the root hub */ + u16 port_status; + u16 port_change; + + /* bind/unbind the host controller */ + int (*set_host)(struct otg_transceiver *otg, + struct usb_bus *host); + + /* bind/unbind the peripheral controller */ + int (*set_peripheral)(struct otg_transceiver *otg, + struct usb_gadget *gadget); + + /* effective for B devices, ignored for A-peripheral */ + int (*set_power)(struct otg_transceiver *otg, + unsigned mA); + + /* for non-OTG B devices: set transceiver into suspend mode */ + int (*set_suspend)(struct otg_transceiver *otg, + int suspend); + + /* for B devices only: start session with A-Host */ + int (*start_srp)(struct otg_transceiver *otg); + + /* start or continue HNP role switch */ + int (*start_hnp)(struct otg_transceiver *otg); + +}; + + +/* for board-specific init logic */ +extern int otg_set_transceiver(struct otg_transceiver *); + + +/* for usb host and peripheral controller drivers */ +extern struct otg_transceiver *otg_get_transceiver(void); + +static inline int +otg_start_hnp(struct otg_transceiver *otg) +{ + return otg->start_hnp(otg); +} + + +/* for HCDs */ +static inline int +otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + return otg->set_host(otg, host); +} + + +/* for usb peripheral controller drivers */ +static inline int +otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) +{ + return otg->set_peripheral(otg, periph); +} + +static inline int +otg_set_power(struct otg_transceiver *otg, unsigned mA) +{ + return otg->set_power(otg, mA); +} + +static inline int +otg_set_suspend(struct otg_transceiver *otg, int suspend) +{ + if (otg->set_suspend != NULL) + return otg->set_suspend(otg, suspend); + else + return 0; +} + +static inline int +otg_start_srp(struct otg_transceiver *otg) +{ + return otg->start_srp(otg); +} + + +/* for OTG controller drivers (and maybe other stuff) */ +extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num); diff --git a/include/linux/usb_otg.h b/include/linux/usb_otg.h deleted file mode 100644 index f827f6e203c..00000000000 --- a/include/linux/usb_otg.h +++ /dev/null @@ -1,131 +0,0 @@ -// include/linux/usb_otg.h - -/* - * These APIs may be used between USB controllers. USB device drivers - * (for either host or peripheral roles) don't use these calls; they - * continue to use just usb_device and usb_gadget. - */ - - -/* OTG defines lots of enumeration states before device reset */ -enum usb_otg_state { - OTG_STATE_UNDEFINED = 0, - - /* single-role peripheral, and dual-role default-b */ - OTG_STATE_B_IDLE, - OTG_STATE_B_SRP_INIT, - OTG_STATE_B_PERIPHERAL, - - /* extra dual-role default-b states */ - OTG_STATE_B_WAIT_ACON, - OTG_STATE_B_HOST, - - /* dual-role default-a */ - OTG_STATE_A_IDLE, - OTG_STATE_A_WAIT_VRISE, - OTG_STATE_A_WAIT_BCON, - OTG_STATE_A_HOST, - OTG_STATE_A_SUSPEND, - OTG_STATE_A_PERIPHERAL, - OTG_STATE_A_WAIT_VFALL, - OTG_STATE_A_VBUS_ERR, -}; - -/* - * the otg driver needs to interact with both device side and host side - * usb controllers. it decides which controller is active at a given - * moment, using the transceiver, ID signal, HNP and sometimes static - * configuration information (including "board isn't wired for otg"). - */ -struct otg_transceiver { - struct device *dev; - const char *label; - - u8 default_a; - enum usb_otg_state state; - - struct usb_bus *host; - struct usb_gadget *gadget; - - /* to pass extra port status to the root hub */ - u16 port_status; - u16 port_change; - - /* bind/unbind the host controller */ - int (*set_host)(struct otg_transceiver *otg, - struct usb_bus *host); - - /* bind/unbind the peripheral controller */ - int (*set_peripheral)(struct otg_transceiver *otg, - struct usb_gadget *gadget); - - /* effective for B devices, ignored for A-peripheral */ - int (*set_power)(struct otg_transceiver *otg, - unsigned mA); - - /* for non-OTG B devices: set transceiver into suspend mode */ - int (*set_suspend)(struct otg_transceiver *otg, - int suspend); - - /* for B devices only: start session with A-Host */ - int (*start_srp)(struct otg_transceiver *otg); - - /* start or continue HNP role switch */ - int (*start_hnp)(struct otg_transceiver *otg); - -}; - - -/* for board-specific init logic */ -extern int otg_set_transceiver(struct otg_transceiver *); - - -/* for usb host and peripheral controller drivers */ -extern struct otg_transceiver *otg_get_transceiver(void); - -static inline int -otg_start_hnp(struct otg_transceiver *otg) -{ - return otg->start_hnp(otg); -} - - -/* for HCDs */ -static inline int -otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) -{ - return otg->set_host(otg, host); -} - - -/* for usb peripheral controller drivers */ -static inline int -otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) -{ - return otg->set_peripheral(otg, periph); -} - -static inline int -otg_set_power(struct otg_transceiver *otg, unsigned mA) -{ - return otg->set_power(otg, mA); -} - -static inline int -otg_set_suspend(struct otg_transceiver *otg, int suspend) -{ - if (otg->set_suspend != NULL) - return otg->set_suspend(otg, suspend); - else - return 0; -} - -static inline int -otg_start_srp(struct otg_transceiver *otg) -{ - return otg->start_srp(otg); -} - - -/* for OTG controller drivers (and maybe other stuff) */ -extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num); -- cgit v1.2.3-70-g09d2 From bd35078f47f795569fae29b2ff187e6f921460ad Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 31 Jul 2006 07:29:39 -0700 Subject: USB: build fixes: ohci-omap The ohci-omap code has diverged from the working version in the linux-omap tree; this syncs up the versions: - Another clock is needed in various cases - The omap-1510 iommu code needs to be #ifdeffed out on newer parts - Saner use of the HCD framework - Various other changes, e.g. a Nokia 770 quirk And some minor dead-whitespace removal. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 113 +++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 42 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 47f1c9bbef8..160cd4c58a0 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -4,7 +4,7 @@ * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2005 David Brownell * (C) Copyright 2002 Hewlett-Packard Company - * + * * OMAP Bus Glue * * Modified for OMAP by Tony Lindgren @@ -66,15 +66,20 @@ extern int usb_disabled(void); extern int ocpi_enable(void); static struct clk *usb_host_ck; +static struct clk *usb_dc_ck; +static int host_enabled; +static int host_initialized; static void omap_ohci_clock_power(int on) { if (on) { + clk_enable(usb_dc_ck); clk_enable(usb_host_ck); /* guesstimate for T5 == 1x 32K clock + APLL lock time */ udelay(100); } else { clk_disable(usb_host_ck); + clk_disable(usb_dc_ck); } } @@ -87,14 +92,14 @@ static int omap_ohci_transceiver_power(int on) if (on) { if (machine_is_omap_innovator() && cpu_is_omap1510()) fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) - | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), + | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); else if (machine_is_omap_osk()) tps65010_set_gpio_out_value(GPIO1, LOW); } else { if (machine_is_omap_innovator() && cpu_is_omap1510()) fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) - & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), + & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); else if (machine_is_omap_osk()) tps65010_set_gpio_out_value(GPIO1, HIGH); @@ -103,6 +108,7 @@ static int omap_ohci_transceiver_power(int on) return 0; } +#ifdef CONFIG_ARCH_OMAP15XX /* * OMAP-1510 specific Local Bus clock on/off */ @@ -121,8 +127,8 @@ static int omap_1510_local_bus_power(int on) /* * OMAP-1510 specific Local Bus initialization * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. - * See also arch/mach-omap/memory.h for __virt_to_dma() and - * __dma_to_virt() which need to match with the physical + * See also arch/mach-omap/memory.h for __virt_to_dma() and + * __dma_to_virt() which need to match with the physical * Local Bus address below. */ static int omap_1510_local_bus_init(void) @@ -130,7 +136,7 @@ static int omap_1510_local_bus_init(void) unsigned int tlb; unsigned long lbaddr, physaddr; - omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, + omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, OMAP1510_LB_CLOCK_DIV); /* Configure the Local Bus MMU table */ @@ -138,7 +144,7 @@ static int omap_1510_local_bus_init(void) lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; physaddr = tlb * 0x00100000 + PHYS_OFFSET; omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); - omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, + omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, OMAP1510_LB_MMU_CAM_L); omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); @@ -152,6 +158,10 @@ static int omap_1510_local_bus_init(void) return 0; } +#else +#define omap_1510_local_bus_power(x) {} +#define omap_1510_local_bus_init() {} +#endif #ifdef CONFIG_USB_OTG @@ -173,13 +183,14 @@ static void start_hnp(struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) +static int ohci_omap_init(struct usb_hcd *hcd) { - struct omap_usb_config *config = pdev->dev.platform_data; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct omap_usb_config *config = hcd->self.controller->platform_data; int need_transceiver = (config->otg != 0); int ret; - dev_dbg(&pdev->dev, "starting USB Controller\n"); + dev_dbg(hcd->self.controller, "starting USB Controller\n"); if (config->otg) { ohci_to_hcd(ohci)->self.otg_port = config->otg; @@ -200,7 +211,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) if (ohci->transceiver) { int status = otg_set_host(ohci->transceiver, &ohci_to_hcd(ohci)->self); - dev_dbg(&pdev->dev, "init %s transceiver, status %d\n", + dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n", ohci->transceiver->label, status); if (status) { if (ohci->transceiver) @@ -208,7 +219,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) return status; } } else { - dev_err(&pdev->dev, "can't find transceiver\n"); + dev_err(hcd->self.controller, "can't find transceiver\n"); return -ENODEV; } } @@ -247,6 +258,10 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) } ohci_writel(ohci, rh, &ohci->regs->roothub.a); distrust_firmware = 0; + } else if (machine_is_nokia770()) { + /* We require a self-powered hub, which should have + * plenty of power. */ + ohci_to_hcd(ohci)->power_budget = 0; } /* FIXME khubd hub requests should manage power switching */ @@ -260,21 +275,15 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) return 0; } -static void omap_stop_hc(struct platform_device *pdev) +static void ohci_omap_stop(struct usb_hcd *hcd) { - dev_dbg(&pdev->dev, "stopping USB Controller\n"); + dev_dbg(hcd->self.controller, "stopping USB Controller\n"); omap_ohci_clock_power(0); } /*-------------------------------------------------------------------------*/ -void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - /** * usb_hcd_omap_probe - initialize OMAP-based HCDs * Context: !in_interrupt() @@ -283,7 +292,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. */ -int usb_hcd_omap_probe (const struct hc_driver *driver, +static int usb_hcd_omap_probe (const struct hc_driver *driver, struct platform_device *pdev) { int retval, irq; @@ -291,12 +300,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, struct ohci_hcd *ohci; if (pdev->num_resources != 2) { - printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", + printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", pdev->num_resources); return -ENODEV; } - if (pdev->resource[0].flags != IORESOURCE_MEM + if (pdev->resource[0].flags != IORESOURCE_MEM || pdev->resource[1].flags != IORESOURCE_IRQ) { printk(KERN_ERR "hcd probe: invalid resource type\n"); return -ENODEV; @@ -306,6 +315,17 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, if (IS_ERR(usb_host_ck)) return PTR_ERR(usb_host_ck); + if (!cpu_is_omap1510()) + usb_dc_ck = clk_get(0, "usb_dc_ck"); + else + usb_dc_ck = clk_get(0, "lb_ck"); + + if (IS_ERR(usb_dc_ck)) { + clk_put(usb_host_ck); + return PTR_ERR(usb_dc_ck); + } + + hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id); if (!hcd) { retval = -ENOMEM; @@ -325,9 +345,8 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, ohci = hcd_to_ohci(hcd); ohci_hcd_init(ohci); - retval = omap_start_hc(ohci, pdev); - if (retval < 0) - goto err2; + host_initialized = 0; + host_enabled = 1; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -335,15 +354,21 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, goto err2; } retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); - if (retval == 0) - return retval; + if (retval) + goto err2; + + host_initialized = 1; + + if (!host_enabled) + omap_ohci_clock_power(0); - omap_stop_hc(pdev); + return 0; err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); err0: + clk_put(usb_dc_ck); clk_put(usb_host_ck); return retval; } @@ -359,28 +384,36 @@ err0: * Reverses the effect of usb_hcd_omap_probe(), first invoking * the HCD's stop() method. It is always called from a thread * context, normally "rmmod", "apmd", or something similar. - * */ -void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) +static inline void +usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + usb_remove_hcd(hcd); + if (ohci->transceiver) { + (void) otg_set_host(ohci->transceiver, 0); + put_device(ohci->transceiver->dev); + } if (machine_is_omap_osk()) omap_free_gpio(9); - omap_stop_hc(pdev); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); + clk_put(usb_dc_ck); clk_put(usb_host_ck); } /*-------------------------------------------------------------------------*/ -static int __devinit +static int ohci_omap_start (struct usb_hcd *hcd) { struct omap_usb_config *config; struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; + if (!host_enabled) + return 0; config = hcd->self.controller->platform_data; if (config->otg || config->rwc) { ohci->hc_control = OHCI_CTRL_RWC; @@ -411,8 +444,9 @@ static const struct hc_driver ohci_omap_hc_driver = { /* * basic lifecycle operations */ + .reset = ohci_omap_init, .start = ohci_omap_start, - .stop = ohci_stop, + .stop = ohci_omap_stop, /* * managing i/o requests and associated device resources @@ -449,13 +483,8 @@ static int ohci_hcd_omap_drv_probe(struct platform_device *dev) static int ohci_hcd_omap_drv_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci (hcd); usb_hcd_omap_remove(hcd, dev); - if (ohci->transceiver) { - (void) otg_set_host(ohci->transceiver, 0); - put_device(ohci->transceiver->dev); - } platform_set_drvdata(dev, NULL); return 0; @@ -475,7 +504,7 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) omap_ohci_clock_power(0); ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = PMSG_SUSPEND; + dev->dev.power.power_state = PMSG_SUSPEND; return 0; } @@ -488,8 +517,8 @@ static int ohci_omap_resume(struct platform_device *dev) ohci->next_statechange = jiffies; omap_ohci_clock_power(1); - dev->power.power_state = PMSG_ON; - usb_hcd_resume_root_hub(dev_get_drvdata(dev)); + dev->dev.power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(platform_get_drvdata(dev)); return 0; } -- cgit v1.2.3-70-g09d2 From 066202dd48cf3296b6cc22b5fcf89aef33fa0efc Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Sat, 5 Aug 2006 20:37:11 -0300 Subject: USB: Make file operations structs in drivers/usb const. Making structs const prevents accidental bugs and with the proper debug options they're protected against corruption. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 2 +- drivers/usb/core/devices.c | 2 +- drivers/usb/core/devio.c | 2 +- drivers/usb/core/file.c | 2 +- drivers/usb/core/inode.c | 6 +++--- drivers/usb/core/usb.h | 4 ++-- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/inode.c | 8 ++++---- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/uhci-debug.c | 4 ++-- drivers/usb/image/mdc800.c | 4 ++-- drivers/usb/input/hiddev.c | 2 +- drivers/usb/misc/auerswald.c | 2 +- drivers/usb/misc/idmouse.c | 2 +- drivers/usb/misc/ldusb.c | 2 +- drivers/usb/misc/legousbtower.c | 2 +- drivers/usb/misc/sisusbvga/sisusb.c | 2 +- drivers/usb/misc/usblcd.c | 2 +- drivers/usb/mon/mon_stat.c | 2 +- drivers/usb/mon/mon_text.c | 2 +- drivers/usb/mon/usb_mon.h | 4 ++-- drivers/usb/usb-skeleton.c | 2 +- 24 files changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 48dee4b8d8e..292919d260a 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -813,7 +813,7 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product) return 0; } -static struct file_operations usblp_fops = { +static const struct file_operations usblp_fops = { .owner = THIS_MODULE, .read = usblp_read, .write = usblp_write, diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index c0f37343a27..241d37326ea 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -667,7 +667,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) return ret; } -struct file_operations usbfs_devices_fops = { +const struct file_operations usbfs_devices_fops = { .llseek = usb_device_lseek, .read = usb_device_read, .poll = usb_device_poll, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e84f19d4089..43c08724a2d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1572,7 +1572,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai return mask; } -struct file_operations usbfs_device_file_operations = { +const struct file_operations usbfs_device_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 8de4f8c99d6..c376c655c5d 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -55,7 +55,7 @@ static int usb_open(struct inode * inode, struct file * file) return err; } -static struct file_operations usb_fops = { +static const struct file_operations usb_fops = { .owner = THIS_MODULE, .open = usb_open, }; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 58b4b101212..df3d152f049 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -44,7 +44,7 @@ #include "hcd.h" static struct super_operations usbfs_ops; -static struct file_operations default_file_operations; +static const struct file_operations default_file_operations; static struct vfsmount *usbfs_mount; static int usbfs_mount_count; /* = 0 */ static int ignore_mount = 0; @@ -407,7 +407,7 @@ static int default_open (struct inode *inode, struct file *file) return 0; } -static struct file_operations default_file_operations = { +static const struct file_operations default_file_operations = { .read = default_read_file, .write = default_write_file, .open = default_open, @@ -494,7 +494,7 @@ static int fs_create_by_name (const char *name, mode_t mode, static struct dentry *fs_create_file (const char *name, mode_t mode, struct dentry *parent, void *data, - struct file_operations *fops, + const struct file_operations *fops, uid_t uid, gid_t gid) { struct dentry *dentry; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 98675fb1bc4..6096ead2758 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -90,8 +90,8 @@ extern const char *usbcore_name; /* usbfs stuff */ extern struct mutex usbfs_mutex; extern struct usb_driver usbfs_driver; -extern struct file_operations usbfs_devices_fops; -extern struct file_operations usbfs_device_file_operations; +extern const struct file_operations usbfs_devices_fops; +extern const struct file_operations usbfs_device_file_operations; extern void usbfs_conn_disc_event(void); extern int usbdev_init(void); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index cfebca05ead..d00958a01cf 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -247,7 +247,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) return single_open(file, proc_udc_show, PDE(inode)->data); } -static struct file_operations proc_ops = { +static const struct file_operations proc_ops = { .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ab508858f34..1072e987ff2 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -714,7 +714,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) /*----------------------------------------------------------------------*/ /* used after endpoint configuration */ -static struct file_operations ep_io_operations = { +static const struct file_operations ep_io_operations = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -873,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd) } /* used before endpoint configuration */ -static struct file_operations ep_config_operations = { +static const struct file_operations ep_config_operations = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -1247,7 +1247,7 @@ static int dev_ioctl (struct inode *inode, struct file *fd, } /* used after device configuration */ -static struct file_operations ep0_io_operations = { +static const struct file_operations ep0_io_operations = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -1929,7 +1929,7 @@ dev_open (struct inode *inode, struct file *fd) return value; } -static struct file_operations dev_init_operations = { +static const struct file_operations dev_init_operations = { .owner = THIS_MODULE, .llseek = no_llseek, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 81f0389fcc9..0a64504c254 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2437,7 +2437,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) return single_open(file, proc_udc_show, NULL); } -static struct file_operations proc_ops = { +static const struct file_operations proc_ops = { .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 8c6b38a0b5b..a72e041df8e 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1207,7 +1207,7 @@ static int isp116x_open_seq(struct inode *inode, struct file *file) return single_open(file, isp116x_show_dbg, inode->i_private); } -static struct file_operations isp116x_debug_fops = { +static const struct file_operations isp116x_debug_fops = { .open = isp116x_open_seq, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 9de115d9db2..8c17da37600 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1517,7 +1517,7 @@ static int proc_sl811h_open(struct inode *inode, struct file *file) return single_open(file, proc_sl811h_show, PDE(inode)->data); } -static struct file_operations proc_ops = { +static const struct file_operations proc_ops = { .open = proc_sl811h_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index d1372cb27f3..e345f15b7d8 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -16,7 +16,7 @@ #include "uhci-hcd.h" -#define uhci_debug_operations (* (struct file_operations *) NULL) +#define uhci_debug_operations (* (const struct file_operations *) NULL) static struct dentry *uhci_debugfs_root; #ifdef DEBUG @@ -500,7 +500,7 @@ static int uhci_debug_release(struct inode *inode, struct file *file) } #undef uhci_debug_operations -static struct file_operations uhci_debug_operations = { +static const struct file_operations uhci_debug_operations = { .owner = THIS_MODULE, .open = uhci_debug_open, .llseek = uhci_debug_lseek, diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 08daf400f98..ca6305c1d64 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -424,7 +424,7 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res) ***************************************************************************/ static struct usb_driver mdc800_usb_driver; -static struct file_operations mdc800_device_ops; +static const struct file_operations mdc800_device_ops; static struct usb_class_driver mdc800_class = { .name = "mdc800%d", .fops = &mdc800_device_ops, @@ -941,7 +941,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s ****************************************************************************/ /* File Operations of this drivers */ -static struct file_operations mdc800_device_ops = +static const struct file_operations mdc800_device_ops = { .owner = THIS_MODULE, .read = mdc800_device_read, diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index f6b839c257a..a2b419d1374 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -722,7 +722,7 @@ inval: return -EINVAL; } -static struct file_operations hiddev_fops = { +static const struct file_operations hiddev_fops = { .owner = THIS_MODULE, .read = hiddev_read, .write = hiddev_write, diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 1fef36e71c5..4a329d8488b 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -1858,7 +1858,7 @@ static int auerchar_release (struct inode *inode, struct file *file) /*----------------------------------------------------------------------*/ /* File operation structure */ -static struct file_operations auerswald_fops = +static const struct file_operations auerswald_fops = { .owner = THIS_MODULE, .llseek = no_llseek, diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index fcd69c52aea..8e6e195a22b 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -98,7 +98,7 @@ static int idmouse_probe(struct usb_interface *interface, static void idmouse_disconnect(struct usb_interface *interface); /* file operation pointers */ -static struct file_operations idmouse_fops = { +static const struct file_operations idmouse_fops = { .owner = THIS_MODULE, .read = idmouse_read, .open = idmouse_open, diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index f30ab1fbb3c..741736b6c13 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -589,7 +589,7 @@ exit: } /* file operations needed when we register this driver */ -static struct file_operations ld_usb_fops = { +static const struct file_operations ld_usb_fops = { .owner = THIS_MODULE, .read = ld_usb_read, .write = ld_usb_write, diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 7699d970e68..77c36e63c7b 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -259,7 +259,7 @@ static void tower_disconnect (struct usb_interface *interface); static DEFINE_MUTEX (disconnect_mutex); /* file operations needed when we register this driver */ -static struct file_operations tower_fops = { +static const struct file_operations tower_fops = { .owner = THIS_MODULE, .read = tower_read, .write = tower_write, diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index e16582f3733..a44124c7e85 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3179,7 +3179,7 @@ sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) } #endif -static struct file_operations usb_sisusb_fops = { +static const struct file_operations usb_sisusb_fops = { .owner = THIS_MODULE, .open = sisusb_open, .release = sisusb_release, diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index e095772dd8e..53e59e36233 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -239,7 +239,7 @@ error: return retval; } -static struct file_operations lcd_fops = { +static const struct file_operations lcd_fops = { .owner = THIS_MODULE, .read = lcd_read, .write = lcd_write, diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index 86ad2b381c4..f6d1491256c 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -62,7 +62,7 @@ static int mon_stat_release(struct inode *inode, struct file *file) return 0; } -struct file_operations mon_fops_stat = { +const struct file_operations mon_fops_stat = { .owner = THIS_MODULE, .open = mon_stat_open, .llseek = no_llseek, diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 2fd39b4fa16..775e374a960 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -435,7 +435,7 @@ static int mon_text_release(struct inode *inode, struct file *file) return 0; } -struct file_operations mon_fops_text = { +const struct file_operations mon_fops_text = { .owner = THIS_MODULE, .open = mon_text_open, .llseek = no_llseek, diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index 33678c24ebe..50efc8ee7c2 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -53,7 +53,7 @@ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); extern struct mutex mon_lock; -extern struct file_operations mon_fops_text; -extern struct file_operations mon_fops_stat; +extern const struct file_operations mon_fops_text; +extern const struct file_operations mon_fops_stat; #endif /* __USB_MON_H */ diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 33f0e81c58d..3339373239a 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -243,7 +243,7 @@ exit: return retval; } -static struct file_operations skel_fops = { +static const struct file_operations skel_fops = { .owner = THIS_MODULE, .read = skel_read, .write = skel_write, -- cgit v1.2.3-70-g09d2 From 64a21d025d3a979a8715f2ec7acabca7b5406c8a Mon Sep 17 00:00:00 2001 From: Aleksey Gorelov Date: Tue, 8 Aug 2006 17:24:08 -0700 Subject: USB: Properly unregister reboot notifier in case of failure in ehci hcd If some problem occurs during ehci startup, for instance, request_irq fails, echi hcd driver tries it best to cleanup, but fails to unregister reboot notifier, which in turn leads to crash on reboot/poweroff. The following patch resolves this problem by not using reboot notifiers anymore, but instead making ehci/ohci driver get its own shutdown method. For PCI, it is done through pci glue, for everything else through platform driver glue. One downside: sa1111 does not use platform driver stuff, and does not have its own shutdown hook, so no 'shutdown' is called for it now. I'm not sure if it is really necessary on that platform, though. Signed-off-by: Aleks Gorelov Cc: Alan Stern Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 16 ++++++++++++++++ drivers/usb/core/hcd.c | 11 +++++++++++ drivers/usb/core/hcd.h | 8 ++++++++ drivers/usb/host/ehci-au1xxx.c | 2 ++ drivers/usb/host/ehci-fsl.c | 2 ++ drivers/usb/host/ehci-hcd.c | 16 +++++----------- drivers/usb/host/ehci-pci.c | 2 ++ drivers/usb/host/ehci.h | 1 - drivers/usb/host/ohci-at91.c | 2 ++ drivers/usb/host/ohci-au1xxx.c | 2 ++ drivers/usb/host/ohci-ep93xx.c | 2 ++ drivers/usb/host/ohci-hcd.c | 12 ++++-------- drivers/usb/host/ohci-lh7a404.c | 2 ++ drivers/usb/host/ohci-mem.c | 1 - drivers/usb/host/ohci-omap.c | 2 ++ drivers/usb/host/ohci-pci.c | 3 +++ drivers/usb/host/ohci-ppc-soc.c | 2 ++ drivers/usb/host/ohci-pxa27x.c | 2 ++ drivers/usb/host/ohci-s3c2410.c | 2 ++ drivers/usb/host/ohci.h | 2 -- 20 files changed, 69 insertions(+), 23 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index fa36391fedd..edf4300a3f7 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -413,4 +413,20 @@ EXPORT_SYMBOL (usb_hcd_pci_resume); #endif /* CONFIG_PM */ +/** + * usb_hcd_pci_shutdown - shutdown host controller + * @dev: USB Host Controller being shutdown + */ +void usb_hcd_pci_shutdown (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + + hcd = pci_get_drvdata(dev); + if (!hcd) + return; + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} +EXPORT_SYMBOL (usb_hcd_pci_shutdown); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fb4d058bbde..dc9628c5893 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -1915,6 +1916,16 @@ void usb_remove_hcd(struct usb_hcd *hcd) } EXPORT_SYMBOL (usb_remove_hcd); +void +usb_hcd_platform_shutdown(struct platform_device* dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} +EXPORT_SYMBOL (usb_hcd_platform_shutdown); + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_USB_MON) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 7022aafb2ae..58c7767bc90 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -192,6 +192,9 @@ struct hc_driver { /* cleanly make HCD stop writing memory and doing I/O */ void (*stop) (struct usb_hcd *hcd); + /* shutdown HCD */ + void (*shutdown) (struct usb_hcd *hcd); + /* return current frame number */ int (*get_frame_number) (struct usb_hcd *hcd); @@ -227,6 +230,9 @@ extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); +struct platform_device; +extern void usb_hcd_platform_shutdown(struct platform_device* dev); + #ifdef CONFIG_PCI struct pci_dev; struct pci_device_id; @@ -239,6 +245,8 @@ extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state); extern int usb_hcd_pci_resume (struct pci_dev *dev); #endif /* CONFIG_PM */ +extern void usb_hcd_pci_shutdown (struct pci_dev *dev); + #endif /* CONFIG_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 26ed757d22a..5d1b12aad77 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -200,6 +200,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { .reset = ehci_init, .start = ehci_run, .stop = ehci_stop, + .shutdown = ehci_shutdown, /* * managing i/o requests and associated device resources @@ -268,6 +269,7 @@ MODULE_ALIAS("au1xxx-ehci"); static struct platform_driver ehci_hcd_au1xxx_driver = { .probe = ehci_hcd_au1xxx_drv_probe, .remove = ehci_hcd_au1xxx_drv_remove, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ehci_hcd_au1xxx_drv_suspend, */ /*.resume = ehci_hcd_au1xxx_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index d030516edfb..1a915e982c1 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -285,6 +285,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .resume = ehci_bus_resume, #endif .stop = ehci_stop, + .shutdown = ehci_shutdown, /* * managing i/o requests and associated device resources @@ -329,6 +330,7 @@ MODULE_ALIAS("fsl-ehci"); static struct platform_driver ehci_fsl_driver = { .probe = ehci_fsl_drv_probe, .remove = ehci_fsl_drv_remove, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "fsl-ehci", }, diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d63177a8eae..1c54b303e5f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -292,21 +292,20 @@ static void ehci_watchdog (unsigned long param) spin_unlock_irqrestore (&ehci->lock, flags); } -/* Reboot notifiers kick in for silicon on any bus (not just pci, etc). +/* ehci_shutdown kick in for silicon on any bus (not just pci, etc). * This forcibly disables dma and IRQs, helping kexec and other cases * where the next system software may expect clean state. */ -static int -ehci_reboot (struct notifier_block *self, unsigned long code, void *null) +static void +ehci_shutdown (struct usb_hcd *hcd) { - struct ehci_hcd *ehci; + struct ehci_hcd *ehci; - ehci = container_of (self, struct ehci_hcd, reboot_notifier); + ehci = hcd_to_ehci (hcd); (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ writel (0, &ehci->regs->configured_flag); - return 0; } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -381,7 +380,6 @@ static void ehci_stop (struct usb_hcd *hcd) /* let companion controllers work when we aren't */ writel (0, &ehci->regs->configured_flag); - unregister_reboot_notifier (&ehci->reboot_notifier); remove_debug_files (ehci); @@ -483,9 +481,6 @@ static int ehci_init(struct usb_hcd *hcd) } ehci->command = temp; - ehci->reboot_notifier.notifier_call = ehci_reboot; - register_reboot_notifier(&ehci->reboot_notifier); - return 0; } @@ -499,7 +494,6 @@ static int ehci_run (struct usb_hcd *hcd) /* EHCI spec section 4.1 */ if ((retval = ehci_reset(ehci)) != 0) { - unregister_reboot_notifier(&ehci->reboot_notifier); ehci_mem_cleanup(ehci); return retval; } diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 6967ab71e28..e6a3bcddd55 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -338,6 +338,7 @@ static const struct hc_driver ehci_pci_hc_driver = { .resume = ehci_pci_resume, #endif .stop = ehci_stop, + .shutdown = ehci_shutdown, /* * managing i/o requests and associated device resources @@ -384,4 +385,5 @@ static struct pci_driver ehci_pci_driver = { .suspend = usb_hcd_pci_suspend, .resume = usb_hcd_pci_resume, #endif + .shutdown = usb_hcd_pci_shutdown, }; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 679c1cdcc91..1385ce2b3f0 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -82,7 +82,6 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ struct timer_list watchdog; - struct notifier_block reboot_notifier; unsigned long actions; unsigned stamp; unsigned long next_statechange; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 33b75087bc0..5a5bdf374d7 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -221,6 +221,7 @@ static const struct hc_driver ohci_at91_hc_driver = { */ .start = ohci_at91_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -310,6 +311,7 @@ MODULE_ALIAS("at91_ohci"); static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, .remove = ohci_hcd_at91_drv_remove, + .shutdown = usb_hcd_platform_shutdown, .suspend = ohci_hcd_at91_drv_suspend, .resume = ohci_hcd_at91_drv_resume, .driver = { diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 44ed3a4c01e..24e23c5783d 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -269,6 +269,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .start = ohci_au1xxx_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -335,6 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_au1xxx_driver = { .probe = ohci_hcd_au1xxx_drv_probe, .remove = ohci_hcd_au1xxx_drv_remove, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_au1xxx_drv_suspend, */ /*.resume = ohci_hcd_au1xxx_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 1a1d320b799..1bf5e7a4e73 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -128,6 +128,7 @@ static struct hc_driver ohci_ep93xx_hc_driver = { .flags = HCD_USB11 | HCD_MEMORY, .start = ohci_ep93xx_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, .urb_enqueue = ohci_urb_enqueue, .urb_dequeue = ohci_urb_dequeue, .endpoint_disable = ohci_endpoint_disable, @@ -203,6 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) static struct platform_driver ohci_hcd_ep93xx_driver = { .probe = ohci_hcd_ep93xx_drv_probe, .remove = ohci_hcd_ep93xx_drv_remove, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_hcd_ep93xx_drv_suspend, .resume = ohci_hcd_ep93xx_drv_resume, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 7c3d8c60a60..2c614af8f73 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -136,7 +136,6 @@ static const char hcd_name [] = "ohci_hcd"; static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); -static int ohci_reboot (struct notifier_block *, unsigned long , void *); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -419,21 +418,20 @@ static void ohci_usb_reset (struct ohci_hcd *ohci) ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } -/* reboot notifier forcibly disables IRQs and DMA, helping kexec and +/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and * other cases where the next software may expect clean state from the * "firmware". this is bus-neutral, unlike shutdown() methods. */ -static int -ohci_reboot (struct notifier_block *block, unsigned long code, void *null) +static void +ohci_shutdown (struct usb_hcd *hcd) { struct ohci_hcd *ohci; - ohci = container_of (block, struct ohci_hcd, reboot_notifier); + ohci = hcd_to_ohci (hcd); ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_usb_reset (ohci); /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); - return 0; } /*-------------------------------------------------------------------------* @@ -504,7 +502,6 @@ static int ohci_init (struct ohci_hcd *ohci) if ((ret = ohci_mem_init (ohci)) < 0) ohci_stop (hcd); else { - register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); } @@ -800,7 +797,6 @@ static void ohci_stop (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); remove_debug_files (ohci); - unregister_reboot_notifier (&ohci->reboot_notifier); ohci_mem_cleanup (ohci); if (ohci->hcca) { dma_free_coherent (hcd->self.controller, diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index f2c9161d6d6..e121d97ed91 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -174,6 +174,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .start = ohci_lh7a404_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -241,6 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_lh7a404_driver = { .probe = ohci_hcd_lh7a404_drv_probe, .remove = ohci_hcd_lh7a404_drv_remove, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_lh7a404_drv_suspend, */ /*.resume = ohci_hcd_lh7a404_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index bfbe328a478..d976614eebd 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - ohci->reboot_notifier.notifier_call = ohci_reboot; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 160cd4c58a0..9c02177de50 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -447,6 +447,7 @@ static const struct hc_driver ohci_omap_hc_driver = { .reset = ohci_omap_init, .start = ohci_omap_start, .stop = ohci_omap_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -532,6 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_omap_driver = { .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_omap_suspend, .resume = ohci_omap_resume, diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ef874443aa9..3732db7d68e 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -177,6 +177,7 @@ static const struct hc_driver ohci_pci_hc_driver = { .reset = ohci_pci_reset, .start = ohci_pci_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, #ifdef CONFIG_PM /* these suspend/resume entries are for upstream PCI glue ONLY */ @@ -232,6 +233,8 @@ static struct pci_driver ohci_pci_driver = { .suspend = usb_hcd_pci_suspend, .resume = usb_hcd_pci_resume, #endif + + .shutdown = usb_hcd_pci_shutdown, }; diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 270aaaad8c6..d9d1ae236bd 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -148,6 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .start = ohci_ppc_soc_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -196,6 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) static struct platform_driver ohci_hcd_ppc_soc_driver = { .probe = ohci_hcd_ppc_soc_drv_probe, .remove = ohci_hcd_ppc_soc_drv_remove, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 2752d36c2a7..e176b04d7ae 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -270,6 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .start = ohci_pxa27x_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -358,6 +359,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev) static struct platform_driver ohci_hcd_pxa27x_driver = { .probe = ohci_hcd_pxa27x_drv_probe, .remove = ohci_hcd_pxa27x_drv_remove, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_hcd_pxa27x_drv_suspend, .resume = ohci_hcd_pxa27x_drv_resume, diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index cd37eddf7d4..59e436424d4 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -447,6 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .start = ohci_s3c2410_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -491,6 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev) static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ /*.resume = ohci_hcd_s3c2410_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index caacf14371f..650d1bf21c1 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -389,8 +389,6 @@ struct ohci_hcd { unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ - struct notifier_block reboot_notifier; - unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ -- cgit v1.2.3-70-g09d2 From de06a3b842b31b31220637c869f112cfbc1a5ef6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 11 Aug 2006 11:33:58 -0400 Subject: UHCI: increase Resume-Detect-off delay The UHCI controller in my laptop takes longer to turn off the Resume-Detect bit than the 4 us allowed by uhci-hcd. Presumably other computers will have the same problem. This patch (as752) increases the maximum delay to 10 us, which should be plenty, and uses polling to avoid penalizing systems which can turn the bit off more quickly. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hub.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index c545ef92fe2..16fb72eb6fc 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -84,6 +84,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, unsigned long port_addr) { int status; + int i; if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) { CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); @@ -92,9 +93,14 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, /* The controller won't actually turn off the RD bit until * it has had a chance to send a low-speed EOP sequence, - * which takes 3 bit times (= 2 microseconds). We'll delay - * slightly longer for good luck. */ - udelay(4); + * which is supposed to take 3 bit times (= 2 microseconds). + * Experiments show that some controllers take longer, so + * we'll poll for completion. */ + for (i = 0; i < 10; ++i) { + if (!(inw(port_addr) & USBPORTSC_RD)) + break; + udelay(1); + } } clear_bit(port, &uhci->resuming_ports); } -- cgit v1.2.3-70-g09d2 From 1720058343fa43a1a25bfad9e62ea06e7e9743b6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 11:32:52 -0400 Subject: usbcore: trim down usb_bus structure As part of the ongoing program to flatten out the HCD bus-glue layer, this patch (as771b) eliminates the hcpriv, release, and kref fields from struct usb_bus. hcpriv and release were not being used for anything worthwhile, and kref has been moved into the enclosing usb_hcd structure. Along with those changes, the patch gets rid of usb_bus_get and usb_bus_put, replacing them with usb_get_hcd and usb_put_hcd. The one interesting aspect is that the dev_set_drvdata call was removed from usb_put_hcd, where it clearly doesn't belong. This means the driver private data won't get reset to NULL. It shouldn't cause any problems, since the private data is undefined when no driver is bound. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 4 +-- drivers/usb/core/hcd.c | 67 +++++++++++++++--------------------------- drivers/usb/core/hcd.h | 13 ++++---- drivers/usb/core/usb.c | 5 ++-- drivers/usb/gadget/dummy_hcd.c | 8 ++--- drivers/usb/host/ehci-dbg.c | 6 ++-- drivers/usb/host/ohci-dbg.c | 6 ++-- drivers/usb/mon/mon_main.c | 6 ++-- include/linux/usb.h | 3 -- 9 files changed, 44 insertions(+), 74 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index f4f4ef0f377..840442a25b6 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -104,7 +104,7 @@ void *hcd_buffer_alloc ( dma_addr_t *dma ) { - struct usb_hcd *hcd = bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(bus); int i; /* some USB hosts just use PIO */ @@ -127,7 +127,7 @@ void hcd_buffer_free ( dma_addr_t dma ) { - struct usb_hcd *hcd = bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(bus); int i; if (!addr) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0cc14206920..9dfc812de03 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -664,31 +664,6 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) /*-------------------------------------------------------------------------*/ -/* exported only within usbcore */ -struct usb_bus *usb_bus_get(struct usb_bus *bus) -{ - if (bus) - kref_get(&bus->kref); - return bus; -} - -static void usb_host_release(struct kref *kref) -{ - struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - - if (bus->release) - bus->release(bus); -} - -/* exported only within usbcore */ -void usb_bus_put(struct usb_bus *bus) -{ - if (bus) - kref_put(&bus->kref, usb_host_release); -} - -/*-------------------------------------------------------------------------*/ - static struct class *usb_host_class; int usb_host_init(void) @@ -720,15 +695,12 @@ static void usb_bus_init (struct usb_bus *bus) bus->devnum_next = 1; bus->root_hub = NULL; - bus->hcpriv = NULL; bus->busnum = -1; bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list); - - kref_init(&bus->kref); } /*-------------------------------------------------------------------------*/ @@ -1081,7 +1053,7 @@ static void urb_unlink (struct urb *urb) int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; - struct usb_hcd *hcd = urb->dev->bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); struct usb_host_endpoint *ep; unsigned long flags; @@ -1189,7 +1161,8 @@ done: /* called in any context */ int usb_hcd_get_frame_number (struct usb_device *udev) { - struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + if (!HC_IS_RUNNING (hcd->state)) return -ESHUTDOWN; return hcd->driver->get_frame_number (hcd); @@ -1262,7 +1235,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) spin_lock (&hcd_data_lock); sys = &urb->dev->dev; - hcd = urb->dev->bus->hcpriv; + hcd = bus_to_hcd(urb->dev->bus); if (hcd == NULL) { retval = -ENODEV; goto done; @@ -1333,7 +1306,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_hcd *hcd; struct urb *urb; - hcd = udev->bus->hcpriv; + hcd = bus_to_hcd(udev->bus); WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && udev->state != USB_STATE_NOTATTACHED); @@ -1673,14 +1646,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ -static void hcd_release (struct usb_bus *bus) -{ - struct usb_hcd *hcd; - - hcd = container_of(bus, struct usb_hcd, self); - kfree(hcd); -} - /** * usb_create_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd @@ -1705,10 +1670,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, return NULL; } dev_set_drvdata(dev, hcd); + kref_init(&hcd->kref); usb_bus_init(&hcd->self); - hcd->self.hcpriv = hcd; - hcd->self.release = &hcd_release; hcd->self.controller = dev; hcd->self.bus_name = bus_name; hcd->self.uses_dma = (dev->dma_mask != NULL); @@ -1725,10 +1689,25 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, } EXPORT_SYMBOL (usb_create_hcd); +static void hcd_release (struct kref *kref) +{ + struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); + + kfree(hcd); +} + +struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) +{ + if (hcd) + kref_get (&hcd->kref); + return hcd; +} +EXPORT_SYMBOL (usb_get_hcd); + void usb_put_hcd (struct usb_hcd *hcd) { - dev_set_drvdata(hcd->self.controller, NULL); - usb_bus_put(&hcd->self); + if (hcd) + kref_put (&hcd->kref, hcd_release); } EXPORT_SYMBOL (usb_put_hcd); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 83e22991479..7a2bcba2ae6 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -55,12 +55,13 @@ /*-------------------------------------------------------------------------*/ -struct usb_hcd { /* usb_bus.hcpriv points to this */ +struct usb_hcd { /* * housekeeping */ struct usb_bus self; /* hcd is-a bus */ + struct kref kref; /* reference counter */ const char *product_desc; /* product/vendor string */ char irq_descr[24]; /* driver + bus # */ @@ -129,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) return &hcd->self; } - -// urb.hcpriv is really hardware-specific +static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus) +{ + return container_of(bus, struct usb_hcd, self); +} struct hcd_timeout { /* timeouts we allocate */ struct list_head timeout_list; @@ -210,6 +213,7 @@ extern int usb_hcd_get_frame_number (struct usb_device *udev); extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); +extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd); extern void usb_put_hcd (struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); @@ -356,9 +360,6 @@ extern struct list_head usb_bus_list; extern struct mutex usb_bus_list_lock; extern wait_queue_head_t usb_kill_urb_queue; -extern struct usb_bus *usb_bus_get (struct usb_bus *bus); -extern void usb_bus_put (struct usb_bus *bus); - extern void usb_enable_root_hub_irq (struct usb_bus *bus); extern int usb_find_interface_driver (struct usb_device *dev, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7ab9d29215f..b0c0a993338 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -169,7 +169,7 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); usb_destroy_configuration(udev); - usb_bus_put(udev->bus); + usb_put_hcd(bus_to_hcd(udev->bus)); kfree(udev->product); kfree(udev->manufacturer); kfree(udev->serial); @@ -197,8 +197,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) if (!dev) return NULL; - bus = usb_bus_get(bus); - if (!bus) { + if (!usb_get_hcd(bus_to_hcd(bus))) { kfree(dev); return NULL; } diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 7d1c22c3495..fdab97a27c0 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -889,11 +889,9 @@ EXPORT_SYMBOL (net2280_set_fifo_mode); static void dummy_gadget_release (struct device *dev) { -#if 0 /* usb_bus_put isn't EXPORTed! */ struct dummy *dum = gadget_dev_to_dummy (dev); - usb_bus_put (&dummy_to_hcd (dum)->self); -#endif + usb_put_hcd (dummy_to_hcd (dum)); } static int dummy_udc_probe (struct platform_device *pdev) @@ -915,9 +913,7 @@ static int dummy_udc_probe (struct platform_device *pdev) if (rc < 0) return rc; -#if 0 /* usb_bus_get isn't EXPORTed! */ - usb_bus_get (&dummy_to_hcd (dum)->self); -#endif + usb_get_hcd (dummy_to_hcd (dum)); platform_set_drvdata (pdev, dum); device_create_file (&dum->gadget.dev, &dev_attr_function); diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 65ac9fef3a7..215ce6d0639 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -451,7 +451,7 @@ show_async (struct class_device *class_dev, char *buf) *buf = 0; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ehci = hcd_to_ehci (hcd); next = buf; size = PAGE_SIZE; @@ -497,7 +497,7 @@ show_periodic (struct class_device *class_dev, char *buf) seen_count = 0; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ehci = hcd_to_ehci (hcd); next = buf; size = PAGE_SIZE; @@ -634,7 +634,7 @@ show_registers (struct class_device *class_dev, char *buf) static char label [] = ""; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ehci = hcd_to_ehci (hcd); next = buf; size = PAGE_SIZE; diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index da52609a929..534d07dcb82 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -477,7 +477,7 @@ show_async (struct class_device *class_dev, char *buf) unsigned long flags; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); /* display control and bulk lists together, for simplicity */ @@ -510,7 +510,7 @@ show_periodic (struct class_device *class_dev, char *buf) seen_count = 0; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); next = buf; size = PAGE_SIZE; @@ -607,7 +607,7 @@ show_registers (struct class_device *class_dev, char *buf) u32 rdata; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); regs = ohci->regs; next = buf; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 275a66f8305..e0ed36cdfd8 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -265,7 +265,6 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) ubus->mon_bus = NULL; mbus->u_bus = NULL; mb(); - // usb_bus_put(ubus); } /* @@ -297,10 +296,9 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) INIT_LIST_HEAD(&mbus->r_list); /* - * This usb_bus_get here is superfluous, because we receive - * a notification if usb_bus is about to be removed. + * We don't need to take a reference to ubus, because we receive + * a notification if the bus is about to be removed. */ - // usb_bus_get(ubus); mbus->u_bus = ubus; ubus->mon_bus = mbus; diff --git a/include/linux/usb.h b/include/linux/usb.h index 09661759621..c66303285a4 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -280,7 +280,6 @@ struct usb_bus { struct usb_devmap devmap; /* device address allocation map */ struct usb_device *root_hub; /* Root hub */ struct list_head bus_list; /* list of busses */ - void *hcpriv; /* Host Controller private data */ int bandwidth_allocated; /* on this bus: how much of the time * reserved for periodic (intr/iso) @@ -295,8 +294,6 @@ struct usb_bus { struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ struct class_device *class_dev; /* class device for this bus */ - struct kref kref; /* reference counting for this bus */ - void (*release)(struct usb_bus *bus); #if defined(CONFIG_USB_MON) struct mon_bus *mon_bus; /* non-null when associated */ -- cgit v1.2.3-70-g09d2 From 53bd6a601a87bb6d0df844872bc15fd4e8d127ce Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 30 Aug 2006 14:50:06 -0700 Subject: USB: EHCI whitespace fixes (cosmetic) [ ... when you have an editor set to remind you of whitespace bugs ... ] Cosmetic EHCI changes: remove end-of-line whitespace, spaces before tabs. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 14 +++++++------- drivers/usb/host/ehci-hcd.c | 6 +++--- drivers/usb/host/ehci-hub.c | 12 ++++++------ drivers/usb/host/ehci-mem.c | 14 +++++++------- drivers/usb/host/ehci-q.c | 20 ++++++++++---------- drivers/usb/host/ehci-sched.c | 26 +++++++++++++------------- drivers/usb/host/ehci.h | 36 ++++++++++++++++++------------------ 7 files changed, 64 insertions(+), 64 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 215ce6d0639..9cd6270d06b 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2002 by David Brownell - * + * * 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 @@ -65,7 +65,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) for (i = 0; i < HCS_N_PORTS (params); i++) { // FIXME MIPS won't readb() ... byte = readb (&ehci->caps->portroute[(i>>1)]); - sprintf(tmp, "%d ", + sprintf(tmp, "%d ", ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf))); strcat(buf, tmp); } @@ -141,12 +141,12 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) } static void __attribute__((__unused__)) -dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) +dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) { ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n", label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb); ehci_dbg (ehci, - " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", + " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", le32_to_cpu(itd->hw_transaction[0]), le32_to_cpu(itd->hw_transaction[1]), le32_to_cpu(itd->hw_transaction[2]), @@ -156,7 +156,7 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) le32_to_cpu(itd->hw_transaction[6]), le32_to_cpu(itd->hw_transaction[7])); ehci_dbg (ehci, - " buf: %08x %08x %08x %08x %08x %08x %08x\n", + " buf: %08x %08x %08x %08x %08x %08x %08x\n", le32_to_cpu(itd->hw_bufp[0]), le32_to_cpu(itd->hw_bufp[1]), le32_to_cpu(itd->hw_bufp[2]), @@ -171,12 +171,12 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) } static void __attribute__((__unused__)) -dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd) +dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd) { ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n", label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb); ehci_dbg (ehci, - " addr %08x sched %04x result %08x buf %08x %08x\n", + " addr %08x sched %04x result %08x buf %08x %08x\n", le32_to_cpu(sitd->hw_fullspeed_ep), le32_to_cpu(sitd->hw_uframe), le32_to_cpu(sitd->hw_results), diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1c54b303e5f..4e1a8c30889 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2000-2004 by David Brownell - * + * * 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 @@ -70,7 +70,7 @@ * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared; * only scheduling is different, no arbitrary limitations. * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support, - * clean up HC run state handshaking. + * clean up HC run state handshaking. * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other * missing pieces: enabling 64bit dma, handoff from BIOS/SMM. @@ -425,7 +425,7 @@ static int ehci_init(struct usb_hcd *hcd) /* controllers may cache some of the periodic schedule ... */ hcc_params = readl(&ehci->caps->hcc_params); - if (HCC_ISOC_CACHE(hcc_params)) // full frame cache + if (HCC_ISOC_CACHE(hcc_params)) // full frame cache ehci->i_thresh = 8; else // N microframes cached ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index d03e3cad5ca..a5eeb9cd6ab 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 by David Brownell - * + * * 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 @@ -103,10 +103,10 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /* re-init operational registers in case we lost power */ if (readl (&ehci->regs->intr_enable) == 0) { - /* at least some APM implementations will try to deliver + /* at least some APM implementations will try to deliver * IRQs right away, so delay them until we're ready. - */ - intr_enable = 1; + */ + intr_enable = 1; writel (0, &ehci->regs->segment); writel (ehci->periodic_dma, &ehci->regs->frame_list); writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); @@ -232,7 +232,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) buf [1] = 0; retval++; } - + /* no hub change reports (bit 0) for now (power, ...) */ /* port N changes (bit N)? */ @@ -304,7 +304,7 @@ ehci_hub_descriptor ( /*-------------------------------------------------------------------------*/ -#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) static int ehci_hub_control ( struct usb_hcd *hcd, diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 766061e0260..a8ba2e1497a 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2001 by David Brownell - * + * * 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 @@ -25,7 +25,7 @@ * - data used only by the HCD ... kmalloc is fine * - async and periodic schedules, shared by HC and HCD ... these * need to use dma_pool or dma_alloc_coherent - * - driver buffers, read/written by HC ... single shot DMA mapped + * - driver buffers, read/written by HC ... single shot DMA mapped * * There's also PCI "register" data, which is memory mapped. * No memory seen by this driver is pageable. @@ -119,7 +119,7 @@ static inline void qh_put (struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -/* The queue heads and transfer descriptors are managed from pools tied +/* The queue heads and transfer descriptors are managed from pools tied * to each of the "per device" structures. * This is the initialisation and cleanup code. */ @@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) int i; /* QTDs for control/bulk/intr transfers */ - ehci->qtd_pool = dma_pool_create ("ehci_qtd", + ehci->qtd_pool = dma_pool_create ("ehci_qtd", ehci_to_hcd(ehci)->self.controller, sizeof (struct ehci_qtd), 32 /* byte alignment (for hw parts) */, @@ -175,7 +175,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) } /* QHs for control/bulk/intr transfers */ - ehci->qh_pool = dma_pool_create ("ehci_qh", + ehci->qh_pool = dma_pool_create ("ehci_qh", ehci_to_hcd(ehci)->self.controller, sizeof (struct ehci_qh), 32 /* byte alignment (for hw parts) */, @@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) } /* ITD for high speed ISO transfers */ - ehci->itd_pool = dma_pool_create ("ehci_itd", + ehci->itd_pool = dma_pool_create ("ehci_itd", ehci_to_hcd(ehci)->self.controller, sizeof (struct ehci_itd), 32 /* byte alignment (for hw parts) */, @@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) } /* SITD for full/low speed split ISO transfers */ - ehci->sitd_pool = dma_pool_create ("ehci_sitd", + ehci->sitd_pool = dma_pool_create ("ehci_sitd", ehci_to_hcd(ehci)->self.controller, sizeof (struct ehci_sitd), 32 /* byte alignment (for hw parts) */, diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index e469221e7ec..c0da40bbfa3 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 by David Brownell - * + * * 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 @@ -31,7 +31,7 @@ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with * interrupts) needs careful scheduling. Performance improvements can be * an ongoing challenge. That's in "ehci-sched.c". - * + * * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, * or otherwise through transaction translators (TTs) in USB 2.0 hubs using * (b) special fields in qh entries or (c) split iso entries. TTs will @@ -199,7 +199,7 @@ static void qtd_copy_status ( && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_TDI(ehci) - || urb->dev->tt->hub != + || urb->dev->tt->hub != ehci_to_hcd(ehci)->self.root_hub)) { #ifdef DEBUG struct usb_device *tt = urb->dev->tt->hub; @@ -364,7 +364,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) */ if (likely (urb->status == -EINPROGRESS)) continue; - + /* issue status after short control reads */ if (unlikely (do_status != 0) && QTD_PID (token) == 0 /* OUT */) { @@ -388,7 +388,7 @@ halt: wmb (); } } - + /* remove it from the queue */ spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); @@ -518,7 +518,7 @@ qh_urb_transaction ( /* for zero length DATA stages, STATUS is always IN */ if (len == 0) token |= (1 /* "in" */ << 8); - } + } /* * data transfer stage: buffer setup @@ -759,7 +759,7 @@ qh_make ( } break; default: - dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); + dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); done: qh_put (qh); return NULL; @@ -972,7 +972,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; qh->qh_next.qh = NULL; - qh_put (qh); // refcount from reclaim + qh_put (qh); // refcount from reclaim /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; @@ -1031,7 +1031,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) timer_action_done (ehci, TIMER_ASYNC_OFF); } return; - } + } qh->qh_state = QH_STATE_UNLINK; ehci->reclaim = qh = qh_get (qh); @@ -1046,7 +1046,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) { /* if (unlikely (qh->reclaim != 0)) - * this will recurse, probably not much + * this will recurse, probably not much */ end_unlink_async (ehci, NULL); return; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 4859900bd13..e5e9c653c90 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2001-2004 by David Brownell * Copyright (c) 2003 Michal Sojka, for high-speed iso transfers - * + * * 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 @@ -613,7 +613,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ static int check_period ( - struct ehci_hcd *ehci, + struct ehci_hcd *ehci, unsigned frame, unsigned uframe, unsigned period, @@ -629,7 +629,7 @@ static int check_period ( /* * 80% periodic == 100 usec/uframe available - * convert "usecs we need" to "max already claimed" + * convert "usecs we need" to "max already claimed" */ usecs = 100 - usecs; @@ -659,14 +659,14 @@ static int check_period ( } static int check_intr_schedule ( - struct ehci_hcd *ehci, + struct ehci_hcd *ehci, unsigned frame, unsigned uframe, const struct ehci_qh *qh, __le32 *c_maskp ) { - int retval = -ENOSPC; + int retval = -ENOSPC; u8 mask = 0; if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ @@ -701,7 +701,7 @@ static int check_intr_schedule ( /* Make sure this tt's buffer is also available for CSPLITs. * We pessimize a bit; probably the typical full speed case * doesn't need the second CSPLIT. - * + * * NOTE: both SPLIT and CSPLIT could be checked in just * one smart pass... */ @@ -728,7 +728,7 @@ done: */ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) { - int status; + int status; unsigned uframe; __le32 c_mask; unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ @@ -784,7 +784,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) ehci_dbg (ehci, "reused qh %p schedule\n", qh); /* stuff into the periodic schedule */ - status = qh_link_periodic (ehci, qh); + status = qh_link_periodic (ehci, qh); done: return status; } @@ -1681,7 +1681,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, status = -ESHUTDOWN; else status = iso_stream_schedule (ehci, urb, stream); - if (likely (status == 0)) + if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); spin_unlock_irqrestore (&ehci->lock, flags); @@ -1738,7 +1738,7 @@ sitd_sched_init ( if (packet->buf1 != (buf & ~(u64)0x0fff)) packet->cross = 1; - /* OUT uses multiple start-splits */ + /* OUT uses multiple start-splits */ if (stream->bEndpointAddress & USB_DIR_IN) continue; length = (length + 187) / 188; @@ -1925,7 +1925,7 @@ sitd_link_urb ( /*-------------------------------------------------------------------------*/ #define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ - | SITD_STS_XACT | SITD_STS_MMF) + | SITD_STS_XACT | SITD_STS_MMF) static unsigned sitd_complete ( @@ -2043,7 +2043,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, status = -ESHUTDOWN; else status = iso_stream_schedule (ehci, urb, stream); - if (status == 0) + if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); spin_unlock_irqrestore (&ehci->lock, flags); @@ -2226,5 +2226,5 @@ restart: now_uframe++; now_uframe %= mod; } - } + } } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 1385ce2b3f0..bbc3082a73d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2002 by David Brownell - * + * * 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 @@ -103,7 +103,7 @@ struct ehci_hcd { /* one per controller */ #endif }; -/* convert between an HCD pointer and the corresponding EHCI_HCD */ +/* convert between an HCD pointer and the corresponding EHCI_HCD */ static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd) { return (struct ehci_hcd *) (hcd->hcd_priv); @@ -178,8 +178,8 @@ struct ehci_caps { #define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ #define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */ #define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */ -#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ -#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ +#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ #define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ u32 hcc_params; /* HCCPARAMS - offset 0x8 */ @@ -204,7 +204,7 @@ struct ehci_regs { #define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ #define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ #define CMD_ASE (1<<5) /* async schedule enable */ -#define CMD_PSE (1<<4) /* periodic schedule enable */ +#define CMD_PSE (1<<4) /* periodic schedule enable */ /* 3:2 is periodic frame list size */ #define CMD_RESET (1<<1) /* reset HC not bus */ #define CMD_RUN (1<<0) /* start/stop HC */ @@ -230,9 +230,9 @@ struct ehci_regs { /* FRINDEX: offset 0x0C */ u32 frame_index; /* current microframe number */ /* CTRLDSSEGMENT: offset 0x10 */ - u32 segment; /* address bits 63:32 if needed */ + u32 segment; /* address bits 63:32 if needed */ /* PERIODICLISTBASE: offset 0x14 */ - u32 frame_list; /* points to periodic list */ + u32 frame_list; /* points to periodic list */ /* ASYNCLISTADDR: offset 0x18 */ u32 async_next; /* address of next async queue head */ @@ -301,7 +301,7 @@ struct ehci_dbg_port { /* * EHCI Specification 0.95 Section 3.5 - * QTD: describe data transfer components (buffer, direction, ...) + * QTD: describe data transfer components (buffer, direction, ...) * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". * * These are associated only with "QH" (Queue Head) structures, @@ -311,7 +311,7 @@ struct ehci_qtd { /* first part defined by EHCI spec */ __le32 hw_next; /* see EHCI 3.5.1 */ __le32 hw_alt_next; /* see EHCI 3.5.2 */ - __le32 hw_token; /* see EHCI 3.5.3 */ + __le32 hw_token; /* see EHCI 3.5.3 */ #define QTD_TOGGLE (1 << 31) /* data toggle */ #define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) #define QTD_IOC (1 << 15) /* interrupt on complete */ @@ -348,8 +348,8 @@ struct ehci_qtd { /* values for that type tag */ #define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1) #define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1) -#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1) -#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1) +#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1) +#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1) /* next async queue entry, or pointer to interrupt/periodic QH */ #define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH) @@ -366,7 +366,7 @@ struct ehci_qtd { * For entries in the async schedule, the type tag always says "qh". */ union ehci_shadow { - struct ehci_qh *qh; /* Q_TYPE_QH */ + struct ehci_qh *qh; /* Q_TYPE_QH */ struct ehci_itd *itd; /* Q_TYPE_ITD */ struct ehci_sitd *sitd; /* Q_TYPE_SITD */ struct ehci_fstn *fstn; /* Q_TYPE_FSTN */ @@ -396,7 +396,7 @@ struct ehci_qh { #define QH_HUBPORT 0x3f800000 #define QH_MULT 0xc0000000 __le32 hw_current; /* qtd list - see EHCI 3.6.4 */ - + /* qtd overlay (hardware parts of a struct ehci_qtd) */ __le32 hw_qtd_next; __le32 hw_alt_next; @@ -471,7 +471,7 @@ struct ehci_iso_stream { struct list_head td_list; /* queued itds/sitds */ struct list_head free_list; /* list of unused itds/sitds */ struct usb_device *udev; - struct usb_host_endpoint *ep; + struct usb_host_endpoint *ep; /* output of (re)scheduling */ unsigned long start; /* jiffies */ @@ -491,8 +491,8 @@ struct ehci_iso_stream { unsigned bandwidth; /* This is used to initialize iTD's hw_bufp fields */ - __le32 buf0; - __le32 buf1; + __le32 buf0; + __le32 buf1; __le32 buf2; /* this is used to initialize sITD's tt info */ @@ -520,7 +520,7 @@ struct ehci_itd { #define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE) - __le32 hw_bufp [7]; /* see EHCI 3.3.3 */ + __le32 hw_bufp [7]; /* see EHCI 3.3.3 */ __le32 hw_bufp_hi [7]; /* Appendix B */ /* the rest is HCD-private */ @@ -541,7 +541,7 @@ struct ehci_itd { /*-------------------------------------------------------------------------*/ /* - * EHCI Specification 0.95 Section 3.4 + * EHCI Specification 0.95 Section 3.4 * siTD, aka split-transaction isochronous Transfer Descriptor * ... describe full speed iso xfers through TT in hubs * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD) -- cgit v1.2.3-70-g09d2 From cd22afda3f84452c6def29a68b06933e814e0e95 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 3 Sep 2006 12:21:50 -0700 Subject: USB: ohci-at91, two one-liners This includes two one-liners forwarded to me for the OHCI support on at91: - KB920x (and other boards with CPUs in non-BGA packages) need a slightly different way to say "ignore that port, it's not pinned out"; - On resume, if we turn clocks on, record that we did so. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 5a5bdf374d7..b466581beb4 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -193,7 +193,7 @@ ohci_at91_start (struct usb_hcd *hcd) if ((ret = ohci_init(ohci)) < 0) return ret; - root->maxchild = board->ports; + ohci->num_ports = board->ports; if ((ret = ohci_run(ohci)) < 0) { err("can't start %s", hcd->self.bus_name); @@ -297,6 +297,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) if (!clocked) { clk_enable(iclk); clk_enable(fclk); + clocked = 1; } return 0; -- cgit v1.2.3-70-g09d2 From 02c399ee45a54987c152fe5f627ed949bb55f187 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:47:11 -0400 Subject: usbcore: remove usb_suspend_root_hub This patch (as740) removes the existing support for autosuspend of root hubs. That support fit in rather awkwardly with the rest of usbcore and it was used only by ohci-hcd. It won't be needed any more since the hub driver will take care of autosuspending all hubs, root or external. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 44 -------------------------------------------- drivers/usb/core/hcd.h | 6 ------ drivers/usb/core/hub.c | 18 +----------------- drivers/usb/core/usb.h | 1 - drivers/usb/host/ohci-hub.c | 3 --- 5 files changed, 1 insertion(+), 71 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9dfc812de03..e86f6295708 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1431,50 +1431,6 @@ int hcd_bus_resume (struct usb_bus *bus) return status; } -/* - * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports - * @hcd: host controller for this root hub - * - * This call arranges that usb_hcd_resume_root_hub() is safe to call later; - * that the HCD's root hub polling is deactivated; and that the root's hub - * driver is suspended. HCDs may call this to autosuspend when their root - * hub's downstream ports are all inactive: unpowered, disconnected, - * disabled, or suspended. - * - * The HCD will autoresume on device connect change detection (using SRP - * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling - * from any ports that are suspended (if that is enabled). In most cases, - * overcurrent signaling (on powered ports) will also start autoresume. - * - * Always called with IRQs blocked. - */ -void usb_hcd_suspend_root_hub (struct usb_hcd *hcd) -{ - struct urb *urb; - - spin_lock (&hcd_root_hub_lock); - usb_suspend_root_hub (hcd->self.root_hub); - - /* force status urb to complete/unlink while suspended */ - if (hcd->status_urb) { - urb = hcd->status_urb; - urb->status = -ECONNRESET; - urb->hcpriv = NULL; - urb->actual_length = 0; - - del_timer (&hcd->rh_timer); - hcd->poll_pending = 0; - hcd->status_urb = NULL; - } else - urb = NULL; - spin_unlock (&hcd_root_hub_lock); - hcd->state = HC_STATE_SUSPENDED; - - if (urb) - usb_hcd_giveback_urb (hcd, urb, NULL); -} -EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub); - /** * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 7a2bcba2ae6..676877c15f8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -368,17 +368,11 @@ extern int usb_find_interface_driver (struct usb_device *dev, #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #ifdef CONFIG_PM -extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd); extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern void usb_root_hub_lost_power (struct usb_device *rhdev); extern int hcd_bus_suspend (struct usb_bus *bus); extern int hcd_bus_resume (struct usb_bus *bus); #else -static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd) -{ - return; -} - static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) { return; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dee812bc6c4..7479bd329ab 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -452,18 +452,14 @@ static void hub_power_on(struct usb_hub *hub) msleep(max(pgood_delay, (unsigned) 100)); } -static inline void __hub_quiesce(struct usb_hub *hub) +static void hub_quiesce(struct usb_hub *hub) { /* (nonblocking) khubd and related activity won't re-trigger */ hub->quiescing = 1; hub->activating = 0; hub->resume_root_hub = 0; -} -static void hub_quiesce(struct usb_hub *hub) -{ /* (blocking) stop khubd and related activity */ - __hub_quiesce(hub); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work(&hub->leds); @@ -1914,18 +1910,6 @@ static inline int remote_wakeup(struct usb_device *udev) #define hub_resume NULL #endif -void usb_suspend_root_hub(struct usb_device *hdev) -{ - struct usb_hub *hub = hdev_to_hub(hdev); - - /* This also makes any led blinker stop retriggering. We're called - * from irq, so the blinker might still be scheduled. Caller promises - * that the root hub status URB will be canceled. - */ - __hub_quiesce(hub); - mark_quiesced(to_usb_interface(hub->intfdev)); -} - void usb_resume_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 10688ad73c6..e8bc2e48913 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -20,7 +20,6 @@ extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern void usb_kick_khubd(struct usb_device *dev); -extern void usb_suspend_root_hub(struct usb_device *hdev); extern void usb_resume_root_hub(struct usb_device *dev); extern int usb_hub_init(void); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index f1b1ed086bd..0b899339cac 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -135,9 +135,6 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) hcd->poll_rh = 0; done: - /* external suspend vs self autosuspend ... same effect */ - if (status == 0) - usb_hcd_suspend_root_hub(hcd); spin_unlock_irqrestore (&ohci->lock, flags); return status; } -- cgit v1.2.3-70-g09d2 From 1ee95216c0db6305c047a90b0822e2f1d2d5acdc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 28 Aug 2006 11:43:25 -0700 Subject: USB: fix __must_check warnings in drivers/usb/host/ Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 7 ++++--- drivers/usb/host/ohci-dbg.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 9cd6270d06b..34b7a31cd85 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -785,10 +785,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); static inline void create_debug_files (struct ehci_hcd *ehci) { struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; + int retval; - class_device_create_file(cldev, &class_device_attr_async); - class_device_create_file(cldev, &class_device_attr_periodic); - class_device_create_file(cldev, &class_device_attr_registers); + retval = class_device_create_file(cldev, &class_device_attr_async); + retval = class_device_create_file(cldev, &class_device_attr_periodic); + retval = class_device_create_file(cldev, &class_device_attr_registers); } static inline void remove_debug_files (struct ehci_hcd *ehci) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 534d07dcb82..8293c1d4be3 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -685,10 +685,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); static inline void create_debug_files (struct ohci_hcd *ohci) { struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; + int retval; - class_device_create_file(cldev, &class_device_attr_async); - class_device_create_file(cldev, &class_device_attr_periodic); - class_device_create_file(cldev, &class_device_attr_registers); + retval = class_device_create_file(cldev, &class_device_attr_async); + retval = class_device_create_file(cldev, &class_device_attr_periodic); + retval = class_device_create_file(cldev, &class_device_attr_registers); ohci_dbg (ohci, "created debug files\n"); } -- cgit v1.2.3-70-g09d2 From d774efeabccf5f5207aa70d5c126fc928e8b30bd Mon Sep 17 00:00:00 2001 From: Tony Olech Date: Wed, 13 Sep 2006 11:27:35 +0100 Subject: USB: u132-hcd: host controller driver for ELAN U132 adapter This "u132-hcd" module is one half of the "driver" for ELAN's U132 which is a USB to CardBus OHCI controller adapter. This module needs the "ftdi-elan" module in order to communicate to CardBus OHCI controller inserted into the U132 adapter. When the "ftdi-elan" module detects a supported CardBus OHCI controller in the U132 adapter it loads this "u132-hcd" module. Upon a successful device probe() the single workqueue is started up which does all the processing of commands from the USB core that implement the host controller. The workqueue maintains the urb queues and issues commands via the functions exported by the "ftdi-elan" module. Each such command will result in a callback. Note that the "ftdi-elan" module is a USB client driver. Note that this "u132-hcd" module is a (cut-down OHCI) host controller. Thus we have a topology with the parent of a host controller being a USB client! This really stresses the USB subsystem semaphore/mutex handling in the module removal. Signed-off-by: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/host/Kconfig | 28 + drivers/usb/host/Makefile | 1 + drivers/usb/host/u132-hcd.c | 3295 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 3325 insertions(+) create mode 100644 drivers/usb/host/u132-hcd.c (limited to 'drivers/usb/host') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index e3364705709..97d57cfc343 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ +obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_ETRAX_USB_HOST) += host/ obj-$(CONFIG_USB_OHCI_AT91) += host/ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4bd5cddae8a..cf10cbc98f8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -142,6 +142,34 @@ config USB_UHCI_HCD To compile this driver as a module, choose M here: the module will be called uhci-hcd. +config USB_U132_HCD + tristate "Elan U132 Adapter Host Controller" + depends on USB && USB_FTDI_ELAN + default M + help + The U132 adapter is a USB to CardBus adapter specifically designed + for PC cards that contain an OHCI host controller. Typical PC cards + are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 + adapter will *NOT* work with PC cards that do not contain an OHCI + controller. + + For those PC cards that contain multiple OHCI controllers only ther + first one is used. + + The driver consists of two modules, the "ftdi-elan" module is a + USB client driver that interfaces to the FTDI chip within ELAN's + USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host + controller driver that talks to the OHCI controller within the + CardBus cards that are inserted in the U132 adapter. + + This driver has been tested with a CardBus OHCI USB adapter, and + worked with a USB PEN Drive inserted into the first USB port of + the PCCARD. A rather pointless thing to do, but useful for testing. + + It is safe to say M here. + + See also + config USB_SL811_HCD tristate "SL811HS HCD support" depends on USB diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index e3020f4b17b..a2e58c86849 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -14,4 +14,5 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o +obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c new file mode 100644 index 00000000000..cb2e2a604d1 --- /dev/null +++ b/drivers/usb/host/u132-hcd.c @@ -0,0 +1,3295 @@ +/* +* Host Controller Driver for the Elan Digital Systems U132 adapter +* +* Copyright(C) 2006 Elan Digital Systems Limited +* http://www.elandigitalsystems.com +* +* Author and Maintainer - Tony Olech - Elan Digital Systems +* tony.olech@elandigitalsystems.com +* +* 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, version 2. +* +* +* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) +* based on various USB host drivers in the 2.6.15 linux kernel +* with constant reference to the 3rd Edition of Linux Device Drivers +* published by O'Reilly +* +* The U132 adapter is a USB to CardBus adapter specifically designed +* for PC cards that contain an OHCI host controller. Typical PC cards +* are the Orange Mobile 3G Option GlobeTrotter Fusion card. +* +* The U132 adapter will *NOT *work with PC cards that do not contain +* an OHCI controller. A simple way to test whether a PC card has an +* OHCI controller as an interface is to insert the PC card directly +* into a laptop(or desktop) with a CardBus slot and if "lspci" shows +* a new USB controller and "lsusb -v" shows a new OHCI Host Controller +* then there is a good chance that the U132 adapter will support the +* PC card.(you also need the specific client driver for the PC card) +* +* Please inform the Author and Maintainer about any PC cards that +* contain OHCI Host Controller and work when directly connected to +* an embedded CardBus slot but do not work when they are connected +* via an ELAN U132 adapter. +* +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../core/hcd.h" +#include "ohci.h" +#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR +#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ + OHCI_INTR_WDH) +MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); +MODULE_DESCRIPTION("U132 USB Host Controller Driver"); +MODULE_LICENSE("GPL"); +#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) +INT_MODULE_PARM(testing, 0); +/* Some boards misreport power switching/overcurrent*/ +static int distrust_firmware = 1; +module_param(distrust_firmware, bool, 0); +MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" + "t setup"); +DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); +/* +* u132_module_lock exists to protect access to global variables +* +*/ +static struct semaphore u132_module_lock; +static int u132_exiting = 0; +static int u132_instances = 0; +static struct list_head u132_static_list; +/* +* end of the global variables protected by u132_module_lock +*/ +static struct workqueue_struct *workqueue; +#define MAX_U132_PORTS 7 +#define MAX_U132_ADDRS 128 +#define MAX_U132_UDEVS 4 +#define MAX_U132_ENDPS 100 +#define MAX_U132_RINGS 4 +static const char *cc_to_text[16] = { + "No Error ", + "CRC Error ", + "Bit Stuff ", + "Data Togg ", + "Stall ", + "DevNotResp ", + "PIDCheck ", + "UnExpPID ", + "DataOver ", + "DataUnder ", + "(for hw) ", + "(for hw) ", + "BufferOver ", + "BuffUnder ", + "(for HCD) ", + "(for HCD) " +}; +struct u132_port { + struct u132 *u132; + int reset; + int enable; + int power; + int Status; +}; +struct u132_addr { + u8 address; +}; +struct u132_udev { + struct kref kref; + struct usb_device *usb_device; + u8 enumeration; + u8 udev_number; + u8 usb_addr; + u8 portnumber; + u8 endp_number_in[16]; + u8 endp_number_out[16]; +}; +#define ENDP_QUEUE_SHIFT 3 +#define ENDP_QUEUE_SIZE (1<platform_dev, offsetof(struct \ + ohci_regs, member), 0, data); +#define u132_write_pcimem(u132, member, data) \ + usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ + ohci_regs, member), 0, data); +#define u132_write_pcimem_byte(u132, member, data) \ + usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ + ohci_regs, member), 0x0e, data); +static inline struct u132 *udev_to_u132(struct u132_udev *udev) +{ + u8 udev_number = udev->udev_number; + return container_of(udev, struct u132, udev[udev_number]); +} + +static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) +{ + return (struct u132 *)(hcd->hcd_priv); +} + +static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) +{ + return container_of((void *)u132, struct usb_hcd, hcd_priv); +} + +static inline void u132_disable(struct u132 *u132) +{ + u132_to_hcd(u132)->state = HC_STATE_HALT; +} + + +#define kref_to_u132(d) container_of(d, struct u132, kref) +#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) +#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) +#include "../misc/usb_u132.h" +static const char hcd_name[] = "u132_hcd"; +#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ + USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ + USB_PORT_STAT_C_RESET) << 16) +static void u132_hcd_delete(struct kref *kref) +{ + struct u132 *u132 = kref_to_u132(kref); + struct platform_device *pdev = u132->platform_dev; + struct usb_hcd *hcd = u132_to_hcd(u132); + u132->going += 1; + down(&u132_module_lock); + list_del_init(&u132->u132_list); + u132_instances -= 1; + up(&u132_module_lock); + dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" + "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); + usb_put_hcd(hcd); +} + +static inline void u132_u132_put_kref(struct u132 *u132) +{ + kref_put(&u132->kref, u132_hcd_delete); +} + +static inline void u132_u132_init_kref(struct u132 *u132) +{ + kref_init(&u132->kref); +} + +static void u132_udev_delete(struct kref *kref) +{ + struct u132_udev *udev = kref_to_u132_udev(kref); + udev->udev_number = 0; + udev->usb_device = NULL; + udev->usb_addr = 0; + udev->enumeration = 0; +} + +static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) +{ + kref_put(&udev->kref, u132_udev_delete); +} + +static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) +{ + kref_get(&udev->kref); +} + +static inline void u132_udev_init_kref(struct u132 *u132, + struct u132_udev *udev) +{ + kref_init(&udev->kref); +} + +static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) +{ + kref_put(&u132->kref, u132_hcd_delete); +} + +static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, + unsigned int delta) +{ + if (delta > 0) { + if (queue_delayed_work(workqueue, &ring->scheduler, delta)) + return; + } else if (queue_work(workqueue, &ring->scheduler)) + return; + kref_put(&u132->kref, u132_hcd_delete); + return; +} + +static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, + unsigned int delta) +{ + kref_get(&u132->kref); + u132_ring_requeue_work(u132, ring, delta); + return; +} + +static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) +{ + if (cancel_delayed_work(&ring->scheduler)) { + kref_put(&u132->kref, u132_hcd_delete); + } +} + +static void u132_endp_delete(struct kref *kref) +{ + struct u132_endp *endp = kref_to_u132_endp(kref); + struct u132 *u132 = endp->u132; + u8 usb_addr = endp->usb_addr; + u8 usb_endp = endp->usb_endp; + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + u8 endp_number = endp->endp_number; + struct usb_host_endpoint *hep = endp->hep; + struct u132_ring *ring = endp->ring; + struct list_head *head = &endp->endp_ring; + ring->length -= 1; + if (endp == ring->curr_endp) { + if (list_empty(head)) { + ring->curr_endp = NULL; + list_del(head); + } else { + struct u132_endp *next_endp = list_entry(head->next, + struct u132_endp, endp_ring); + ring->curr_endp = next_endp; + list_del(head); + }} else + list_del(head); + if (endp->input) { + udev->endp_number_in[usb_endp] = 0; + u132_udev_put_kref(u132, udev); + } + if (endp->output) { + udev->endp_number_out[usb_endp] = 0; + u132_udev_put_kref(u132, udev); + } + u132->endp[endp_number - 1] = NULL; + hep->hcpriv = NULL; + kfree(endp); + u132_u132_put_kref(u132); +} + +static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) +{ + kref_put(&endp->kref, u132_endp_delete); +} + +static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) +{ + kref_get(&endp->kref); +} + +static inline void u132_endp_init_kref(struct u132 *u132, + struct u132_endp *endp) +{ + kref_init(&endp->kref); + kref_get(&u132->kref); +} + +static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, + unsigned int delta) +{ + if (delta > 0) { + if (queue_delayed_work(workqueue, &endp->scheduler, delta)) + kref_get(&endp->kref); + } else if (queue_work(workqueue, &endp->scheduler)) + kref_get(&endp->kref); + return; +} + +static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) +{ + if (cancel_delayed_work(&endp->scheduler)) + kref_put(&endp->kref, u132_endp_delete); +} + +static inline void u132_monitor_put_kref(struct u132 *u132) +{ + kref_put(&u132->kref, u132_hcd_delete); +} + +static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) +{ + if (delta > 0) { + if (queue_delayed_work(workqueue, &u132->monitor, delta)) { + kref_get(&u132->kref); + } + } else if (queue_work(workqueue, &u132->monitor)) + kref_get(&u132->kref); + return; +} + +static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) +{ + if (delta > 0) { + if (queue_delayed_work(workqueue, &u132->monitor, delta)) + return; + } else if (queue_work(workqueue, &u132->monitor)) + return; + kref_put(&u132->kref, u132_hcd_delete); + return; +} + +static void u132_monitor_cancel_work(struct u132 *u132) +{ + if (cancel_delayed_work(&u132->monitor)) + kref_put(&u132->kref, u132_hcd_delete); +} + +static int read_roothub_info(struct u132 *u132) +{ + u32 revision; + int retval; + retval = u132_read_pcimem(u132, revision, &revision); + if (retval) { + dev_err(&u132->platform_dev->dev, "error %d accessing device co" + "ntrol\n", retval); + return retval; + } else if ((revision & 0xFF) == 0x10) { + } else if ((revision & 0xFF) == 0x11) { + } else { + dev_err(&u132->platform_dev->dev, "device revision is not valid" + " %08X\n", revision); + return -ENODEV; + } + retval = u132_read_pcimem(u132, control, &u132->hc_control); + if (retval) { + dev_err(&u132->platform_dev->dev, "error %d accessing device co" + "ntrol\n", retval); + return retval; + } + retval = u132_read_pcimem(u132, roothub.status, + &u132->hc_roothub_status); + if (retval) { + dev_err(&u132->platform_dev->dev, "error %d accessing device re" + "g roothub.status\n", retval); + return retval; + } + retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); + if (retval) { + dev_err(&u132->platform_dev->dev, "error %d accessing device re" + "g roothub.a\n", retval); + return retval; + } + { + int I = u132->num_ports; + int i = 0; + while (I-- > 0) { + retval = u132_read_pcimem(u132, roothub.portstatus[i], + &u132->hc_roothub_portstatus[i]); + if (retval) { + dev_err(&u132->platform_dev->dev, "error %d acc" + "essing device roothub.portstatus[%d]\n" + , retval, i); + return retval; + } else + i += 1; + } + } + return 0; +} + +static void u132_hcd_monitor_work(void *data) +{ + struct u132 *u132 = data; + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + u132_monitor_put_kref(u132); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + u132_monitor_put_kref(u132); + return; + } else { + int retval; + down(&u132->sw_lock); + retval = read_roothub_info(u132); + if (retval) { + struct usb_hcd *hcd = u132_to_hcd(u132); + u132_disable(u132); + u132->going = 1; + up(&u132->sw_lock); + usb_hc_died(hcd); + ftdi_elan_gone_away(u132->platform_dev); + u132_monitor_put_kref(u132); + return; + } else { + u132_monitor_requeue_work(u132, 500); + up(&u132->sw_lock); + return; + } + } +} + +static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, + struct urb *urb, int status) +{ + struct u132_ring *ring; + unsigned long irqs; + struct usb_hcd *hcd = u132_to_hcd(u132); + urb->error_count = 0; + urb->status = status; + urb->hcpriv = NULL; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + endp->queue_next += 1; + if (ENDP_QUEUE_SIZE > --endp->queue_size) { + endp->active = 0; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + } else { + struct list_head *next = endp->urb_more.next; + struct u132_urbq *urbq = list_entry(next, struct u132_urbq, + urb_more); + list_del(next); + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = + urbq->urb; + endp->active = 0; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(urbq); + } down(&u132->scheduler_lock); + ring = endp->ring; + ring->in_use = 0; + u132_ring_cancel_work(u132, ring); + u132_ring_queue_work(u132, ring, 0); + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + usb_hcd_giveback_urb(hcd, urb, NULL); + return; +} + +static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, + struct urb *urb, int status) +{ + u132_endp_put_kref(u132, endp); +} + +static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, + struct urb *urb, int status) +{ + unsigned long irqs; + struct usb_hcd *hcd = u132_to_hcd(u132); + urb->error_count = 0; + urb->status = status; + urb->hcpriv = NULL; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + endp->queue_next += 1; + if (ENDP_QUEUE_SIZE > --endp->queue_size) { + endp->active = 0; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + } else { + struct list_head *next = endp->urb_more.next; + struct u132_urbq *urbq = list_entry(next, struct u132_urbq, + urb_more); + list_del(next); + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = + urbq->urb; + endp->active = 0; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(urbq); + } usb_hcd_giveback_urb(hcd, urb, NULL); + return; +} + +static inline int edset_input(struct u132 *u132, struct u132_ring *ring, + struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, + urb, address, endp->usb_endp, toggle_bits, callback); +} + +static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, + struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, + urb, address, endp->usb_endp, toggle_bits, callback); +} + +static inline int edset_single(struct u132 *u132, struct u132_ring *ring, + struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, + endp, urb, address, endp->usb_endp, toggle_bits, callback); +} + +static inline int edset_output(struct u132 *u132, struct u132_ring *ring, + struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, + endp, urb, address, endp->usb_endp, toggle_bits, callback); +} + + +/* +* must not LOCK sw_lock +* +*/ +static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + struct u132_ring *ring = endp->ring; + u8 *u = urb->transfer_buffer + urb->actual_length; + u8 *b = buf; + int L = len; + while (L-- > 0) { + *u++ = *b++; + } + urb->actual_length += len; + if ((condition_code == TD_CC_NOERROR) && + (urb->transfer_buffer_length > urb->actual_length)) { + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, + 1 & toggle_bits); + if (urb->actual_length > 0) { + int retval; + up(&u132->scheduler_lock); + retval = edset_single(u132, ring, endp, urb, + address, endp->toggle_bits, + u132_hcd_interrupt_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, + retval); + } else { + ring->in_use = 0; + endp->active = 0; + endp->jiffies = jiffies + + msecs_to_jiffies(urb->interval); + u132_ring_cancel_work(u132, ring); + u132_ring_queue_work(u132, ring, 0); + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + } + return; + } else if ((condition_code == TD_DATAUNDERRUN) && + ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, + 1 & toggle_bits); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else { + if (condition_code == TD_CC_NOERROR) { + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, + 0, 1 & toggle_bits); + } else if (condition_code == TD_CC_STALL) { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, endp->usb_endp, + 0, 0); + } else { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, endp->usb_endp, + 0, 0); + dev_err(&u132->platform_dev->dev, "urb=%p givin" + "g back INTERRUPT %s\n", urb, + cc_to_text[condition_code]); + } + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, + cc_to_error[condition_code]); + return; + } + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + struct u132_ring *ring = endp->ring; + urb->actual_length += len; + endp->toggle_bits = toggle_bits; + if (urb->transfer_buffer_length > urb->actual_length) { + int retval; + up(&u132->scheduler_lock); + retval = edset_output(u132, ring, endp, urb, address, + endp->toggle_bits, u132_hcd_bulk_output_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else { + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + struct u132_ring *ring = endp->ring; + u8 *u = urb->transfer_buffer + urb->actual_length; + u8 *b = buf; + int L = len; + while (L-- > 0) { + *u++ = *b++; + } + urb->actual_length += len; + if ((condition_code == TD_CC_NOERROR) && + (urb->transfer_buffer_length > urb->actual_length)) { + int retval; + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, + 1 & toggle_bits); + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_input(u132->platform_dev, + ring->number, endp, urb, address, + endp->usb_endp, endp->toggle_bits, + u132_hcd_bulk_input_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else if (condition_code == TD_CC_NOERROR) { + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, + 1 & toggle_bits); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, + cc_to_error[condition_code]); + return; + } else if ((condition_code == TD_DATAUNDERRUN) && + ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, + 1 & toggle_bits); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else if (condition_code == TD_DATAUNDERRUN) { + endp->toggle_bits = toggle_bits; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, + 1 & toggle_bits); + dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" + ") giving back BULK IN %s\n", urb, + cc_to_text[condition_code]); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else if (condition_code == TD_CC_STALL) { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, + cc_to_error[condition_code]); + return; + } else { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); + dev_err(&u132->platform_dev->dev, "urb=%p giving back B" + "ULK IN code=%d %s\n", urb, condition_code, + cc_to_text[condition_code]); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, + cc_to_error[condition_code]); + return; + } + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + struct u132_ring *ring = endp->ring; + u8 *u = urb->transfer_buffer; + u8 *b = buf; + int L = len; + while (L-- > 0) { + *u++ = *b++; + } + urb->actual_length = len; + if ((condition_code == TD_CC_NOERROR) || ((condition_code == + TD_DATAUNDERRUN) && ((urb->transfer_flags & + URB_SHORT_NOT_OK) == 0))) { + int retval; + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_empty(u132->platform_dev, + ring->number, endp, urb, address, + endp->usb_endp, 0x3, + u132_hcd_configure_empty_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else if (condition_code == TD_CC_STALL) { + up(&u132->scheduler_lock); + dev_warn(&u132->platform_dev->dev, "giving back SETUP I" + "NPUT STALL urb %p\n", urb); + u132_hcd_giveback_urb(u132, endp, urb, + cc_to_error[condition_code]); + return; + } else { + up(&u132->scheduler_lock); + dev_err(&u132->platform_dev->dev, "giving back SETUP IN" + "PUT %s urb %p\n", cc_to_text[condition_code], + urb); + u132_hcd_giveback_urb(u132, endp, urb, + cc_to_error[condition_code]); + return; + } + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + if (usb_pipein(urb->pipe)) { + int retval; + struct u132_ring *ring = endp->ring; + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_input(u132->platform_dev, + ring->number, endp, urb, address, + endp->usb_endp, 0, + u132_hcd_configure_input_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else { + int retval; + struct u132_ring *ring = endp->ring; + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_input(u132->platform_dev, + ring->number, endp, urb, address, + endp->usb_endp, 0, + u132_hcd_configure_empty_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, + u8 *buf, int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + u132->addr[0].address = 0; + endp->usb_addr = udev->usb_addr; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, + u8 *buf, int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + int retval; + struct u132_ring *ring = endp->ring; + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_input(u132->platform_dev, + ring->number, endp, urb, 0, endp->usb_endp, 0, + u132_hcd_enumeration_empty_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, 0); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + int retval; + struct u132_ring *ring = endp->ring; + u8 *u = urb->transfer_buffer; + u8 *b = buf; + int L = len; + while (L-- > 0) { + *u++ = *b++; + } + urb->actual_length = len; + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_empty(u132->platform_dev, + ring->number, endp, urb, address, endp->usb_endp, 0x3, + u132_hcd_initial_empty_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, + int len, int toggle_bits, int error_count, int condition_code, + int repeat_number, int halted, int skipped, int actual, int non_null) +{ + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + u8 address = u132->addr[endp->usb_addr].address; + down(&u132->scheduler_lock); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + up(&u132->scheduler_lock); + u132_hcd_forget_urb(u132, endp, urb, -ENODEV); + return; + } else if (endp->dequeueing) { + endp->dequeueing = 0; + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -EINTR); + return; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; + } else if (urb->status == -EINPROGRESS) { + int retval; + struct u132_ring *ring = endp->ring; + up(&u132->scheduler_lock); + retval = usb_ftdi_elan_edset_input(u132->platform_dev, + ring->number, endp, urb, address, endp->usb_endp, 0, + u132_hcd_initial_input_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else { + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" + "s=%d\n", urb, urb->status); + up(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, urb->status); + return; + } +} + +static void u132_hcd_ring_work_scheduler(void *data); +static void u132_hcd_endp_work_scheduler(void *data); +/* +* this work function is only executed from the work queue +* +*/ +static void u132_hcd_ring_work_scheduler(void *data) +{ + struct u132_ring *ring = data; + struct u132 *u132 = ring->u132; + down(&u132->scheduler_lock); + if (ring->in_use) { + up(&u132->scheduler_lock); + u132_ring_put_kref(u132, ring); + return; + } else if (ring->curr_endp) { + struct u132_endp *last_endp = ring->curr_endp; + struct list_head *scan; + struct list_head *head = &last_endp->endp_ring; + unsigned long wakeup = 0; + list_for_each(scan, head) { + struct u132_endp *endp = list_entry(scan, + struct u132_endp, endp_ring); + if (endp->queue_next == endp->queue_last) { + } else if ((endp->delayed == 0) + || time_after_eq(jiffies, endp->jiffies)) { + ring->curr_endp = endp; + u132_endp_cancel_work(u132, last_endp); + u132_endp_queue_work(u132, last_endp, 0); + up(&u132->scheduler_lock); + u132_ring_put_kref(u132, ring); + return; + } else { + unsigned long delta = endp->jiffies - jiffies; + if (delta > wakeup) + wakeup = delta; + } + } + if (last_endp->queue_next == last_endp->queue_last) { + } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, + last_endp->jiffies)) { + u132_endp_cancel_work(u132, last_endp); + u132_endp_queue_work(u132, last_endp, 0); + up(&u132->scheduler_lock); + u132_ring_put_kref(u132, ring); + return; + } else { + unsigned long delta = last_endp->jiffies - jiffies; + if (delta > wakeup) + wakeup = delta; + } + if (wakeup > 0) { + u132_ring_requeue_work(u132, ring, wakeup); + up(&u132->scheduler_lock); + return; + } else { + up(&u132->scheduler_lock); + u132_ring_put_kref(u132, ring); + return; + } + } else { + up(&u132->scheduler_lock); + u132_ring_put_kref(u132, ring); + return; + } +} + +static void u132_hcd_endp_work_scheduler(void *data) +{ + struct u132_ring *ring; + struct u132_endp *endp = data; + struct u132 *u132 = endp->u132; + down(&u132->scheduler_lock); + ring = endp->ring; + if (endp->edset_flush) { + endp->edset_flush = 0; + if (endp->dequeueing) + usb_ftdi_elan_edset_flush(u132->platform_dev, + ring->number, endp); + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else if (endp->active) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else if (ring->in_use) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else if (endp->queue_next == endp->queue_last) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else if (endp->pipetype == PIPE_INTERRUPT) { + u8 address = u132->addr[endp->usb_addr].address; + if (ring->in_use) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else { + int retval; + struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & + endp->queue_next]; + endp->active = 1; + ring->curr_endp = endp; + ring->in_use = 1; + up(&u132->scheduler_lock); + retval = edset_single(u132, ring, endp, urb, address, + endp->toggle_bits, u132_hcd_interrupt_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } + } else if (endp->pipetype == PIPE_CONTROL) { + u8 address = u132->addr[endp->usb_addr].address; + if (ring->in_use) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else if (address == 0) { + int retval; + struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & + endp->queue_next]; + endp->active = 1; + ring->curr_endp = endp; + ring->in_use = 1; + up(&u132->scheduler_lock); + retval = edset_setup(u132, ring, endp, urb, address, + 0x2, u132_hcd_initial_setup_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else if (endp->usb_addr == 0) { + int retval; + struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & + endp->queue_next]; + endp->active = 1; + ring->curr_endp = endp; + ring->in_use = 1; + up(&u132->scheduler_lock); + retval = edset_setup(u132, ring, endp, urb, 0, 0x2, + u132_hcd_enumeration_address_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } else { + int retval; + u8 address = u132->addr[endp->usb_addr].address; + struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & + endp->queue_next]; + endp->active = 1; + ring->curr_endp = endp; + ring->in_use = 1; + up(&u132->scheduler_lock); + retval = edset_setup(u132, ring, endp, urb, address, + 0x2, u132_hcd_configure_setup_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, retval); + return; + } + } else { + if (endp->input) { + u8 address = u132->addr[endp->usb_addr].address; + if (ring->in_use) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else { + int retval; + struct urb *urb = endp->urb_list[ + ENDP_QUEUE_MASK & endp->queue_next]; + endp->active = 1; + ring->curr_endp = endp; + ring->in_use = 1; + up(&u132->scheduler_lock); + retval = edset_input(u132, ring, endp, urb, + address, endp->toggle_bits, + u132_hcd_bulk_input_recv); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, + retval); + return; + } + } else { /* output pipe */ + u8 address = u132->addr[endp->usb_addr].address; + if (ring->in_use) { + up(&u132->scheduler_lock); + u132_endp_put_kref(u132, endp); + return; + } else { + int retval; + struct urb *urb = endp->urb_list[ + ENDP_QUEUE_MASK & endp->queue_next]; + endp->active = 1; + ring->curr_endp = endp; + ring->in_use = 1; + up(&u132->scheduler_lock); + retval = edset_output(u132, ring, endp, urb, + address, endp->toggle_bits, + u132_hcd_bulk_output_sent); + if (retval == 0) { + } else + u132_hcd_giveback_urb(u132, endp, urb, + retval); + return; + } + } + } +} + +static void port_power(struct u132 *u132, int pn, int is_on) +{ + u132->port[pn].power = is_on; +} + +static void u132_power(struct u132 *u132, int is_on) +{ + struct usb_hcd *hcd = u132_to_hcd(u132) + ; /* hub is inactive unless the port is powered */ + if (is_on) { + if (u132->power) + return; + u132->power = 1; + hcd->self.controller->power.power_state = PMSG_ON; + } else { + u132->power = 0; + hcd->state = HC_STATE_HALT; + hcd->self.controller->power.power_state = PMSG_SUSPEND; + } +} + +static int u132_periodic_reinit(struct u132 *u132) +{ + int retval; + u32 fi = u132->hc_fminterval & 0x03fff; + u32 fit; + u32 fminterval; + retval = u132_read_pcimem(u132, fminterval, &fminterval); + if (retval) + return retval; + fit = fminterval & FIT; + retval = u132_write_pcimem(u132, fminterval, + (fit ^ FIT) | u132->hc_fminterval); + if (retval) + return retval; + retval = u132_write_pcimem(u132, periodicstart, + ((9 *fi) / 10) & 0x3fff); + if (retval) + return retval; + return 0; +} + +static char *hcfs2string(int state) +{ + switch (state) { + case OHCI_USB_RESET: + return "reset"; + case OHCI_USB_RESUME: + return "resume"; + case OHCI_USB_OPER: + return "operational"; + case OHCI_USB_SUSPEND: + return "suspend"; + } + return "?"; +} + +static int u132_usb_reset(struct u132 *u132) +{ + int retval; + retval = u132_read_pcimem(u132, control, &u132->hc_control); + if (retval) + return retval; + u132->hc_control &= OHCI_CTRL_RWC; + retval = u132_write_pcimem(u132, control, u132->hc_control); + if (retval) + return retval; + return 0; +} + +static int u132_init(struct u132 *u132) +{ + int retval; + u32 control; + u132_disable(u132); + u132->next_statechange = + jiffies; /* SMM owns the HC? not for long! */ { + u32 control; + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + if (control & OHCI_CTRL_IR) { + u32 temp = 50; + retval = u132_write_pcimem(u132, intrenable, + OHCI_INTR_OC); + if (retval) + return retval; + retval = u132_write_pcimem_byte(u132, cmdstatus, + OHCI_OCR); + if (retval) + return retval; + check:{ + retval = u132_read_pcimem(u132, control, + &control); + if (retval) + return retval; + } + if (control & OHCI_CTRL_IR) { + msleep(10); + if (--temp == 0) { + dev_err(&u132->platform_dev->dev, "USB " + "HC takeover failed!(BIOS/SMM b" + "ug) control=%08X\n", control); + return -EBUSY; + } + goto check; + } + u132_usb_reset(u132); + } + } + retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); + if (retval) + return retval; + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + if (u132->num_ports == 0) { + u32 rh_a = -1; + retval = u132_read_pcimem(u132, roothub.a, &rh_a); + if (retval) + return retval; + u132->num_ports = rh_a & RH_A_NDP; + retval = read_roothub_info(u132); + if (retval) + return retval; + } + if (u132->num_ports > MAX_U132_PORTS) { + return -EINVAL; + } + return 0; +} + + +/* Start an OHCI controller, set the BUS operational +* resets USB and controller +* enable interrupts +*/ +static int u132_run(struct u132 *u132) +{ + int retval; + u32 control; + u32 status; + u32 fminterval; + u32 periodicstart; + u32 cmdstatus; + u32 roothub_a; + int mask = OHCI_INTR_INIT; + int first = u132->hc_fminterval == 0; + int sleep_time = 0; + int reset_timeout = 30; /* ... allow extra time */ + u132_disable(u132); + if (first) { + u32 temp; + retval = u132_read_pcimem(u132, fminterval, &temp); + if (retval) + return retval; + u132->hc_fminterval = temp & 0x3fff; + if (u132->hc_fminterval != FI) { + } + u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; + } + retval = u132_read_pcimem(u132, control, &u132->hc_control); + if (retval) + return retval; + dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " + "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), + u132->hc_control); + switch (u132->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + sleep_time = 0; + break; + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + u132->hc_control &= OHCI_CTRL_RWC; + u132->hc_control |= OHCI_USB_RESUME; + sleep_time = 10; + break; + default: + u132->hc_control &= OHCI_CTRL_RWC; + u132->hc_control |= OHCI_USB_RESET; + sleep_time = 50; + break; + } + retval = u132_write_pcimem(u132, control, u132->hc_control); + if (retval) + return retval; + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + msleep(sleep_time); + retval = u132_read_pcimem(u132, roothub.a, &roothub_a); + if (retval) + return retval; + if (!(roothub_a & RH_A_NPS)) { + int temp; /* power down each port */ + for (temp = 0; temp < u132->num_ports; temp++) { + retval = u132_write_pcimem(u132, + roothub.portstatus[temp], RH_PS_LSDA); + if (retval) + return retval; + } + } + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + retry:retval = u132_read_pcimem(u132, cmdstatus, &status); + if (retval) + return retval; + retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR); + if (retval) + return retval; + extra:{ + retval = u132_read_pcimem(u132, cmdstatus, &status); + if (retval) + return retval; + if (0 != (status & OHCI_HCR)) { + if (--reset_timeout == 0) { + dev_err(&u132->platform_dev->dev, "USB HC reset" + " timed out!\n"); + return -ENODEV; + } else { + msleep(5); + goto extra; + } + } + } + if (u132->flags & OHCI_QUIRK_INITRESET) { + retval = u132_write_pcimem(u132, control, u132->hc_control); + if (retval) + return retval; + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + } + retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); + if (retval) + return retval; + retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); + if (retval) + return retval; + retval = u132_write_pcimem(u132, hcca, 0x00000000); + if (retval) + return retval; + retval = u132_periodic_reinit(u132); + if (retval) + return retval; + retval = u132_read_pcimem(u132, fminterval, &fminterval); + if (retval) + return retval; + retval = u132_read_pcimem(u132, periodicstart, &periodicstart); + if (retval) + return retval; + if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { + if (!(u132->flags & OHCI_QUIRK_INITRESET)) { + u132->flags |= OHCI_QUIRK_INITRESET; + goto retry; + } else + dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" + "\n", fminterval, periodicstart); + } /* start controller operations */ + u132->hc_control &= OHCI_CTRL_RWC; + u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; + retval = u132_write_pcimem(u132, control, u132->hc_control); + if (retval) + return retval; + retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF); + if (retval) + return retval; + retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); + if (retval) + return retval; + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + u132_to_hcd(u132)->state = HC_STATE_RUNNING; + retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); + if (retval) + return retval; + retval = u132_write_pcimem(u132, intrstatus, mask); + if (retval) + return retval; + retval = u132_write_pcimem(u132, intrdisable, + OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | + OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | + OHCI_INTR_SO); + if (retval) + return retval; /* handle root hub init quirks ... */ + retval = u132_read_pcimem(u132, roothub.a, &roothub_a); + if (retval) + return retval; + roothub_a &= ~(RH_A_PSM | RH_A_OCPM); + if (u132->flags & OHCI_QUIRK_SUPERIO) { + roothub_a |= RH_A_NOCP; + roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); + retval = u132_write_pcimem(u132, roothub.a, roothub_a); + if (retval) + return retval; + } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { + roothub_a |= RH_A_NPS; + retval = u132_write_pcimem(u132, roothub.a, roothub_a); + if (retval) + return retval; + } + retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); + if (retval) + return retval; + retval = u132_write_pcimem(u132, roothub.b, + (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); + if (retval) + return retval; + retval = u132_read_pcimem(u132, control, &control); + if (retval) + return retval; + mdelay((roothub_a >> 23) & 0x1fe); + u132_to_hcd(u132)->state = HC_STATE_RUNNING; + return 0; +} + +static void u132_hcd_stop(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" + "ed\n", hcd); + } else { + down(&u132->sw_lock); + msleep(100); + u132_power(u132, 0); + up(&u132->sw_lock); + } +} + +static int u132_hcd_start(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else if (hcd->self.controller) { + int retval; + struct platform_device *pdev = + to_platform_device(hcd->self.controller); + u16 vendor = ((struct u132_platform_data *) + (pdev->dev.platform_data))->vendor; + u16 device = ((struct u132_platform_data *) + (pdev->dev.platform_data))->device; + down(&u132->sw_lock); + msleep(10); + if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { + u132->flags = OHCI_QUIRK_AMD756; + } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { + dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" + "ounds unavailable\n"); + } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) + u132->flags |= OHCI_QUIRK_ZFMICRO; + retval = u132_run(u132); + if (retval) { + u132_disable(u132); + u132->going = 1; + } + msleep(100); + up(&u132->sw_lock); + return retval; + } else { + dev_err(&u132->platform_dev->dev, "platform_device missing\n"); + return -ENODEV; + } +} + +static int u132_hcd_reset(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else { + int retval; + down(&u132->sw_lock); + retval = u132_init(u132); + if (retval) { + u132_disable(u132); + u132->going = 1; + } + up(&u132->sw_lock); + return retval; + } +} + +static int create_endpoint_and_queue_int(struct u132 *u132, + struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, + gfp_t mem_flags) +{ + struct u132_ring *ring; + unsigned long irqs; + u8 endp_number = ++u132->num_endpoints; + struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = + kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { + return -ENOMEM; + } + INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + spin_lock_init(&endp->queue_lock.slock); + INIT_LIST_HEAD(&endp->urb_more); + ring = endp->ring = &u132->ring[0]; + if (ring->curr_endp) { + list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); + } else { + INIT_LIST_HEAD(&endp->endp_ring); + ring->curr_endp = endp; + } + ring->length += 1; + endp->dequeueing = 0; + endp->edset_flush = 0; + endp->active = 0; + endp->delayed = 0; + endp->endp_number = endp_number; + endp->u132 = u132; + endp->hep = hep; + endp->pipetype = usb_pipetype(urb->pipe); + u132_endp_init_kref(u132, endp); + if (usb_pipein(urb->pipe)) { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, usb_endp, 0, 0); + endp->input = 1; + endp->output = 0; + udev->endp_number_in[usb_endp] = endp_number; + u132_udev_get_kref(u132, udev); + } else { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, usb_endp, 1, 0); + endp->input = 0; + endp->output = 1; + udev->endp_number_out[usb_endp] = endp_number; + u132_udev_get_kref(u132, udev); + } + urb->hcpriv = u132; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + endp->delayed = 1; + endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); + endp->udev_number = address; + endp->usb_addr = usb_addr; + endp->usb_endp = usb_endp; + endp->queue_size = 1; + endp->queue_last = 0; + endp->queue_next = 0; + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); + return 0; +} + +static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, + struct usb_host_endpoint *hep, struct urb *urb, + struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, + u8 usb_endp, u8 address) +{ + urb->hcpriv = u132; + endp->delayed = 1; + endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); + if (endp->queue_size++ < ENDP_QUEUE_SIZE) { + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; + } else { + struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), + GFP_ATOMIC); + if (urbq == NULL) { + endp->queue_size -= 1; + return -ENOMEM; + } else { + list_add_tail(&urbq->urb_more, &endp->urb_more); + urbq->urb = urb; + } + } + return 0; +} + +static int create_endpoint_and_queue_bulk(struct u132 *u132, + struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, + gfp_t mem_flags) +{ + int ring_number; + struct u132_ring *ring; + unsigned long irqs; + u8 endp_number = ++u132->num_endpoints; + struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = + kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { + return -ENOMEM; + } + INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + spin_lock_init(&endp->queue_lock.slock); + INIT_LIST_HEAD(&endp->urb_more); + endp->dequeueing = 0; + endp->edset_flush = 0; + endp->active = 0; + endp->delayed = 0; + endp->endp_number = endp_number; + endp->u132 = u132; + endp->hep = hep; + endp->pipetype = usb_pipetype(urb->pipe); + u132_endp_init_kref(u132, endp); + if (usb_pipein(urb->pipe)) { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, usb_endp, 0, 0); + ring_number = 3; + endp->input = 1; + endp->output = 0; + udev->endp_number_in[usb_endp] = endp_number; + u132_udev_get_kref(u132, udev); + } else { + endp->toggle_bits = 0x2; + usb_settoggle(udev->usb_device, usb_endp, 1, 0); + ring_number = 2; + endp->input = 0; + endp->output = 1; + udev->endp_number_out[usb_endp] = endp_number; + u132_udev_get_kref(u132, udev); + } + ring = endp->ring = &u132->ring[ring_number - 1]; + if (ring->curr_endp) { + list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); + } else { + INIT_LIST_HEAD(&endp->endp_ring); + ring->curr_endp = endp; + } + ring->length += 1; + urb->hcpriv = u132; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + endp->udev_number = address; + endp->usb_addr = usb_addr; + endp->usb_endp = usb_endp; + endp->queue_size = 1; + endp->queue_last = 0; + endp->queue_next = 0; + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + u132_endp_queue_work(u132, endp, 0); + return 0; +} + +static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, + struct usb_host_endpoint *hep, struct urb *urb, + struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, + u8 usb_endp, u8 address) +{ + urb->hcpriv = u132; + if (endp->queue_size++ < ENDP_QUEUE_SIZE) { + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; + } else { + struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), + GFP_ATOMIC); + if (urbq == NULL) { + endp->queue_size -= 1; + return -ENOMEM; + } else { + list_add_tail(&urbq->urb_more, &endp->urb_more); + urbq->urb = urb; + } + } + return 0; +} + +static int create_endpoint_and_queue_control(struct u132 *u132, + struct usb_host_endpoint *hep, struct urb *urb, + struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, + gfp_t mem_flags) +{ + struct u132_ring *ring; + u8 endp_number = ++u132->num_endpoints; + struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = + kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { + return -ENOMEM; + } + INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + spin_lock_init(&endp->queue_lock.slock); + INIT_LIST_HEAD(&endp->urb_more); + ring = endp->ring = &u132->ring[0]; + if (ring->curr_endp) { + list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); + } else { + INIT_LIST_HEAD(&endp->endp_ring); + ring->curr_endp = endp; + } + ring->length += 1; + endp->dequeueing = 0; + endp->edset_flush = 0; + endp->active = 0; + endp->delayed = 0; + endp->endp_number = endp_number; + endp->u132 = u132; + endp->hep = hep; + u132_endp_init_kref(u132, endp); + u132_endp_get_kref(u132, endp); + if (usb_addr == 0) { + unsigned long irqs; + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + endp->udev_number = address; + endp->usb_addr = usb_addr; + endp->usb_endp = usb_endp; + endp->input = 1; + endp->output = 1; + endp->pipetype = usb_pipetype(urb->pipe); + u132_udev_init_kref(u132, udev); + u132_udev_get_kref(u132, udev); + udev->endp_number_in[usb_endp] = endp_number; + udev->endp_number_out[usb_endp] = endp_number; + urb->hcpriv = u132; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + endp->queue_size = 1; + endp->queue_last = 0; + endp->queue_next = 0; + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + u132_endp_queue_work(u132, endp, 0); + return 0; + } else { /*(usb_addr > 0) */ + unsigned long irqs; + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + endp->udev_number = address; + endp->usb_addr = usb_addr; + endp->usb_endp = usb_endp; + endp->input = 1; + endp->output = 1; + endp->pipetype = usb_pipetype(urb->pipe); + u132_udev_get_kref(u132, udev); + udev->enumeration = 2; + udev->endp_number_in[usb_endp] = endp_number; + udev->endp_number_out[usb_endp] = endp_number; + urb->hcpriv = u132; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + endp->queue_size = 1; + endp->queue_last = 0; + endp->queue_next = 0; + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + u132_endp_queue_work(u132, endp, 0); + return 0; + } +} + +static int queue_control_on_old_endpoint(struct u132 *u132, + struct usb_host_endpoint *hep, struct urb *urb, + struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, + u8 usb_endp) +{ + if (usb_addr == 0) { + if (usb_pipein(urb->pipe)) { + urb->hcpriv = u132; + if (endp->queue_size++ < ENDP_QUEUE_SIZE) { + endp->urb_list[ENDP_QUEUE_MASK & + endp->queue_last++] = urb; + } else { + struct u132_urbq *urbq = + kmalloc(sizeof(struct u132_urbq), + GFP_ATOMIC); + if (urbq == NULL) { + endp->queue_size -= 1; + return -ENOMEM; + } else { + list_add_tail(&urbq->urb_more, + &endp->urb_more); + urbq->urb = urb; + } + } + return 0; + } else { /* usb_pipeout(urb->pipe) */ + struct u132_addr *addr = &u132->addr[usb_dev->devnum]; + int I = MAX_U132_UDEVS; + int i = 0; + while (--I > 0) { + struct u132_udev *udev = &u132->udev[++i]; + if (udev->usb_device) { + continue; + } else { + udev->enumeration = 1; + u132->addr[0].address = i; + endp->udev_number = i; + udev->udev_number = i; + udev->usb_addr = usb_dev->devnum; + u132_udev_init_kref(u132, udev); + udev->endp_number_in[usb_endp] = + endp->endp_number; + u132_udev_get_kref(u132, udev); + udev->endp_number_out[usb_endp] = + endp->endp_number; + udev->usb_device = usb_dev; + ((u8 *) (urb->setup_packet))[2] = + addr->address = i; + u132_udev_get_kref(u132, udev); + break; + } + } + if (I == 0) { + dev_err(&u132->platform_dev->dev, "run out of d" + "evice space\n"); + return -EINVAL; + } + urb->hcpriv = u132; + if (endp->queue_size++ < ENDP_QUEUE_SIZE) { + endp->urb_list[ENDP_QUEUE_MASK & + endp->queue_last++] = urb; + } else { + struct u132_urbq *urbq = + kmalloc(sizeof(struct u132_urbq), + GFP_ATOMIC); + if (urbq == NULL) { + endp->queue_size -= 1; + return -ENOMEM; + } else { + list_add_tail(&urbq->urb_more, + &endp->urb_more); + urbq->urb = urb; + } + } + return 0; + } + } else { /*(usb_addr > 0) */ + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + urb->hcpriv = u132; + if (udev->enumeration == 2) { + } else + udev->enumeration = 2; + if (endp->queue_size++ < ENDP_QUEUE_SIZE) { + endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = + urb; + } else { + struct u132_urbq *urbq = + kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); + if (urbq == NULL) { + endp->queue_size -= 1; + return -ENOMEM; + } else { + list_add_tail(&urbq->urb_more, &endp->urb_more); + urbq->urb = urb; + } + } + return 0; + } +} + +static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, + struct urb *urb, gfp_t mem_flags) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (irqs_disabled()) { + if (__GFP_WAIT & mem_flags) { + printk(KERN_ERR "invalid context for function that migh" + "t sleep\n"); + return -EINVAL; + } + } + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed urb=" + "%p status=%d\n", urb, urb->status); + return -ESHUTDOWN; + } else { + u8 usb_addr = usb_pipedevice(urb->pipe); + u8 usb_endp = usb_pipeendpoint(urb->pipe); + struct usb_device *usb_dev = urb->dev; + if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + struct u132_endp *endp = hep->hcpriv; + urb->actual_length = 0; + if (endp) { + unsigned long irqs; + int retval; + spin_lock_irqsave(&endp->queue_lock.slock, + irqs); + retval = queue_int_on_old_endpoint(u132, udev, + hep, urb, usb_dev, endp, usb_addr, + usb_endp, address); + spin_unlock_irqrestore(&endp->queue_lock.slock, + irqs); + if (retval) { + return retval; + } else { + u132_endp_queue_work(u132, endp, + msecs_to_jiffies(urb->interval)) + ; + return 0; + } + } else if (u132->num_endpoints == MAX_U132_ENDPS) { + return -EINVAL; + } else { /*(endp == NULL) */ + return create_endpoint_and_queue_int(u132, udev, + hep, urb, usb_dev, usb_addr, usb_endp, + address, mem_flags); + } + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + dev_err(&u132->platform_dev->dev, "the hardware does no" + "t support PIPE_ISOCHRONOUS\n"); + return -EINVAL; + } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + struct u132_endp *endp = hep->hcpriv; + urb->actual_length = 0; + if (endp) { + unsigned long irqs; + int retval; + spin_lock_irqsave(&endp->queue_lock.slock, + irqs); + retval = queue_bulk_on_old_endpoint(u132, udev, + hep, urb, usb_dev, endp, usb_addr, + usb_endp, address); + spin_unlock_irqrestore(&endp->queue_lock.slock, + irqs); + if (retval) { + return retval; + } else { + u132_endp_queue_work(u132, endp, 0); + return 0; + } + } else if (u132->num_endpoints == MAX_U132_ENDPS) { + return -EINVAL; + } else + return create_endpoint_and_queue_bulk(u132, + udev, hep, urb, usb_dev, usb_addr, + usb_endp, address, mem_flags); + } else { + struct u132_endp *endp = hep->hcpriv; + u16 urb_size = 8; + u8 *b = urb->setup_packet; + int i = 0; + char data[30 *3 + 4]; + char *d = data; + int m = (sizeof(data) - 1) / 3; + int l = 0; + data[0] = 0; + while (urb_size-- > 0) { + if (i > m) { + } else if (i++ < m) { + int w = sprintf(d, " %02X", *b++); + d += w; + l += w; + } else + d += sprintf(d, " .."); + } + if (endp) { + unsigned long irqs; + int retval; + spin_lock_irqsave(&endp->queue_lock.slock, + irqs); + retval = queue_control_on_old_endpoint(u132, + hep, urb, usb_dev, endp, usb_addr, + usb_endp); + spin_unlock_irqrestore(&endp->queue_lock.slock, + irqs); + if (retval) { + return retval; + } else { + u132_endp_queue_work(u132, endp, 0); + return 0; + } + } else if (u132->num_endpoints == MAX_U132_ENDPS) { + return -EINVAL; + } else + return create_endpoint_and_queue_control(u132, + hep, urb, usb_dev, usb_addr, usb_endp, + mem_flags); + } + } +} + +static int dequeue_from_overflow_chain(struct u132 *u132, + struct u132_endp *endp, struct urb *urb) +{ + struct list_head *scan; + struct list_head *head = &endp->urb_more; + list_for_each(scan, head) { + struct u132_urbq *urbq = list_entry(scan, struct u132_urbq, + urb_more); + if (urbq->urb == urb) { + struct usb_hcd *hcd = u132_to_hcd(u132); + list_del(scan); + endp->queue_size -= 1; + urb->error_count = 0; + urb->hcpriv = NULL; + usb_hcd_giveback_urb(hcd, urb, NULL); + return 0; + } else + continue; + } + dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" + "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" + "\n", urb, endp->endp_number, endp, endp->ring->number, + endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', + endp->usb_endp, endp->usb_addr, endp->queue_size, + endp->queue_next, endp->queue_last); + return -EINVAL; +} + +static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, + struct urb *urb) +{ + unsigned long irqs; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + if (endp->queue_size == 0) { + dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" + "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, + endp->endp_number, endp, endp->ring->number, + endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', + endp->usb_endp, endp->usb_addr); + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return -EINVAL; + } + if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { + if (endp->active) { + endp->dequeueing = 1; + endp->edset_flush = 1; + u132_endp_queue_work(u132, endp, 0); + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + urb->hcpriv = NULL; + return 0; + } else { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + u132_hcd_abandon_urb(u132, endp, urb, urb->status); + return 0; + } + } else { + u16 queue_list = 0; + u16 queue_size = endp->queue_size; + u16 queue_scan = endp->queue_next; + struct urb **urb_slot = NULL; + while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { + if (urb == endp->urb_list[ENDP_QUEUE_MASK & + ++queue_scan]) { + urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & + queue_scan]; + break; + } else + continue; + } + while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { + *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & + ++queue_scan]; + urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & + queue_scan]; + } + if (urb_slot) { + struct usb_hcd *hcd = u132_to_hcd(u132); + endp->queue_size -= 1; + if (list_empty(&endp->urb_more)) { + spin_unlock_irqrestore(&endp->queue_lock.slock, + irqs); + } else { + struct list_head *next = endp->urb_more.next; + struct u132_urbq *urbq = list_entry(next, + struct u132_urbq, urb_more); + list_del(next); + *urb_slot = urbq->urb; + spin_unlock_irqrestore(&endp->queue_lock.slock, + irqs); + kfree(urbq); + } urb->error_count = 0; + urb->hcpriv = NULL; + usb_hcd_giveback_urb(hcd, urb, NULL); + return 0; + } else if (list_empty(&endp->urb_more)) { + dev_err(&u132->platform_dev->dev, "urb=%p not found in " + "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" + "=%d size=%d next=%04X last=%04X\n", urb, + endp->endp_number, endp, endp->ring->number, + endp->input ? 'I' : ' ', + endp->output ? 'O' : ' ', endp->usb_endp, + endp->usb_addr, endp->queue_size, + endp->queue_next, endp->queue_last); + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return -EINVAL; + } else { + int retval = dequeue_from_overflow_chain(u132, endp, + urb); + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return retval; + } + } +} + +static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 2) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else { + u8 usb_addr = usb_pipedevice(urb->pipe); + u8 usb_endp = usb_pipeendpoint(urb->pipe); + u8 address = u132->addr[usb_addr].address; + struct u132_udev *udev = &u132->udev[address]; + if (usb_pipein(urb->pipe)) { + u8 endp_number = udev->endp_number_in[usb_endp]; + struct u132_endp *endp = u132->endp[endp_number - 1]; + return u132_endp_urb_dequeue(u132, endp, urb); + } else { + u8 endp_number = udev->endp_number_out[usb_endp]; + struct u132_endp *endp = u132->endp[endp_number - 1]; + return u132_endp_urb_dequeue(u132, endp, urb); + } + } +} + +static void u132_endpoint_disable(struct usb_hcd *hcd, + struct usb_host_endpoint *hep) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 2) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + } else { + struct u132_endp *endp = hep->hcpriv; + if (endp) + u132_endp_put_kref(u132, endp); + } +} + +static int u132_get_frame(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else { + int frame = 0; + dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); + msleep(100); + return frame; + } +} + +static int u132_roothub_descriptor(struct u132 *u132, + struct usb_hub_descriptor *desc) +{ + int retval; + u16 temp; + u32 rh_a = -1; + u32 rh_b = -1; + retval = u132_read_pcimem(u132, roothub.a, &rh_a); + if (retval) + return retval; + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; + desc->bHubContrCurrent = 0; + desc->bNbrPorts = u132->num_ports; + temp = 1 + (u132->num_ports / 8); + desc->bDescLength = 7 + 2 *temp; + temp = 0; + if (rh_a & RH_A_NPS) + temp |= 0x0002; + if (rh_a & RH_A_PSM) + temp |= 0x0001; + if (rh_a & RH_A_NOCP) { + temp |= 0x0010; + } else if (rh_a & RH_A_OCPM) + temp |= 0x0008; + desc->wHubCharacteristics = cpu_to_le16(temp); + retval = u132_read_pcimem(u132, roothub.b, &rh_b); + if (retval) + return retval; + memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); + desc->bitmap[0] = rh_b & RH_B_DR; + if (u132->num_ports > 7) { + desc->bitmap[1] = (rh_b & RH_B_DR) >> 8; + desc->bitmap[2] = 0xff; + } else + desc->bitmap[1] = 0xff; + return 0; +} + +static int u132_roothub_status(struct u132 *u132, __le32 *desc) +{ + u32 rh_status = -1; + int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); + *desc = cpu_to_le32(rh_status); + return ret_status; +} + +static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) +{ + if (wIndex == 0 || wIndex > u132->num_ports) { + return -EINVAL; + } else { + int port = wIndex - 1; + u32 rh_portstatus = -1; + int ret_portstatus = u132_read_pcimem(u132, + roothub.portstatus[port], &rh_portstatus); + *desc = cpu_to_le32(rh_portstatus); + if (*(u16 *) (desc + 2)) { + dev_info(&u132->platform_dev->dev, "Port %d Status Chan" + "ge = %08X\n", port, *desc); + } + return ret_portstatus; + } +} + + +/* this timer value might be vendor-specific ... */ +#define PORT_RESET_HW_MSEC 10 +#define PORT_RESET_MSEC 10 +/* wrap-aware logic morphed from */ +#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) +static int u132_roothub_portreset(struct u132 *u132, int port_index) +{ + int retval; + u32 fmnumber; + u16 now; + u16 reset_done; + retval = u132_read_pcimem(u132, fmnumber, &fmnumber); + if (retval) + return retval; + now = fmnumber; + reset_done = now + PORT_RESET_MSEC; + do { + u32 portstat; + do { + retval = u132_read_pcimem(u132, + roothub.portstatus[port_index], &portstat); + if (retval) + return retval; + if (RH_PS_PRS & portstat) { + continue; + } else + break; + } while (tick_before(now, reset_done)); + if (RH_PS_PRS & portstat) + return -ENODEV; + if (RH_PS_CCS & portstat) { + if (RH_PS_PRSC & portstat) { + retval = u132_write_pcimem(u132, + roothub.portstatus[port_index], + RH_PS_PRSC); + if (retval) + return retval; + } + } else + break; /* start the next reset, + sleep till it's probably done */ + retval = u132_write_pcimem(u132, roothub.portstatus[port_index], + RH_PS_PRS); + if (retval) + return retval; + msleep(PORT_RESET_HW_MSEC); + retval = u132_read_pcimem(u132, fmnumber, &fmnumber); + if (retval) + return retval; + now = fmnumber; + } while (tick_before(now, reset_done)); + return 0; +} + +static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, + u16 wIndex) +{ + if (wIndex == 0 || wIndex > u132->num_ports) { + return -EINVAL; + } else { + int retval; + int port_index = wIndex - 1; + struct u132_port *port = &u132->port[port_index]; + port->Status &= ~(1 << wValue); + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + retval = u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PSS); + if (retval) + return retval; + return 0; + case USB_PORT_FEAT_POWER: + retval = u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PPS); + if (retval) + return retval; + return 0; + case USB_PORT_FEAT_RESET: + retval = u132_roothub_portreset(u132, port_index); + if (retval) + return retval; + return 0; + default: + return -EPIPE; + } + } +} + +static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, + u16 wIndex) +{ + if (wIndex == 0 || wIndex > u132->num_ports) { + return -EINVAL; + } else { + int port_index = wIndex - 1; + u32 temp; + int retval; + struct u132_port *port = &u132->port[port_index]; + port->Status &= ~(1 << wValue); + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + temp = RH_PS_CCS; + break; + case USB_PORT_FEAT_C_ENABLE: + temp = RH_PS_PESC; + break; + case USB_PORT_FEAT_SUSPEND: + temp = RH_PS_POCI; + if ((u132->hc_control & OHCI_CTRL_HCFS) + != OHCI_USB_OPER) { + dev_err(&u132->platform_dev->dev, "TODO resume_" + "root_hub\n"); + } + break; + case USB_PORT_FEAT_C_SUSPEND: + temp = RH_PS_PSSC; + break; + case USB_PORT_FEAT_POWER: + temp = RH_PS_LSDA; + break; + case USB_PORT_FEAT_C_CONNECTION: + temp = RH_PS_CSC; + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + temp = RH_PS_OCIC; + break; + case USB_PORT_FEAT_C_RESET: + temp = RH_PS_PRSC; + break; + default: + return -EPIPE; + } + retval = u132_write_pcimem(u132, roothub.portstatus[port_index], + temp); + if (retval) + return retval; + return 0; + } +} + + +/* the virtual root hub timer IRQ checks for hub status*/ +static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" + "ed %d\n", hcd, u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" + "ed\n", hcd); + dump_stack(); + return -ESHUTDOWN; + } else { + int i, changed = 0, length = 1; + if (u132->flags & OHCI_QUIRK_AMD756) { + if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { + dev_err(&u132->platform_dev->dev, "bogus NDP, r" + "ereads as NDP=%d\n", + u132->hc_roothub_a & RH_A_NDP); + goto done; + } + } + if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) { + buf[0] = changed = 1; + } else + buf[0] = 0; + if (u132->num_ports > 7) { + buf[1] = 0; + length++; + } + for (i = 0; i < u132->num_ports; i++) { + if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | + RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | + RH_PS_PRSC)) { + changed = 1; + if (i < 7) { + buf[0] |= 1 << (i + 1); + } else + buf[1] |= 1 << (i - 7); + continue; + } + if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) { + continue; + } + if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) { + continue; + } + } + done:return changed ? length : 0; + } +} + +static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else { + int retval = 0; + down(&u132->sw_lock); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + case C_HUB_LOCAL_POWER: + break; + default: + goto stall; + } + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + case C_HUB_LOCAL_POWER: + break; + default: + goto stall; + } + break; + case ClearPortFeature:{ + retval = u132_roothub_clearportfeature(u132, + wValue, wIndex); + if (retval) + goto error; + break; + } + case GetHubDescriptor:{ + retval = u132_roothub_descriptor(u132, + (struct usb_hub_descriptor *)buf); + if (retval) + goto error; + break; + } + case GetHubStatus:{ + retval = u132_roothub_status(u132, + (__le32 *) buf); + if (retval) + goto error; + break; + } + case GetPortStatus:{ + retval = u132_roothub_portstatus(u132, + (__le32 *) buf, wIndex); + if (retval) + goto error; + break; + } + case SetPortFeature:{ + retval = u132_roothub_setportfeature(u132, + wValue, wIndex); + if (retval) + goto error; + break; + } + default: + goto stall; + error:u132_disable(u132); + u132->going = 1; + break; + stall:retval = -EPIPE; + break; + } + up(&u132->sw_lock); + return retval; + } +} + +static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else + return 0; +} + +static void u132_hub_irq_enable(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + } else if (u132->going > 0) + dev_err(&u132->platform_dev->dev, "device is being removed\n"); +} + + +#ifdef CONFIG_PM +static int u132_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else + return 0; +} + +static int u132_hcd_resume(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else + return 0; +} + +static int u132_bus_suspend(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else + return 0; +} + +static int u132_bus_resume(struct usb_hcd *hcd) +{ + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else + return 0; +} + +#else +#define u132_hcd_suspend NULL +#define u132_hcd_resume NULL +#define u132_bus_suspend NULL +#define u132_bus_resume NULL +#endif +static struct hc_driver u132_hc_driver = { + .description = hcd_name, + .hcd_priv_size = sizeof(struct u132), + .irq = NULL, + .flags = HCD_USB11 | HCD_MEMORY, + .reset = u132_hcd_reset, + .start = u132_hcd_start, + .suspend = u132_hcd_suspend, + .resume = u132_hcd_resume, + .stop = u132_hcd_stop, + .urb_enqueue = u132_urb_enqueue, + .urb_dequeue = u132_urb_dequeue, + .endpoint_disable = u132_endpoint_disable, + .get_frame_number = u132_get_frame, + .hub_status_data = u132_hub_status_data, + .hub_control = u132_hub_control, + .bus_suspend = u132_bus_suspend, + .bus_resume = u132_bus_resume, + .start_port_reset = u132_start_port_reset, + .hub_irq_enable = u132_hub_irq_enable, +}; + +/* +* This function may be called by the USB core whilst the "usb_all_devices_rwsem" +* is held for writing, thus this module must not call usb_remove_hcd() +* synchronously - but instead should immediately stop activity to the +* device and ansynchronously call usb_remove_hcd() +*/ +static int __devexit u132_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + if (hcd) { + struct u132 *u132 = hcd_to_u132(hcd); + dump_stack(); + if (u132->going++ > 1) { + return -ENODEV; + } else { + int rings = MAX_U132_RINGS; + int endps = MAX_U132_ENDPS; + msleep(100); + down(&u132->sw_lock); + u132_monitor_cancel_work(u132); + while (rings-- > 0) { + struct u132_ring *ring = &u132->ring[rings]; + u132_ring_cancel_work(u132, ring); + } while (endps-- > 0) { + struct u132_endp *endp = u132->endp[endps]; + if (endp) + u132_endp_cancel_work(u132, endp); + } + u132->going += 1; + printk(KERN_INFO "removing device u132.%d\n", + u132->sequence_num); + up(&u132->sw_lock); + usb_remove_hcd(hcd); + u132_u132_put_kref(u132); + return 0; + } + } else + return 0; +} + +static void u132_initialise(struct u132 *u132, struct platform_device *pdev) +{ + int rings = MAX_U132_RINGS; + int ports = MAX_U132_PORTS; + int addrs = MAX_U132_ADDRS; + int udevs = MAX_U132_UDEVS; + int endps = MAX_U132_ENDPS; + u132->board = pdev->dev.platform_data; + u132->platform_dev = pdev; + u132->power = 0; + u132->reset = 0; + init_MUTEX(&u132->sw_lock); + init_MUTEX(&u132->scheduler_lock); + while (rings-- > 0) { + struct u132_ring *ring = &u132->ring[rings]; + ring->u132 = u132; + ring->number = rings + 1; + ring->length = 0; + ring->curr_endp = NULL; + INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler, + (void *)ring); + } down(&u132->sw_lock); + INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132); + while (ports-- > 0) { + struct u132_port *port = &u132->port[ports]; + port->u132 = u132; + port->reset = 0; + port->enable = 0; + port->power = 0; + port->Status = 0; + } while (addrs-- > 0) { + struct u132_addr *addr = &u132->addr[addrs]; + addr->address = 0; + } while (udevs-- > 0) { + struct u132_udev *udev = &u132->udev[udevs]; + int i = ARRAY_SIZE(udev->endp_number_in); + int o = ARRAY_SIZE(udev->endp_number_out); + udev->usb_device = NULL; + udev->udev_number = 0; + udev->usb_addr = 0; + udev->portnumber = 0; + while (i-- > 0) { + udev->endp_number_in[i] = 0; + } + while (o-- > 0) { + udev->endp_number_out[o] = 0; + } + } + while (endps-- > 0) { + u132->endp[endps] = NULL; + } + up(&u132->sw_lock); + return; +} + +static int __devinit u132_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + msleep(100); + if (u132_exiting > 0) { + return -ENODEV; + } /* refuse to confuse usbcore */ + if (pdev->dev.dma_mask) { + return -EINVAL; + } + hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + printk(KERN_ERR "failed to create the usb hcd struct for U132\n" + ); + ftdi_elan_gone_away(pdev); + return -ENOMEM; + } else { + int retval = 0; + struct u132 *u132 = hcd_to_u132(hcd); + hcd->rsrc_start = 0; + down(&u132_module_lock); + list_add_tail(&u132->u132_list, &u132_static_list); + u132->sequence_num = ++u132_instances; + up(&u132_module_lock); + u132_u132_init_kref(u132); + u132_initialise(u132, pdev); + hcd->product_desc = "ELAN U132 Host Controller"; + retval = usb_add_hcd(hcd, 0, 0); + if (retval != 0) { + dev_err(&u132->platform_dev->dev, "init error %d\n", + retval); + u132_u132_put_kref(u132); + return retval; + } else { + u132_monitor_queue_work(u132, 100); + return 0; + } + } +} + + +#ifdef CONFIG_PM +/* for this device there's no useful distinction between the controller +* and its root hub, except that the root hub only gets direct PM calls +* when CONFIG_USB_SUSPEND is enabled. +*/ +static int u132_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else { + int retval = 0; + if (state.event == PM_EVENT_FREEZE) { + retval = u132_bus_suspend(hcd); + } else if (state.event == PM_EVENT_SUSPEND) { + int ports = MAX_U132_PORTS; + while (ports-- > 0) { + port_power(u132, ports, 0); + } + } + if (retval == 0) + pdev->dev.power.power_state = state; + return retval; + } +} + +static int u132_resume(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct u132 *u132 = hcd_to_u132(hcd); + if (u132->going > 1) { + dev_err(&u132->platform_dev->dev, "device has been removed %d\n" + , u132->going); + return -ENODEV; + } else if (u132->going > 0) { + dev_err(&u132->platform_dev->dev, "device is being removed\n"); + return -ESHUTDOWN; + } else { + int retval = 0; + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { + int ports = MAX_U132_PORTS; + while (ports-- > 0) { + port_power(u132, ports, 1); + } + retval = 0; + } else { + pdev->dev.power.power_state = PMSG_ON; + retval = u132_bus_resume(hcd); + } + return retval; + } +} + +#else +#define u132_suspend NULL +#define u132_resume NULL +#endif +/* +* this driver is loaded explicitely by ftdi_u132 +* +* the platform_driver struct is static because it is per type of module +*/ +static struct platform_driver u132_platform_driver = { + .probe = u132_probe, + .remove = __devexit_p(u132_remove), + .suspend = u132_suspend, + .resume = u132_resume, + .driver = { + .name = (char *)hcd_name, + .owner = THIS_MODULE, + }, +}; +static int __init u132_hcd_init(void) +{ + int retval; + INIT_LIST_HEAD(&u132_static_list); + u132_instances = 0; + u132_exiting = 0; + init_MUTEX(&u132_module_lock); + if (usb_disabled()) + return -ENODEV; + printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__, + __DATE__); + workqueue = create_singlethread_workqueue("u132"); + retval = platform_driver_register(&u132_platform_driver); + return retval; +} + + +module_init(u132_hcd_init); +static void __exit u132_hcd_exit(void) +{ + struct u132 *u132; + struct u132 *temp; + down(&u132_module_lock); + u132_exiting += 1; + up(&u132_module_lock); + list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { + platform_device_unregister(u132->platform_dev); + } platform_driver_unregister(&u132_platform_driver); + printk(KERN_INFO "u132-hcd driver deregistered\n"); + wait_event(u132_hcd_wait, u132_instances == 0); + flush_workqueue(workqueue); + destroy_workqueue(workqueue); +} + + +module_exit(u132_hcd_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 38e2bfc94e95dd6005fdaf40dfec0157396741da Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 18 Sep 2006 22:49:02 -0700 Subject: USB: Dealias -110 code (more complete) The purpose of this patch is to split off the case when a device does not reply on the lower level (which is reported by HC hardware), and a case when the device accepted the request, but does not reply at upper level. This redefinition allows to diagnose issues easier, without asking the user if the -110 happened "immediately". The usbmon splits such cases already thanks to its timestamp, but it's not always available. I adjusted all drivers which I found affected (by searching for "urb"). Out of tree drivers may suffer a little bit, but I do not expect much breakage. At worst they may print a few messages. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/error-codes.txt | 11 ++++------- drivers/isdn/gigaset/bas-gigaset.c | 2 +- drivers/isdn/hisax/hfc_usb.h | 6 +++--- drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 1 - drivers/media/dvb/ttusb-dec/ttusb_dec.c | 2 +- drivers/media/video/ov511.c | 7 ++++--- drivers/media/video/pwc/pwc-if.c | 2 +- drivers/media/video/w9968cf.c | 7 +++---- drivers/net/irda/irda-usb.c | 18 +++++++----------- drivers/net/wireless/zd1201.c | 4 ++-- drivers/usb/host/isp116x.h | 2 +- drivers/usb/host/ohci.h | 2 +- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/input/hid-core.c | 3 ++- drivers/usb/input/itmtouch.c | 2 +- drivers/usb/input/mtouchusb.c | 2 +- drivers/usb/input/touchkitusb.c | 2 +- drivers/usb/input/usbtouchscreen.c | 2 +- drivers/usb/misc/auerswald.c | 4 ++-- drivers/usb/net/pegasus.c | 2 +- drivers/usb/net/rtl8150.c | 2 +- drivers/usb/net/usbnet.c | 12 ++++++------ drivers/usb/storage/transport.c | 5 ----- sound/usb/usbmidi.c | 6 +++--- 24 files changed, 48 insertions(+), 60 deletions(-) (limited to 'drivers/usb/host') diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt index 867f4c38f35..39c68f8c4e6 100644 --- a/Documentation/usb/error-codes.txt +++ b/Documentation/usb/error-codes.txt @@ -98,13 +98,13 @@ one or more packets could finish before an error stops further endpoint I/O. error, a failure to respond (often caused by device disconnect), or some other fault. --ETIMEDOUT (**) No response packet received within the prescribed +-ETIME (**) No response packet received within the prescribed bus turn-around time. This error may instead be reported as -EPROTO or -EILSEQ. - Note that the synchronous USB message functions - also use this code to indicate timeout expired - before the transfer completed. +-ETIMEDOUT Synchronous USB message functions use this code + to indicate timeout expired before the transfer + completed, and no other error was reported by HC. -EPIPE (**) Endpoint stalled. For non-control endpoints, reset this status with usb_clear_halt(). @@ -163,6 +163,3 @@ usb_get_*/usb_set_*(): usb_control_msg(): usb_bulk_msg(): -ETIMEDOUT Timeout expired before the transfer completed. - In the future this code may change to -ETIME, - whose definition is a closer match to this sort - of error. diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 3845defd490..5cfbe6a3801 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -192,7 +192,7 @@ static char *get_usb_statmsg(int status) return "bit stuffing error, timeout, or unknown USB error"; case -EILSEQ: return "CRC mismatch, timeout, or unknown USB error"; - case -ETIMEDOUT: + case -ETIME: return "timed out"; case -EPIPE: return "endpoint stalled"; diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h index ec52c1a7c22..6349367ed48 100644 --- a/drivers/isdn/hisax/hfc_usb.h +++ b/drivers/isdn/hisax/hfc_usb.h @@ -137,11 +137,11 @@ static struct hfcusb_symbolic_list urb_errlist[] = { {-ENXIO, "URB already queued"}, {-EFBIG, "Too much ISO frames requested"}, {-ENOSR, "Buffer error (overrun)"}, - {-EPIPE, "Specified endpoint is stalled (device not responding)"}, + {-EPIPE, "Specified endpoint is stalled"}, {-EOVERFLOW, "Babble (bad cable?)"}, {-EPROTO, "Bit-stuff error (bad cable?)"}, - {-EILSEQ, "CRC/Timeout"}, - {-ETIMEDOUT, "NAK (device does not respond)"}, + {-EILSEQ, "CRC or missing token"}, + {-ETIME, "Device did not respond"}, {-ESHUTDOWN, "Device unplugged"}, {-1, NULL} }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 9002f35aa95..88b283731bb 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -80,7 +80,6 @@ static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) switch (urb->status) { case 0: /* success */ - case -ETIMEDOUT: /* NAK */ break; case -ECONNRESET: /* kill */ case -ENOENT: diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 6c1cb770bcf..c9d663549df 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -215,7 +215,7 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - case -ETIMEDOUT: + case -ETIME: /* this urb is dead, cleanup */ dprintk("%s:urb shutting down with status: %d\n", __FUNCTION__, urb->status); diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 1b07a61c2eb..5d8cd283fcd 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -301,10 +301,11 @@ static struct symbolic_list senlist[] = { static struct symbolic_list urb_errlist[] = { { -ENOSR, "Buffer error (overrun)" }, { -EPIPE, "Stalled (device not responding)" }, - { -EOVERFLOW, "Babble (bad cable?)" }, + { -EOVERFLOW, "Babble (device sends too much data)" }, { -EPROTO, "Bit-stuff error (bad cable?)" }, - { -EILSEQ, "CRC/Timeout" }, - { -ETIMEDOUT, "NAK (device does not respond)" }, + { -EILSEQ, "CRC/Timeout (bad cable?)" }, + { -ETIME, "Device does not respond to token" }, + { -ETIMEDOUT, "Device does not respond to command" }, { -1, NULL } }; diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index d4703944df9..53c4b5790d5 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -711,7 +711,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; - case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; + case -ETIME: errmsg = "Device does not respond"; break; } PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); /* Give up after a number of contiguous errors on the USB bus. diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 20f211b55ad..2912326a5ae 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -586,15 +586,14 @@ static struct w9968cf_symbolic_list urb_errlist[] = { { -EFBIG, "Too much ISO frames requested" }, { -ENOSR, "Buffer error (overrun)" }, { -EPIPE, "Specified endpoint is stalled (device not responding)"}, - { -EOVERFLOW, "Babble (bad cable?)" }, + { -EOVERFLOW, "Babble (too much data)" }, { -EPROTO, "Bit-stuff error (bad cable?)" }, { -EILSEQ, "CRC/Timeout" }, - { -ETIMEDOUT, "NAK (device does not respond)" }, + { -ETIME, "Device does not respond to token" }, + { -ETIMEDOUT, "Device does not respond to command" }, { -1, NULL } }; - - /**************************************************************************** * Memory management functions * ****************************************************************************/ diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 2a0d538b387..383cef1f599 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -671,10 +671,8 @@ static void irda_usb_net_timeout(struct net_device *netdev) * Jean II */ done = 1; break; - case -ECONNABORTED: /* -103 */ - case -ECONNRESET: /* -104 */ - case -ETIMEDOUT: /* -110 */ - case -ENOENT: /* -2 (urb unlinked by us) */ + case -ECONNRESET: + case -ENOENT: /* urb unlinked by us */ default: /* ??? - Play safe */ urb->status = 0; netif_wake_queue(self->netdev); @@ -712,10 +710,8 @@ static void irda_usb_net_timeout(struct net_device *netdev) * Jean II */ done = 1; break; - case -ECONNABORTED: /* -103 */ - case -ECONNRESET: /* -104 */ - case -ETIMEDOUT: /* -110 */ - case -ENOENT: /* -2 (urb unlinked by us) */ + case -ECONNRESET: + case -ENOENT: /* urb unlinked by us */ default: /* ??? - Play safe */ if(skb != NULL) { dev_kfree_skb_any(skb); @@ -845,14 +841,14 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) self->stats.rx_crc_errors++; /* Also precursor to a hot-unplug on UHCI. */ /* Fallthrough... */ - case -ECONNRESET: /* -104 */ + case -ECONNRESET: /* Random error, if I remember correctly */ /* uhci_cleanup_unlink() is going to kill the Rx * URB just after we return. No problem, at this * point the URB will be idle ;-) - Jean II */ - case -ESHUTDOWN: /* -108 */ + case -ESHUTDOWN: /* That's usually a hot-unplug. Submit will fail... */ - case -ETIMEDOUT: /* -110 */ + case -ETIME: /* Usually precursor to a hot-unplug on OHCI. */ default: self->stats.rx_errors++; diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index c52e9bcf8d0..f50ec10675d 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -119,7 +119,7 @@ static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs) switch(urb->status) { case -EILSEQ: case -ENODEV: - case -ETIMEDOUT: + case -ETIME: case -ENOENT: case -EPIPE: case -EOVERFLOW: @@ -201,7 +201,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) switch(urb->status) { case -EILSEQ: case -ENODEV: - case -ETIMEDOUT: + case -ETIME: case -ENOENT: case -EPIPE: case -EOVERFLOW: diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index a1b7c3813d3..b91e2edd9c5 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -233,7 +233,7 @@ static const int cc_to_error[16] = { /* Bit Stuff */ -EPROTO, /* Data Togg */ -EILSEQ, /* Stall */ -EPIPE, - /* DevNotResp */ -ETIMEDOUT, + /* DevNotResp */ -ETIME, /* PIDCheck */ -EPROTO, /* UnExpPID */ -EPROTO, /* DataOver */ -EOVERFLOW, diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 650d1bf21c1..93fdc3c3534 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -159,7 +159,7 @@ static const int cc_to_error [16] = { /* Bit Stuff */ -EPROTO, /* Data Togg */ -EILSEQ, /* Stall */ -EPIPE, - /* DevNotResp */ -ETIMEDOUT, + /* DevNotResp */ -ETIME, /* PIDCheck */ -EPROTO, /* UnExpPID */ -EPROTO, /* DataOver */ -EOVERFLOW, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 8c17da37600..3a586aab393 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -597,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs) /* error? retry, until "3 strikes" */ } else if (++ep->error_count >= 3) { if (status & SL11H_STATMASK_TMOUT) - urbstat = -ETIMEDOUT; + urbstat = -ETIME; else if (status & SL11H_STATMASK_OVF) urbstat = -EOVERFLOW; else diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index fc5b662ea17..2a3e9e9b4b3 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1023,7 +1023,8 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) return; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ - case -ETIMEDOUT: /* NAK */ + case -ETIME: /* protocol error or unplug */ + case -ETIMEDOUT: /* Should never happen, but... */ clear_bit(HID_IN_RUNNING, &hid->iofl); hid_io_error(hid); return; diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 86acb5f1907..61966d719ca 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -87,7 +87,7 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) case 0: /* success */ break; - case -ETIMEDOUT: + case -ETIME: /* this urb is timing out */ dbg("%s - urb timed out - was the device unplugged?", __FUNCTION__); diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index a9ccda8810e..5dce951f275 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -107,7 +107,7 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) case 0: /* success */ break; - case -ETIMEDOUT: + case -ETIME: /* this urb is timing out */ dbg("%s - urb timed out - was the device unplugged?", __FUNCTION__); diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 0149043ffb9..30b9f820e7a 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -201,7 +201,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs) case 0: /* success */ break; - case -ETIMEDOUT: + case -ETIME: /* this urb is timing out */ dbg("%s - urb timed out - was the device unplugged?", __FUNCTION__); diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index a1be7840ea0..4640d1000d8 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -508,7 +508,7 @@ static void usbtouch_irq(struct urb *urb, struct pt_regs *regs) case 0: /* success */ break; - case -ETIMEDOUT: + case -ETIME: /* this urb is timing out */ dbg("%s - urb timed out - was the device unplugged?", __FUNCTION__); diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 4a329d8488b..4fd2110b341 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -806,7 +806,7 @@ static void auerbuf_releasebuf( pauerbuf_t bp) 0 Initial, OK -EINPROGRESS during submission until end -ENOENT if urb is unlinked --ETIMEDOUT Transfer timed out, NAK +-ETIME Device did not respond -ENOMEM Memory Overflow -ENODEV Specified USB-device or bus doesn't exist -ENXIO URB already queued @@ -832,7 +832,7 @@ static int auerswald_status_retry (int status) { switch (status) { case 0: - case -ETIMEDOUT: + case -ETIME: case -EOVERFLOW: case -EAGAIN: case -EPIPE: diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index ab21f960d25..b8e25af13f0 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -619,7 +619,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: break; - case -ETIMEDOUT: + case -ETIME: if (netif_msg_rx_err(pegasus)) pr_debug("%s: reset MAC\n", net->name); pegasus->flags &= ~PEGASUS_RX_BUSY; diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index a72685b9606..2364c209938 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -438,7 +438,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) break; case -ENOENT: return; /* the urb is in unlink state */ - case -ETIMEDOUT: + case -ETIME: warn("may be reset is needed?.."); goto goon; default: diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 8e8e74d4053..98a522f1e26 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -425,9 +425,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) // we get controller i/o faults during khubd disconnect() delays. // throttle down resubmits, to avoid log floods; just temporarily, // so we still recover when the fault isn't a khubd delay. - case -EPROTO: // ehci - case -ETIMEDOUT: // ohci - case -EILSEQ: // uhci + case -EPROTO: + case -ETIME: + case -EILSEQ: dev->stats.rx_errors++; if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); @@ -821,9 +821,9 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs) // like rx, tx gets controller i/o faults during khubd delays // and so it uses the same throttling mechanism. - case -EPROTO: // ehci - case -ETIMEDOUT: // ohci - case -EILSEQ: // uhci + case -EPROTO: + case -ETIME: + case -EILSEQ: if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index d6acc92a4ae..f23514c4e64 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -294,11 +294,6 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; - /* timeout or excessively long NAK */ - case -ETIMEDOUT: - US_DEBUGP("-- timeout or NAK\n"); - return USB_STOR_XFER_ERROR; - /* babble - the device tried to send more than we wanted to read */ case -EOVERFLOW: US_DEBUGP("-- babble\n"); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5105b6b0574..abe29dadd97 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -181,9 +181,9 @@ static int snd_usbmidi_urb_error(int status) case -ENODEV: return -ENODEV; /* errors that might occur during unplugging */ - case -EPROTO: /* EHCI */ - case -ETIMEDOUT: /* OHCI */ - case -EILSEQ: /* UHCI */ + case -EPROTO: + case -ETIME: + case -EILSEQ: return -EIO; default: snd_printk(KERN_ERR "urb status %d\n", status); -- cgit v1.2.3-70-g09d2 From 71795c1df30b034414c921b4930ed88de34ca348 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 18 Sep 2006 22:57:22 -0700 Subject: USB: ohci_usb can oops on shutdown When ohci-hcd is shutting down (for rmmod or PC-card removal), there is a window when the device is shut down, HC communication area (->hcca) is freed, but the core has not called "free_irq" yet. If another device triggers a shared interrupt in this window, we oops when trying to access the freed ->hcca. This patch removes the window by calling free_irq before ->hcca is freed. The patch is tested at the PC hotplug test rig at Stratus, and with rmmod by Rafael Wysocki. Signed-off-by: Pete Zaitcev Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2c614af8f73..1027aa04583 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -795,7 +795,9 @@ static void ohci_stop (struct usb_hcd *hcd) ohci_usb_reset (ohci); ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - + free_irq(hcd->irq, hcd); + hcd->irq = -1; + remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { -- cgit v1.2.3-70-g09d2 From 26f953fd884ea4879585287917f855c63c6b2666 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 18 Sep 2006 17:03:16 -0700 Subject: USB: EHCI update VIA workaround This revamps handling of the hardware "async advance" IRQ, and its watchdog timer. Basically it dis-entangles that important timeout from the others, simplifying the associated state and code to make it more robust. This reportedly improves behavior of EHCI on some systems with VIA chips, and AFAIK won't affect non-VIA hardware. VIA systems need this code to recover from silcon bugs whereby the "async advance" IRQ isn't issued. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 4 +-- drivers/usb/host/ehci-hcd.c | 73 +++++++++++++++++++++++++++++++-------------- drivers/usb/host/ehci-hub.c | 2 +- drivers/usb/host/ehci-pci.c | 2 +- drivers/usb/host/ehci-q.c | 6 ++-- drivers/usb/host/ehci.h | 22 +++++++++----- 6 files changed, 70 insertions(+), 39 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 34b7a31cd85..23b95b2bfe1 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -754,9 +754,7 @@ show_registers (struct class_device *class_dev, char *buf) } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p%s\n", - ehci->reclaim, - ehci->reclaim_ready ? " ready" : ""); + temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 4e1a8c30889..5ac91859113 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ +#define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -254,6 +254,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ +static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs); static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); #include "ehci-hub.c" @@ -263,28 +264,39 @@ static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); /*-------------------------------------------------------------------------*/ -static void ehci_watchdog (unsigned long param) +static void ehci_iaa_watchdog (unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; + u32 status; spin_lock_irqsave (&ehci->lock, flags); + WARN_ON(!ehci->reclaim); - /* lost IAA irqs wedge things badly; seen with a vt8235 */ + /* lost IAA irqs wedge things badly; seen first with a vt8235 */ if (ehci->reclaim) { - u32 status = readl (&ehci->regs->status); - + status = readl (&ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); writel (STS_IAA, &ehci->regs->status); - ehci->reclaim_ready = 1; + end_unlink_async (ehci, NULL); } } - /* stop async processing after it's idled a bit */ + spin_unlock_irqrestore (&ehci->lock, flags); +} + +static void ehci_watchdog (unsigned long param) +{ + struct ehci_hcd *ehci = (struct ehci_hcd *) param; + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); + + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) - start_unlink_async (ehci, ehci->async); + start_unlink_async (ehci, ehci->async); /* ehci could run by timer, without IRQs ... */ ehci_work (ehci, NULL); @@ -333,8 +345,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) { timer_action_done (ehci, TIMER_IO_WATCHDOG); - if (ehci->reclaim_ready) - end_unlink_async (ehci, regs); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -369,6 +379,7 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); + del_timer_sync (&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -415,6 +426,10 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; + init_timer(&ehci->iaa_watchdog); + ehci->iaa_watchdog.function = ehci_iaa_watchdog; + ehci->iaa_watchdog.data = (unsigned long) ehci; + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -431,7 +446,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; - ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -605,7 +619,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - ehci->reclaim_ready = 1; + end_unlink_async (ehci, regs); bh = 1; } @@ -709,10 +723,14 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - /* if we need to use IAA and it's busy, defer */ - if (qh->qh_state == QH_STATE_LINKED - && ehci->reclaim - && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { + // BUG_ON(qh->qh_state != QH_STATE_LINKED); + + /* failfast */ + if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) + end_unlink_async (ehci, NULL); + + /* defer till later if busy */ + else if (ehci->reclaim) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -722,12 +740,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* bypass IAA if the hc can't care */ - } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) - end_unlink_async (ehci, NULL); - - /* something else might have unlinked the qh by now */ - if (qh->qh_state == QH_STATE_LINKED) + /* start IAA cycle */ + } else start_unlink_async (ehci, qh); } @@ -749,7 +763,19 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - unlink_async (ehci, qh); + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + unlink_async (ehci, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + WARN_ON(1); + break; + } break; case PIPE_INTERRUPT: @@ -841,6 +867,7 @@ rescan: unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index a5eeb9cd6ab..b2ee13c5851 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = readl (&ehci->regs->command); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async (ehci, NULL); ehci_work(ehci, NULL); /* suspend any active/unsuspended ports, maybe allow wakeup */ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index e6a3bcddd55..08d0472d4f5 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -303,7 +303,7 @@ restart: /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async (ehci, NULL); ehci_work(ehci, NULL); spin_unlock_irq(&ehci->lock); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index c0da40bbfa3..7fc25b6bd7d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - timer_action_done (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_done (ehci); // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -977,7 +977,6 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; - ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh, regs); @@ -1052,11 +1051,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } - ehci->reclaim_ready = 0; cmd |= CMD_IAAD; writel (cmd, &ehci->regs->command); (void) readl (&ehci->regs->command); - timer_action (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_start (ehci); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bbc3082a73d..6aac39f50e0 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -58,7 +58,6 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -81,6 +80,7 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ + struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -114,9 +114,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) } +static inline void +iaa_watchdog_start (struct ehci_hcd *ehci) +{ + WARN_ON(timer_pending(&ehci->iaa_watchdog)); + mod_timer (&ehci->iaa_watchdog, + jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); +} + +static inline void iaa_watchdog_done (struct ehci_hcd *ehci) +{ + del_timer (&ehci->iaa_watchdog); +} + enum ehci_timer_action { TIMER_IO_WATCHDOG, - TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -134,9 +146,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) unsigned long t; switch (action) { - case TIMER_IAA_WATCHDOG: - t = EHCI_IAA_JIFFIES; - break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -153,8 +162,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (action != TIMER_IAA_WATCHDOG - && t > ehci->watchdog.expires + if (time_before_eq(t, ehci->watchdog.expires) && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); -- cgit v1.2.3-70-g09d2 From 2e3a43f0b6f16705ec76d3744b82a116965ebebe Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 27 Sep 2006 15:43:22 -0700 Subject: ohci: Use ref-counting hotplug safe interfaces We want to avoid legacy APIs like pci_find_slot(). Signed-off-by: Alan Cox Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 3732db7d68e..87441855278 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -73,13 +73,14 @@ ohci_pci_start (struct usb_hcd *hcd) else if (pdev->vendor == PCI_VENDOR_ID_NS) { struct pci_dev *b; - b = pci_find_slot (pdev->bus->number, + b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO && b->vendor == PCI_VENDOR_ID_NS) { ohci->flags |= OHCI_QUIRK_SUPERIO; ohci_dbg (ohci, "Using NSC SuperIO setup\n"); } + pci_dev_put(b); } /* Check for Compaq's ZFMicro chipset, which needs short -- cgit v1.2.3-70-g09d2 From 1f7e1a3b7e05c833229c4b6e9d3c96262df59e99 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Sep 2006 15:41:21 -0400 Subject: OHCI: remove existing autosuspend code The autosuspend technique used by ohci-hcd doesn't mesh well with the newer USB core autosuspend code. This patch (as789) removes ohci-hcd's autosuspend support. Now the driver will be usable, but it won't automatically go into a low-power state when no devices are connected. That's for a later patch. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 50 ++++++--------------------------------------- 1 file changed, 6 insertions(+), 44 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 0b899339cac..ef4965450de 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -41,6 +41,7 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); + hcd->poll_rh = 0; ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); } @@ -117,8 +118,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) /* maybe resume can wake root hub */ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) ohci->hc_control |= OHCI_CTRL_RWE; - else + else { + ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); ohci->hc_control &= ~OHCI_CTRL_RWE; + } /* Suspend hub ... this is the "global (to this bus) suspend" mode, * which doesn't imply ports will first be individually suspended. @@ -310,20 +313,16 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; - int can_suspend; unsigned long flags; - can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); spin_lock_irqsave (&ohci->lock, flags); /* handle autosuspended root: finish resuming before * letting khubd or root hub timer see state changes. */ if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER - || !HC_IS_RUNNING(hcd->state))) { - can_suspend = 0; + || !HC_IS_RUNNING(hcd->state))) goto done; - } /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) @@ -348,10 +347,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); - /* can't autosuspend with active ports */ - if ((status & RH_PS_PES) && !(status & RH_PS_PSS)) - can_suspend = 0; - if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; @@ -366,42 +361,12 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) /* after root hub changes, stop polling after debouncing * for a while and maybe kicking in autosuspend */ - if (changed) { + if (changed) ohci->next_statechange = jiffies + STATECHANGE_DELAY; - can_suspend = 0; - } else if (time_before (jiffies, ohci->next_statechange)) { - can_suspend = 0; - } else { -#ifdef CONFIG_PM - can_suspend = can_suspend - && !ohci->ed_rm_list - && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) - & ohci->hc_control) - == OHCI_USB_OPER; -#endif - if (hcd->uses_new_polling) { - hcd->poll_rh = 0; - /* use INTR_RHSC iff INTR_RD won't apply */ - if (!can_suspend) - ohci_writel (ohci, OHCI_INTR_RHSC, - &ohci->regs->intrenable); - } - } done: spin_unlock_irqrestore (&ohci->lock, flags); -#ifdef CONFIG_PM - /* save power by autosuspending idle root hubs; - * INTR_RD wakes us when there's work - */ - if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) { - ohci_vdbg (ohci, "autosuspend\n"); - (void) ohci_bus_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); - } -#endif - return changed ? length : 0; } @@ -572,9 +537,6 @@ static int ohci_hub_control ( break; case USB_PORT_FEAT_SUSPEND: temp = RH_PS_POCI; - if ((ohci->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) - usb_hcd_resume_root_hub(hcd); break; case USB_PORT_FEAT_C_SUSPEND: temp = RH_PS_PSSC; -- cgit v1.2.3-70-g09d2 From 8d1a243ba5dda5c1a3cca5df8fb19ab8b138f074 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 26 Sep 2006 14:46:16 -0400 Subject: OHCI: add auto-stop support This patch (as790b) adds "autostop" support to ohci-hcd: the driver will automatically stop the host controller when no devices have been connected for at least one second. This feature is useful when the USB autosuspend facility isn't available, such as when CONFIG_USB_SUSPEND hasn't been set. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 18 ++-- drivers/usb/host/ohci-hub.c | 229 ++++++++++++++++++++++++++++++-------------- drivers/usb/host/ohci.h | 1 + 3 files changed, 164 insertions(+), 84 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1027aa04583..d1d68c40225 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -715,17 +715,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) return IRQ_NOTMINE; } - /* NOTE: vendors didn't always make the same implementation - * choices for RHSC. Sometimes it triggers on an edge (like - * setting and maybe clearing a port status change bit); and - * it's level-triggered on other silicon, active until khubd - * clears all active port status change bits. Poll by timer - * til it's fully debounced and the difference won't matter. - */ if (ints & OHCI_INTR_RHSC) { ohci_vdbg (ohci, "rhsc\n"); - ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrdisable); - hcd->poll_rh = 1; ohci->next_statechange = jiffies + STATECHANGE_DELAY; ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); usb_hcd_poll_rh_status(hcd); @@ -743,13 +734,18 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) if (ints & OHCI_INTR_RD) { ohci_vdbg (ohci, "resume detect\n"); ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); - if (hcd->state != HC_STATE_QUIESCING) + hcd->poll_rh = 1; + if (ohci->autostop) { + spin_lock (&ohci->lock); + ohci_rh_resume (ohci); + spin_unlock (&ohci->lock); + } else usb_hcd_resume_root_hub(hcd); } if (ints & OHCI_INTR_WDH) { if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); spin_lock (&ohci->lock); dl_done_list (ohci, ptregs); spin_unlock (&ohci->lock); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ef4965450de..f36cbd02736 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -41,31 +41,20 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - hcd->poll_rh = 0; ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); } -#ifdef CONFIG_PM - #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) static void dl_done_list (struct ohci_hcd *, struct pt_regs *); static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); -static int ohci_restart (struct ohci_hcd *ohci); -static int ohci_bus_suspend (struct usb_hcd *hcd) +static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) +__releases(ohci->lock) +__acquires(ohci->lock) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; - unsigned long flags; - - spin_lock_irqsave (&ohci->lock, flags); - - if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { - spin_unlock_irqrestore (&ohci->lock, flags); - return -ESHUTDOWN; - } ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { @@ -81,15 +70,16 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: - ohci_dbg (ohci, "already suspended\n"); - goto done; + if (!ohci->autostop) { + ohci_dbg (ohci, "already suspended\n"); + goto done; + } } - ohci_dbg (ohci, "suspend root hub\n"); + ohci_dbg (ohci, "%s root hub\n", + autostop ? "auto-stop" : "suspend"); /* First stop any processing */ - if (ohci->hc_control & OHCI_SCHED_ENABLES) { - int limit; - + if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) { ohci->hc_control &= ~OHCI_SCHED_ENABLES; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); @@ -99,24 +89,17 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); - limit = 2000; - while (limit > 0) { - udelay (250); - limit =- 250; - if (ohci_readl (ohci, &ohci->regs->intrstatus) - & OHCI_INTR_SF) - break; - } - dl_done_list (ohci, NULL); - mdelay (7); + ohci->autostop = 0; + spin_unlock_irq (&ohci->lock); + msleep (8); + spin_lock_irq (&ohci->lock); } dl_done_list (ohci, NULL); finish_unlinks (ohci, ohci_frame_no(ohci), NULL); - ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), - &ohci->regs->intrstatus); /* maybe resume can wake root hub */ - if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) + if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) || + autostop) ohci->hc_control |= OHCI_CTRL_RWE; else { ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); @@ -132,13 +115,12 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); /* no resumes until devices finish suspending */ - ohci->next_statechange = jiffies + msecs_to_jiffies (5); - - /* no timer polling */ - hcd->poll_rh = 0; + if (!autostop) { + ohci->next_statechange = jiffies + msecs_to_jiffies (5); + ohci->autostop = 0; + } done: - spin_unlock_irqrestore (&ohci->lock, flags); return status; } @@ -151,24 +133,16 @@ static inline struct ed *find_head (struct ed *ed) } /* caller has locked the root hub */ -static int ohci_bus_resume (struct usb_hcd *hcd) +static int ohci_rh_resume (struct ohci_hcd *ohci) +__releases(ohci->lock) +__acquires(ohci->lock) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct usb_hcd *hcd = ohci_to_hcd (ohci); u32 temp, enables; int status = -EINPROGRESS; - unsigned long flags; - - if (time_before (jiffies, ohci->next_statechange)) - msleep(5); - - spin_lock_irqsave (&ohci->lock, flags); - - if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { - spin_unlock_irqrestore (&ohci->lock, flags); - return -ESHUTDOWN; - } - + int autostopped = ohci->autostop; + ohci->autostop = 0; ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { @@ -188,7 +162,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ohci->hc_control |= OHCI_USB_RESUME; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); - ohci_dbg (ohci, "resume root hub\n"); + ohci_dbg (ohci, "%s root hub\n", + autostopped ? "auto-start" : "resume"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ @@ -203,16 +178,26 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } - spin_unlock_irqrestore (&ohci->lock, flags); +#ifdef CONFIG_PM if (status == -EBUSY) { - (void) ohci_init (ohci); - return ohci_restart (ohci); + if (!autostopped) { + static int ohci_restart (struct ohci_hcd *ohci); + + spin_unlock_irq (&ohci->lock); + (void) ohci_init (ohci); + status = ohci_restart (ohci); + spin_lock_irq (&ohci->lock); + } + return status; } +#endif if (status != -EINPROGRESS) return status; + if (autostopped) + goto skip_resume; + spin_unlock_irq (&ohci->lock); temp = ohci->num_ports; - enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, &ohci->regs->roothub.portstatus [temp]); @@ -245,17 +230,21 @@ static int ohci_bus_resume (struct usb_hcd *hcd) /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); + /* the following code is executed with ohci->lock held and + * irqs disabled if and only if autostopped is true + */ + +skip_resume: /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); - ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), - &ohci->regs->intrstatus); /* Then re-enable operations */ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); - msleep (3); + if (!autostopped) + msleep (3); temp = ohci->hc_control; temp &= OHCI_CTRL_RWC; @@ -265,7 +254,11 @@ static int ohci_bus_resume (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); /* TRSMRCY */ - msleep (10); + if (!autostopped) { + msleep (10); + spin_lock_irq (&ohci->lock); + } + /* now ohci->lock is always held and irqs are always disabled */ /* keep it alive for more than ~5x suspend + resume costs */ ohci->next_statechange = jiffies + STATECHANGE_DELAY; @@ -302,6 +295,45 @@ static int ohci_bus_resume (struct usb_hcd *hcd) return 0; } +#ifdef CONFIG_PM + +static int ohci_bus_suspend (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int rc; + + spin_lock_irq (&ohci->lock); + + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) + rc = -ESHUTDOWN; + else + rc = ohci_rh_suspend (ohci, 0); + spin_unlock_irq (&ohci->lock); + return rc; +} + +static int ohci_bus_resume (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int rc; + + if (time_before (jiffies, ohci->next_statechange)) + msleep(5); + + spin_lock_irq (&ohci->lock); + + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) + rc = -ESHUTDOWN; + else + rc = ohci_rh_resume (ohci); + spin_unlock_irq (&ohci->lock); + + /* poll until we know a device is connected or we autostop */ + if (rc == 0) + usb_hcd_poll_rh_status(hcd); + return rc; +} + #endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -313,17 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; + int any_connected = 0, rhsc_enabled = 1; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); - /* handle autosuspended root: finish resuming before - * letting khubd or root hub timer see state changes. - */ - if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER - || !HC_IS_RUNNING(hcd->state))) - goto done; - /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { @@ -347,6 +373,9 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); + /* can't autostop if ports are connected */ + any_connected |= (status & RH_PS_CCS); + if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; @@ -354,15 +383,69 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); - continue; } } - /* after root hub changes, stop polling after debouncing - * for a while and maybe kicking in autosuspend + /* NOTE: vendors didn't always make the same implementation + * choices for RHSC. Sometimes it triggers on an edge (like + * setting and maybe clearing a port status change bit); and + * it's level-triggered on other silicon, active until khubd + * clears all active port status change bits. If it's still + * set (level-triggered) we must disable it and rely on + * polling until khubd re-enables it. */ - if (changed) - ohci->next_statechange = jiffies + STATECHANGE_DELAY; + if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { + ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); + (void) ohci_readl (ohci, &ohci->regs->intrdisable); + rhsc_enabled = 0; + } + hcd->poll_rh = 1; + + /* carry out appropriate state changes */ + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + + case OHCI_USB_OPER: + /* keep on polling until we know a device is connected + * and RHSC is enabled */ + if (!ohci->autostop) { + if (any_connected) { + if (rhsc_enabled) + hcd->poll_rh = 0; + } else { + ohci->autostop = 1; + ohci->next_statechange = jiffies + HZ; + } + + /* if no devices have been attached for one second, autostop */ + } else { + if (changed || any_connected) { + ohci->autostop = 0; + ohci->next_statechange = jiffies + + STATECHANGE_DELAY; + } else if (time_after_eq (jiffies, + ohci->next_statechange) + && !ohci->ed_rm_list + && !(ohci->hc_control & + OHCI_SCHED_ENABLES)) { + ohci_rh_suspend (ohci, 1); + } + } + break; + + /* if there is a port change, autostart or ask to be resumed */ + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + if (changed) { + if (ohci->autostop) + ohci_rh_resume (ohci); + else + usb_hcd_resume_root_hub (hcd); + } else { + /* everything is idle, no need for polling */ + hcd->poll_rh = 0; + } + break; + } done: spin_unlock_irqrestore (&ohci->lock, flags); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 93fdc3c3534..a2f42a2f47c 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -388,6 +388,7 @@ struct ohci_hcd { u32 hc_control; /* copy of hc control reg */ unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ + unsigned autostop:1; /* rh auto stopping/stopped */ unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ -- cgit v1.2.3-70-g09d2 From 6e3ce3ae8e872f2d3a30f5ce5bc3b7c5eeca4343 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 28 Sep 2006 17:06:45 -0700 Subject: USB: fix build error in ohci driver Thanks to Andrew for the original patch for this. I need to upgrade my version of gcc to catch these things... Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index f36cbd02736..ec75774abea 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -132,6 +132,8 @@ static inline struct ed *find_head (struct ed *ed) return ed; } +static int ohci_restart (struct ohci_hcd *ohci); + /* caller has locked the root hub */ static int ohci_rh_resume (struct ohci_hcd *ohci) __releases(ohci->lock) @@ -181,8 +183,6 @@ __acquires(ohci->lock) #ifdef CONFIG_PM if (status == -EBUSY) { if (!autostopped) { - static int ohci_restart (struct ohci_hcd *ohci); - spin_unlock_irq (&ohci->lock); (void) ohci_init (ohci); status = ohci_restart (ohci); -- cgit v1.2.3-70-g09d2