Commit a4aa0f08 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-isdn.bkbits.net/linux-2.5.make

into home.transmeta.com:/home/torvalds/v2.5/linux
parents b28ae717 0bcf1924
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mm.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -18,5 +18,5 @@ extern void device_remove_dir(struct device * dev); ...@@ -18,5 +18,5 @@ extern void device_remove_dir(struct device * dev);
extern int device_bus_link(struct device * dev); extern int device_bus_link(struct device * dev);
extern int driver_bind(struct device_driver * drv); extern int driver_attach(struct device_driver * drv);
extern void driver_unbind(struct device_driver * drv); extern void driver_detach(struct device_driver * drv);
...@@ -167,12 +167,13 @@ static int bus_make_dir(struct bus_type * bus) ...@@ -167,12 +167,13 @@ static int bus_make_dir(struct bus_type * bus)
int bus_register(struct bus_type * bus) int bus_register(struct bus_type * bus)
{ {
spin_lock(&device_lock);
rwlock_init(&bus->lock); rwlock_init(&bus->lock);
INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers); INIT_LIST_HEAD(&bus->drivers);
list_add_tail(&bus->node,&bus_driver_list);
atomic_set(&bus->refcount,2); atomic_set(&bus->refcount,2);
spin_lock(&device_lock);
list_add_tail(&bus->node,&bus_driver_list);
spin_unlock(&device_lock); spin_unlock(&device_lock);
pr_debug("bus type '%s' registered\n",bus->name); pr_debug("bus type '%s' registered\n",bus->name);
......
...@@ -31,7 +31,7 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED; ...@@ -31,7 +31,7 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
* @dev: device * @dev: device
* @drv: driver * @drv: driver
* *
* We're here because the bus's bind callback returned success for this * We're here because the bus's match callback returned success for this
* pair. We call the driver's probe callback to verify they're really a * pair. We call the driver's probe callback to verify they're really a
* match made in heaven. * match made in heaven.
* *
...@@ -67,60 +67,74 @@ static int found_match(struct device * dev, struct device_driver * drv) ...@@ -67,60 +67,74 @@ static int found_match(struct device * dev, struct device_driver * drv)
} }
/** /**
* bind_device - try to associated device with a driver * device_attach - try to associated device with a driver
* @drv: current driver to try * @drv: current driver to try
* @data: device in disguise * @data: device in disguise
* *
* This function is used as a callback to bus_for_each_drv. * This function is used as a callback to bus_for_each_drv.
* It calls the bus's ::bind callback to check if the driver supports * It calls the bus's match callback to check if the driver supports
* the device. If so, it calls the found_match() function above to * the device. If so, it calls the found_match() function above to
* take care of all the details. * take care of all the details.
*/ */
static int do_device_bind(struct device_driver * drv, void * data) static int do_device_attach(struct device_driver * drv, void * data)
{ {
struct device * dev = (struct device *)data; struct device * dev = (struct device *)data;
int error = 0; int error = 0;
if (!dev->driver) { if (!dev->driver) {
if (drv->bus->bind && drv->bus->bind(dev,drv)) if (drv->bus->match && drv->bus->match(dev,drv))
error = found_match(dev,drv); error = found_match(dev,drv);
} }
return error; return error;
} }
static int device_bind(struct device * dev) static int device_attach(struct device * dev)
{ {
int error = 0; int error = 0;
if (dev->bus) if (dev->bus)
error = bus_for_each_drv(dev->bus,dev,do_device_bind); error = bus_for_each_drv(dev->bus,dev,do_device_attach);
return error; return error;
} }
static void device_unbind(struct device * dev) static void device_detach(struct device * dev)
{ {
/* unbind from driver */ struct device_driver * drv;
if (dev->driver && dev->driver->remove)
dev->driver->remove(dev); if (dev->driver) {
lock_device(dev);
drv = dev->driver;
dev->driver = NULL;
unlock_device(dev);
write_lock(&drv->lock);
list_del_init(&dev->driver_list);
write_unlock(&drv->lock);
/* detach from driver */
if (drv->remove)
drv->remove(dev);
put_driver(drv);
}
} }
static int do_driver_bind(struct device * dev, void * data) static int do_driver_attach(struct device * dev, void * data)
{ {
struct device_driver * drv = (struct device_driver *)data; struct device_driver * drv = (struct device_driver *)data;
int error = 0; int error = 0;
if (!dev->driver) { if (!dev->driver) {
if (dev->bus->bind && dev->bus->bind(dev,drv)) if (dev->bus->match && dev->bus->match(dev,drv))
error = found_match(dev,drv); error = found_match(dev,drv);
} }
return error; return error;
} }
int driver_bind(struct device_driver * drv) int driver_attach(struct device_driver * drv)
{ {
return bus_for_each_dev(drv->bus,drv,do_driver_bind); return bus_for_each_dev(drv->bus,drv,do_driver_attach);
} }
static int do_driver_unbind(struct device * dev, struct device_driver * drv) static int do_driver_detach(struct device * dev, struct device_driver * drv)
{ {
lock_device(dev); lock_device(dev);
if (dev->driver == drv) { if (dev->driver == drv) {
...@@ -133,31 +147,32 @@ static int do_driver_unbind(struct device * dev, struct device_driver * drv) ...@@ -133,31 +147,32 @@ static int do_driver_unbind(struct device * dev, struct device_driver * drv)
return 0; return 0;
} }
void driver_unbind(struct device_driver * drv) void driver_detach(struct device_driver * drv)
{ {
struct device * next; struct device * next;
struct device * dev = NULL; struct device * dev = NULL;
struct list_head * node; struct list_head * node;
int error = 0; int error = 0;
read_lock(&drv->lock); write_lock(&drv->lock);
node = drv->devices.next; node = drv->devices.next;
while (node != &drv->devices) { while (node != &drv->devices) {
next = list_entry(node,struct device,driver_list); next = list_entry(node,struct device,driver_list);
get_device(next); get_device(next);
read_unlock(&drv->lock); list_del_init(&next->driver_list);
write_unlock(&drv->lock);
if (dev) if (dev)
put_device(dev); put_device(dev);
dev = next; dev = next;
if ((error = do_driver_unbind(dev,drv))) { if ((error = do_driver_detach(dev,drv))) {
put_device(dev); put_device(dev);
break; break;
} }
read_lock(&drv->lock); write_lock(&drv->lock);
node = dev->driver_list.next; node = drv->devices.next;
} }
read_unlock(&drv->lock); write_unlock(&drv->lock);
if (dev) if (dev)
put_device(dev); put_device(dev);
} }
...@@ -181,13 +196,13 @@ int device_register(struct device *dev) ...@@ -181,13 +196,13 @@ int device_register(struct device *dev)
if (!dev || !strlen(dev->bus_id)) if (!dev || !strlen(dev->bus_id))
return -EINVAL; return -EINVAL;
spin_lock(&device_lock);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list); INIT_LIST_HEAD(&dev->g_list);
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
atomic_set(&dev->refcount,2); atomic_set(&dev->refcount,2);
spin_lock(&device_lock);
if (dev != &device_root) { if (dev != &device_root) {
if (!dev->parent) if (!dev->parent)
dev->parent = &device_root; dev->parent = &device_root;
...@@ -212,7 +227,7 @@ int device_register(struct device *dev) ...@@ -212,7 +227,7 @@ int device_register(struct device *dev)
bus_add_device(dev); bus_add_device(dev);
/* bind to driver */ /* bind to driver */
device_bind(dev); device_attach(dev);
/* notify platform of device entry */ /* notify platform of device entry */
if (platform_notify) if (platform_notify)
...@@ -246,7 +261,7 @@ void put_device(struct device * dev) ...@@ -246,7 +261,7 @@ void put_device(struct device * dev)
if (platform_notify_remove) if (platform_notify_remove)
platform_notify_remove(dev); platform_notify_remove(dev);
device_unbind(dev); device_detach(dev);
bus_remove_device(dev); bus_remove_device(dev);
/* remove the driverfs directory */ /* remove the driverfs directory */
......
...@@ -74,33 +74,27 @@ int driver_register(struct device_driver * drv) ...@@ -74,33 +74,27 @@ int driver_register(struct device_driver * drv)
list_add(&drv->bus_list,&drv->bus->drivers); list_add(&drv->bus_list,&drv->bus->drivers);
write_unlock(&drv->bus->lock); write_unlock(&drv->bus->lock);
driver_make_dir(drv); driver_make_dir(drv);
driver_bind(drv); driver_attach(drv);
put_driver(drv); put_driver(drv);
return 0; return 0;
} }
static void __remove_driver(struct device_driver * drv) static void __remove_driver(struct device_driver * drv)
{ {
if (drv->bus) { pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name); driver_detach(drv);
driverfs_remove_dir(&drv->dir);
driver_unbind(drv);
write_lock(&drv->bus->lock);
list_del_init(&drv->bus_list);
write_unlock(&drv->bus->lock);
driverfs_remove_dir(&drv->dir);
put_bus(drv->bus);
}
if (drv->release) if (drv->release)
drv->release(drv); drv->release(drv);
put_bus(drv->bus);
} }
void remove_driver(struct device_driver * drv) void remove_driver(struct device_driver * drv)
{ {
spin_lock(&device_lock); write_lock(&drv->bus->lock);
atomic_set(&drv->refcount,0); atomic_set(&drv->refcount,0);
spin_unlock(&device_lock); list_del_init(&drv->bus_list);
write_unlock(&drv->bus->lock);
__remove_driver(drv); __remove_driver(drv);
} }
...@@ -110,10 +104,13 @@ void remove_driver(struct device_driver * drv) ...@@ -110,10 +104,13 @@ void remove_driver(struct device_driver * drv)
*/ */
void put_driver(struct device_driver * drv) void put_driver(struct device_driver * drv)
{ {
if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) write_lock(&drv->bus->lock);
if (!atomic_dec_and_test(&drv->refcount)) {
write_unlock(&drv->bus->lock);
return; return;
spin_unlock(&device_lock); }
list_del_init(&drv->bus_list);
write_unlock(&drv->bus->lock);
__remove_driver(drv); __remove_driver(drv);
} }
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
#define DRIVER_VERSION "0.2" #define DRIVER_VERSION "0.3"
#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" #define DRIVER_DESC "IBM Hot Plug PCI Controller Driver"
int ibmphp_debug; int ibmphp_debug;
...@@ -106,7 +106,7 @@ static inline int slot_update (struct slot **sl) ...@@ -106,7 +106,7 @@ static inline int slot_update (struct slot **sl)
return rc; return rc;
} }
static int get_max_slots (void) static int __init get_max_slots (void)
{ {
struct list_head * tmp; struct list_head * tmp;
int slot_count = 0; int slot_count = 0;
...@@ -528,7 +528,7 @@ static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value) ...@@ -528,7 +528,7 @@ static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
* function. It will also power off empty slots that are powered on since BIOS * function. It will also power off empty slots that are powered on since BIOS
* leaves those on, albeit disconnected * leaves those on, albeit disconnected
******************************************************************************/ ******************************************************************************/
static int init_ops (void) static int __init init_ops (void)
{ {
struct slot *slot_cur; struct slot *slot_cur;
int retval; int retval;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/init.h>
#include "ibmphp.h" #include "ibmphp.h"
/* /*
...@@ -76,7 +77,7 @@ static struct slot *alloc_ibm_slot (void) ...@@ -76,7 +77,7 @@ static struct slot *alloc_ibm_slot (void)
return slot; return slot;
} }
static struct ebda_hpc_list *alloc_ebda_hpc_list (void) static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
{ {
struct ebda_hpc_list *list; struct ebda_hpc_list *list;
...@@ -127,7 +128,7 @@ static void free_ebda_hpc (struct controller *controller) ...@@ -127,7 +128,7 @@ static void free_ebda_hpc (struct controller *controller)
kfree (controller); kfree (controller);
} }
static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void) static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void)
{ {
struct ebda_rsrc_list *list; struct ebda_rsrc_list *list;
...@@ -149,7 +150,7 @@ static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) ...@@ -149,7 +150,7 @@ static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void)
return resource; return resource;
} }
static void print_bus_info (void) static void __init print_bus_info (void)
{ {
struct bus_info *ptr; struct bus_info *ptr;
struct list_head *ptr1; struct list_head *ptr1;
...@@ -184,7 +185,7 @@ static void print_ebda_pci_rsrc (void) ...@@ -184,7 +185,7 @@ static void print_ebda_pci_rsrc (void)
} }
} }
static void print_ebda_hpc (void) static void __init print_ebda_hpc (void)
{ {
struct controller *hpc_ptr; struct controller *hpc_ptr;
struct list_head *ptr1; struct list_head *ptr1;
...@@ -228,7 +229,7 @@ static void print_ebda_hpc (void) ...@@ -228,7 +229,7 @@ static void print_ebda_hpc (void)
} }
} }
int ibmphp_access_ebda (void) int __init ibmphp_access_ebda (void)
{ {
u8 format, num_ctlrs, rio_complete, hs_complete; u8 format, num_ctlrs, rio_complete, hs_complete;
u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base;
...@@ -387,7 +388,7 @@ int ibmphp_access_ebda (void) ...@@ -387,7 +388,7 @@ int ibmphp_access_ebda (void)
* each hpc from physical address to a list of hot plug controllers based on * each hpc from physical address to a list of hot plug controllers based on
* hpc descriptors. * hpc descriptors.
*/ */
static int ebda_rsrc_controller (void) static int __init ebda_rsrc_controller (void)
{ {
u16 addr, addr_slot, addr_bus; u16 addr, addr_slot, addr_bus;
u8 ctlr_id, temp, bus_index; u8 ctlr_id, temp, bus_index;
...@@ -649,7 +650,7 @@ static int ebda_rsrc_controller (void) ...@@ -649,7 +650,7 @@ static int ebda_rsrc_controller (void)
* map info (bus, devfun, start addr, end addr..) of i/o, memory, * map info (bus, devfun, start addr, end addr..) of i/o, memory,
* pfm from the physical addr to a list of resource. * pfm from the physical addr to a list of resource.
*/ */
static int ebda_rsrc_rsrc (void) static int __init ebda_rsrc_rsrc (void)
{ {
u16 addr; u16 addr;
short rsrc; short rsrc;
...@@ -717,7 +718,7 @@ static int ebda_rsrc_rsrc (void) ...@@ -717,7 +718,7 @@ static int ebda_rsrc_rsrc (void)
/* /*
* map info of scalability details and rio details from physical address * map info of scalability details and rio details from physical address
*/ */
static int ebda_rio_table(void) static int __init ebda_rio_table(void)
{ {
u16 offset; u16 offset;
u8 i; u8 i;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Written By: Jyoti Shah, IBM Corporation * Written By: Jyoti Shah, IBM Corporation
* *
* Copyright (c) 2001,2001 IBM Corp. * Copyright (c) 2001-2002 IBM Corp.
* *
* All rights reserved. * All rights reserved.
* *
...@@ -27,17 +27,14 @@ ...@@ -27,17 +27,14 @@
* *
*/ */
//#include <linux/delay.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h>
#include "ibmphp.h" #include "ibmphp.h"
#define POLL_NO 0x01
#define POLL_YES 0x00
static int to_debug = FALSE; static int to_debug = FALSE;
#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) #define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0)
...@@ -98,19 +95,15 @@ static int to_debug = FALSE; ...@@ -98,19 +95,15 @@ static int to_debug = FALSE;
// if bits 20,22,25,26,27,29,30 are OFF return TRUE // if bits 20,22,25,26,27,29,30 are OFF return TRUE
#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) #define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE))
// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
#define INCREMENT_POLLCNT(i) ((i < POLL_LATCH_CNT) ? i++ : (i=0))
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// global variables // global variables
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
static int ibmphp_shutdown; static int ibmphp_shutdown;
static int tid_poll; static int tid_poll;
static int stop_polling; // 2 values: poll, don't poll
static struct semaphore sem_hpcaccess; // lock access to HPC static struct semaphore sem_hpcaccess; // lock access to HPC
static struct semaphore semOperations; // lock all operations and static struct semaphore semOperations; // lock all operations and
// access to data structures // access to data structures
static struct semaphore sem_exit; // make sure polling thread goes away static struct semaphore sem_exit; // make sure polling thread goes away
static struct semaphore sem_poll; // make sure poll is idle
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// local function prototypes // local function prototypes
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -134,15 +127,13 @@ static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); ...@@ -134,15 +127,13 @@ static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *);
* *
* Action: initialize semaphores and variables * Action: initialize semaphores and variables
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
void ibmphp_hpc_initvars (void) void __init ibmphp_hpc_initvars (void)
{ {
debug ("%s - Entry\n", __FUNCTION__); debug ("%s - Entry\n", __FUNCTION__);
init_MUTEX (&sem_hpcaccess); init_MUTEX (&sem_hpcaccess);
init_MUTEX (&semOperations); init_MUTEX (&semOperations);
init_MUTEX_LOCKED (&sem_exit); init_MUTEX_LOCKED (&sem_exit);
init_MUTEX_LOCKED (&sem_poll);
stop_polling = POLL_YES;
to_debug = FALSE; to_debug = FALSE;
ibmphp_shutdown = FALSE; ibmphp_shutdown = FALSE;
tid_poll = 0; tid_poll = 0;
...@@ -710,11 +701,6 @@ void free_hpc_access (void) ...@@ -710,11 +701,6 @@ void free_hpc_access (void)
void ibmphp_lock_operations (void) void ibmphp_lock_operations (void)
{ {
down (&semOperations); down (&semOperations);
stop_polling = POLL_NO;
to_debug = TRUE;
/* waiting for polling to actually stop */
down (&sem_poll);
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
...@@ -723,8 +709,6 @@ void ibmphp_lock_operations (void) ...@@ -723,8 +709,6 @@ void ibmphp_lock_operations (void)
void ibmphp_unlock_operations (void) void ibmphp_unlock_operations (void)
{ {
debug ("%s - Entry\n", __FUNCTION__); debug ("%s - Entry\n", __FUNCTION__);
stop_polling = POLL_YES;
to_debug = FALSE;
up (&semOperations); up (&semOperations);
debug ("%s - Exit\n", __FUNCTION__); debug ("%s - Exit\n", __FUNCTION__);
} }
...@@ -732,34 +716,30 @@ void ibmphp_unlock_operations (void) ...@@ -732,34 +716,30 @@ void ibmphp_unlock_operations (void)
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
* Name: poll_hpc() * Name: poll_hpc()
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
#define POLL_LATCH_REGISTER 0
#define POLL_SLOTS 1
#define POLL_SLEEP 2
static void poll_hpc (void) static void poll_hpc (void)
{ {
struct slot myslot, *pslot = NULL; struct slot myslot;
struct slot *pslot = NULL;
struct list_head *pslotlist; struct list_head *pslotlist;
int rc; int rc;
int poll_state = POLL_LATCH_REGISTER;
u8 oldlatchlow = 0x00; u8 oldlatchlow = 0x00;
u8 curlatchlow = 0x00; u8 curlatchlow = 0x00;
int pollcnt = 0; int poll_count = 0;
u8 ctrl_count = 0x00; u8 ctrl_count = 0x00;
debug ("poll_hpc - Entry\n"); debug ("%s - Entry\n", __FUNCTION__);
while (!ibmphp_shutdown) { while (!ibmphp_shutdown) {
if (stop_polling) { /* try to get the lock to do some kind of harware access */
debug ("poll_hpc - stop_polling\n"); down (&semOperations);
up (&sem_poll);
/* to prevent deadlock */
if (ibmphp_shutdown)
break;
/* to make the thread sleep */
down (&semOperations);
up (&semOperations);
debug ("poll_hpc - after stop_polling sleep\n");
} else {
if (pollcnt) {
// only poll the latch register
oldlatchlow = curlatchlow;
switch (poll_state) {
case POLL_LATCH_REGISTER:
oldlatchlow = curlatchlow;
ctrl_count = 0x00; ctrl_count = 0x00;
list_for_each (pslotlist, &ibmphp_slot_head) { list_for_each (pslotlist, &ibmphp_slot_head) {
if (ctrl_count >= ibmphp_get_total_controllers()) if (ctrl_count >= ibmphp_get_total_controllers())
...@@ -773,14 +753,16 @@ static void poll_hpc (void) ...@@ -773,14 +753,16 @@ static void poll_hpc (void)
&curlatchlow); &curlatchlow);
if (oldlatchlow != curlatchlow) if (oldlatchlow != curlatchlow)
process_changeinlatch (oldlatchlow, process_changeinlatch (oldlatchlow,
curlatchlow, pslot->ctrl); curlatchlow,
pslot->ctrl);
} }
} }
} }
} else { poll_state = POLL_SLOTS;
break;
case POLL_SLOTS:
list_for_each (pslotlist, &ibmphp_slot_head) { list_for_each (pslotlist, &ibmphp_slot_head) {
if (stop_polling)
break;
pslot = list_entry (pslotlist, struct slot, ibm_slot_list); pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
// make a copy of the old status // make a copy of the old status
memcpy ((void *) &myslot, (void *) pslot, memcpy ((void *) &myslot, (void *) pslot,
...@@ -791,31 +773,45 @@ static void poll_hpc (void) ...@@ -791,31 +773,45 @@ static void poll_hpc (void)
process_changeinstatus (pslot, &myslot); process_changeinstatus (pslot, &myslot);
} }
if (!stop_polling) { ctrl_count = 0x00;
ctrl_count = 0x00; list_for_each (pslotlist, &ibmphp_slot_head) {
list_for_each (pslotlist, &ibmphp_slot_head) { if (ctrl_count >= ibmphp_get_total_controllers())
if (ctrl_count >= ibmphp_get_total_controllers()) break;
break; pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
pslot = if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
list_entry (pslotlist, struct slot, ctrl_count++;
ibm_slot_list); if (READ_SLOT_LATCH (pslot->ctrl))
if (pslot->ctrl->ctlr_relative_id == ctrl_count) { rc = ibmphp_hpc_readslot (pslot,
ctrl_count++; READ_SLOTLATCHLOWREG,
if (READ_SLOT_LATCH (pslot->ctrl)) &curlatchlow);
rc = ibmphp_hpc_readslot (pslot,
READ_SLOTLATCHLOWREG,
&curlatchlow);
}
} }
} }
} ++poll_count;
INCREMENT_POLLCNT (pollcnt); if (poll_count >= POLL_LATCH_CNT) {
long_delay (POLL_INTERVAL_SEC * HZ); // snooze poll_count = 0;
poll_state = POLL_SLEEP;
}
break;
case POLL_SLEEP:
/* don't sleep with a lock on the hardware */
up (&semOperations);
long_delay (POLL_INTERVAL_SEC * HZ);
down (&semOperations);
poll_state = POLL_LATCH_REGISTER;
break;
} }
/* give up the harware semaphore */
up (&semOperations);
/* sleep for a short time just for good measure */
set_current_state (TASK_INTERRUPTIBLE);
schedule_timeout (HZ/10);
} }
up (&sem_poll);
up (&sem_exit); up (&sem_exit);
debug ("poll_hpc - Exit\n"); debug ("%s - Exit\n", __FUNCTION__);
} }
...@@ -1049,19 +1045,19 @@ static int hpc_poll_thread (void *data) ...@@ -1049,19 +1045,19 @@ static int hpc_poll_thread (void *data)
* *
* Action: start polling thread * Action: start polling thread
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
int ibmphp_hpc_start_poll_thread (void) int __init ibmphp_hpc_start_poll_thread (void)
{ {
int rc = 0; int rc = 0;
debug ("ibmphp_hpc_start_poll_thread - Entry\n"); debug ("%s - Entry\n", __FUNCTION__);
tid_poll = kernel_thread (hpc_poll_thread, 0, 0); tid_poll = kernel_thread (hpc_poll_thread, 0, 0);
if (tid_poll < 0) { if (tid_poll < 0) {
err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n"); err ("%s - Error, thread not started\n", __FUNCTION__);
rc = -1; rc = -1;
} }
debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc); debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
return rc; return rc;
} }
...@@ -1070,9 +1066,9 @@ int ibmphp_hpc_start_poll_thread (void) ...@@ -1070,9 +1066,9 @@ int ibmphp_hpc_start_poll_thread (void)
* *
* Action: stop polling thread and cleanup * Action: stop polling thread and cleanup
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
void ibmphp_hpc_stop_poll_thread (void) void __exit ibmphp_hpc_stop_poll_thread (void)
{ {
debug ("ibmphp_hpc_stop_poll_thread - Entry\n"); debug ("%s - Entry\n", __FUNCTION__);
ibmphp_shutdown = TRUE; ibmphp_shutdown = TRUE;
ibmphp_lock_operations (); ibmphp_lock_operations ();
...@@ -1083,10 +1079,9 @@ void ibmphp_hpc_stop_poll_thread (void) ...@@ -1083,10 +1079,9 @@ void ibmphp_hpc_stop_poll_thread (void)
// cleanup // cleanup
free_hpc_access (); free_hpc_access ();
ibmphp_unlock_operations (); ibmphp_unlock_operations ();
up (&sem_poll);
up (&sem_exit); up (&sem_exit);
debug ("ibmphp_hpc_stop_poll_thread - Exit\n"); debug ("%s - Exit\n", __FUNCTION__);
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/init.h>
#include "ibmphp.h" #include "ibmphp.h"
static int flags = 0; /* for testing */ static int flags = 0; /* for testing */
...@@ -45,7 +46,7 @@ static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); ...@@ -45,7 +46,7 @@ static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
static LIST_HEAD(gbuses); static LIST_HEAD(gbuses);
static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr) static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr)
{ {
struct bus_node * newbus; struct bus_node * newbus;
...@@ -61,7 +62,7 @@ static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr) ...@@ -61,7 +62,7 @@ static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr)
return newbus; return newbus;
} }
static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr) static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
{ {
struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
if (!rs) { if (!rs) {
...@@ -77,7 +78,7 @@ static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr) ...@@ -77,7 +78,7 @@ static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr)
return rs; return rs;
} }
static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
{ {
struct bus_node * newbus; struct bus_node * newbus;
struct range_node *newrange; struct range_node *newrange;
...@@ -184,7 +185,7 @@ static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_r ...@@ -184,7 +185,7 @@ static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_r
* Input: ptr to the head of the resource list from EBDA * Input: ptr to the head of the resource list from EBDA
* Output: 0, -1 or error codes * Output: 0, -1 or error codes
***************************************************************************/ ***************************************************************************/
int ibmphp_rsrc_init (void) int __init ibmphp_rsrc_init (void)
{ {
struct ebda_pci_rsrc *curr; struct ebda_pci_rsrc *curr;
struct range_node *newrange = NULL; struct range_node *newrange = NULL;
...@@ -1650,7 +1651,7 @@ void ibmphp_free_resources (void) ...@@ -1650,7 +1651,7 @@ void ibmphp_free_resources (void)
* a new Mem node * a new Mem node
* This routine is called right after initialization * This routine is called right after initialization
*******************************************************************************/ *******************************************************************************/
static int once_over (void) static int __init once_over (void)
{ {
struct resource_node *pfmem_cur; struct resource_node *pfmem_cur;
struct resource_node *pfmem_prev; struct resource_node *pfmem_prev;
...@@ -1871,7 +1872,7 @@ void ibmphp_print_test (void) ...@@ -1871,7 +1872,7 @@ void ibmphp_print_test (void)
* behind them All these are TO DO. * behind them All these are TO DO.
* Also need to add more error checkings... (from fnc returns etc) * Also need to add more error checkings... (from fnc returns etc)
*/ */
static int update_bridge_ranges (struct bus_node **bus) static int __init update_bridge_ranges (struct bus_node **bus)
{ {
u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address; u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address;
u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
...@@ -1885,7 +1886,7 @@ static int update_bridge_ranges (struct bus_node **bus) ...@@ -1885,7 +1886,7 @@ static int update_bridge_ranges (struct bus_node **bus)
bus_cur = *bus; bus_cur = *bus;
busno = bus_cur->busno; busno = bus_cur->busno;
debug ("inside update_bridge_ranges \n"); debug ("inside %s \n", __FUNCTION__);
debug ("bus_cur->busno = %x\n", bus_cur->busno); debug ("bus_cur->busno = %x\n", bus_cur->busno);
for (device = 0; device < 32; device++) { for (device = 0; device < 32; device++) {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/namei.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "pci_hotplug.h" #include "pci_hotplug.h"
......
...@@ -165,7 +165,7 @@ pci_dev_driver(const struct pci_dev *dev) ...@@ -165,7 +165,7 @@ pci_dev_driver(const struct pci_dev *dev)
} }
/** /**
* pci_bus_bind - Tell if a PCI device structure has a matching PCI device id structure * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure
* @ids: array of PCI device id structures to search in * @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against * @dev: the PCI device structure to match against
* *
...@@ -173,7 +173,7 @@ pci_dev_driver(const struct pci_dev *dev) ...@@ -173,7 +173,7 @@ pci_dev_driver(const struct pci_dev *dev)
* system is in its list of supported devices.Returns the matching * system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match. * pci_device_id structure or %NULL if there is no match.
*/ */
static int pci_bus_bind(struct device * dev, struct device_driver * drv) static int pci_bus_match(struct device * dev, struct device_driver * drv)
{ {
struct pci_dev * pci_dev = list_entry(dev, struct pci_dev, dev); struct pci_dev * pci_dev = list_entry(dev, struct pci_dev, dev);
struct pci_driver * pci_drv = list_entry(drv,struct pci_driver,driver); struct pci_driver * pci_drv = list_entry(drv,struct pci_driver,driver);
...@@ -196,7 +196,7 @@ static int pci_bus_bind(struct device * dev, struct device_driver * drv) ...@@ -196,7 +196,7 @@ static int pci_bus_bind(struct device * dev, struct device_driver * drv)
struct bus_type pci_bus_type = { struct bus_type pci_bus_type = {
name: "pci", name: "pci",
bind: pci_bus_bind, match: pci_bus_match,
}; };
static int __init pci_driver_init(void) static int __init pci_driver_init(void)
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
comment 'USB Device Class drivers' comment 'USB Device Class drivers'
dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
dep_tristate ' USB Bluetooth TTY support' CONFIG_USB_BLUETOOTH_TTY $CONFIG_USB dep_tristate ' USB Bluetooth TTY support' CONFIG_USB_BLUETOOTH_TTY $CONFIG_USB
dep_tristate ' USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB
dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
obj-$(CONFIG_USB_ACM) += cdc-acm.o obj-$(CONFIG_USB_ACM) += cdc-acm.o
obj-$(CONFIG_USB_AUDIO) += audio.o obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_BLUETOOTH_TTY) += bluetty.o obj-$(CONFIG_USB_BLUETOOTH_TTY) += bluetty.o
obj-$(CONFIG_USB_MIDI) += usb-midi.o
obj-$(CONFIG_USB_PRINTER) += printer.o obj-$(CONFIG_USB_PRINTER) += printer.o
......
This diff is collapsed.
/*
usb-midi.h -- USB-MIDI driver
Copyright (C) 2001
NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
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, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ------------------------------------------------------------------------- */
#ifndef _USB_MIDI_H_
#define _USB_MIDI_H_
#ifndef USB_SUBCLASS_MIDISTREAMING
#define USB_SUBCLASS_MIDISTREAMING 3
#endif
#define USB_DT_CS_DEVICE 0x21
#define USB_DT_CS_CONFIG 0x22
#define USB_DT_CS_STRING 0x23
#define USB_DT_CS_INTERFACE 0x24
#define USB_DT_CS_ENDPOINT 0x25
/* ------------------------------------------------------------------------- */
/* Roland MIDI Devices */
#define USB_VENDOR_ID_ROLAND 0x0582
#define USBMIDI_ROLAND_UA100G 0x0000
#define USBMIDI_ROLAND_MPU64 0x0002
#define USBMIDI_ROLAND_SC8850 0x0003
#define USBMIDI_ROLAND_UM2 0x0005
#define USBMIDI_ROLAND_UM1 0x0009
#define USBMIDI_ROLAND_PC300 0x0008
/* YAMAHA MIDI Devices */
#define USB_VENDOR_ID_YAMAHA 0x0499
#define USBMIDI_YAMAHA_MU1000 0x1001
/* Steinberg MIDI Devices */
#define USB_VENDOR_ID_STEINBERG 0x0763
#define USBMIDI_STEINBERG_USB2MIDI 0x1001
/* ------------------------------------------------------------------------- */
/* Supported devices */
struct usb_midi_endpoint {
int endpoint;
int cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
};
struct usb_midi_device {
char *deviceName;
int idVendor;
int idProduct;
int interface;
int altSetting; /* -1: auto detect */
struct usb_midi_endpoint in[15];
struct usb_midi_endpoint out[15];
};
static struct usb_midi_device usb_midi_devices[] = {
{ /* Roland UM-1 */
"Roland UM-1",
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
{ { 0x81, 1 }, {-1, -1} },
{ { 0x01, 1,}, {-1, -1} },
},
{ /* Roland UM-2 */
"Roland UM-2" ,
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
{ { 0x81, 3 }, {-1, -1} },
{ { 0x01, 3,}, {-1, -1} },
},
/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
{ /* Roland UA-100 */
"Roland UA-100",
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
{ { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
{ { 0x02, 7 }, {-1, -1} },
},
/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
{ /* Roland SC8850 */
"Roland SC8850",
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
{ { 0x81, 15 }, {-1, -1} }, /** cables 0,1,2, and 3 **/
{ { 0x01, 15 }, {-1, -1} },
},
{ /* YAMAHA MU1000 */
"YAMAHA MU1000",
USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1,
{ { 0x81, 1 }, {-1, -1} },
{ { 0x01, 15 }, {-1, -1} },
},
{ /* Roland PC-300 */
"Roland PC-300",
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1,
{ { 0x81, 1 }, {-1, -1} },
{ { 0x01, 1 }, {-1, -1} },
}
};
#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
/* for Hot-Plugging */
static struct usb_device_id usb_midi_ids [] = {
{ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: USB_SUBCLASS_MIDISTREAMING},
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1 ) },
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2 ) },
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
/* { USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_midi_ids);
/* ------------------------------------------------------------------------- */
#endif /* _USB_MIDI_H_ */
...@@ -2,11 +2,15 @@ ...@@ -2,11 +2,15 @@
# Makefile for USB Core files and filesystem # Makefile for USB Core files and filesystem
# #
export-objs := usb.o hcd.o urb.o message.o config.o export-objs := usb.o hcd.o hcd-pci.o urb.o message.o config.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o \ usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o \
config.o config.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
endif
ifeq ($(CONFIG_USB_DEVICEFS),y) ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += devio.o inode.o drivers.o devices.o usbcore-objs += devio.o inode.o drivers.o devices.o
endif endif
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mm.h> #include <linux/gfp.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usbdevice_fs.h> #include <linux/usbdevice_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
......
/*
* (C) Copyright David Brownell 2000-2002
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
#include "hcd.h"
/* PCI-based HCs are normal, but custom bus glue should be ok */
/*-------------------------------------------------------------------------*/
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
/**
* usb_hcd_pci_probe - initialize PCI-based HCDs
* @dev: USB Host Controller being probed
* @id: pci hotplug id connecting controller to HCD framework
* Context: !in_interrupt()
*
* Allocates basic PCI resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*
* Store this function in the HCD's struct pci_driver as probe().
*/
int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
struct hc_driver *driver;
unsigned long resource, len;
void *base;
u8 latency, limit;
struct usb_hcd *hcd;
int retval, region;
char buf [8], *bufp = buf;
if (!id || !(driver = (struct hc_driver *) id->driver_data))
return -EINVAL;
if (pci_enable_device (dev) < 0)
return -ENODEV;
if (!dev->irq) {
err ("Found HC with no IRQ. Check BIOS/PCI %s setup!",
dev->slot_name);
return -ENODEV;
}
if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
region = 0;
resource = pci_resource_start (dev, 0);
len = pci_resource_len (dev, 0);
if (!request_mem_region (resource, len, driver->description)) {
dbg ("controller already in use");
return -EBUSY;
}
base = ioremap_nocache (resource, len);
if (base == NULL) {
dbg ("error mapping memory");
retval = -EFAULT;
clean_1:
release_mem_region (resource, len);
err ("init %s fail, %d", dev->slot_name, retval);
return retval;
}
} else { // UHCI
resource = len = 0;
for (region = 0; region < PCI_ROM_RESOURCE; region++) {
if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
continue;
resource = pci_resource_start (dev, region);
len = pci_resource_len (dev, region);
if (request_region (resource, len,
driver->description))
break;
}
if (region == PCI_ROM_RESOURCE) {
dbg ("no i/o regions available");
return -EBUSY;
}
base = (void *) resource;
}
// driver->start(), later on, will transfer device from
// control by SMM/BIOS to control by Linux (if needed)
pci_set_master (dev);
hcd = driver->hcd_alloc ();
if (hcd == NULL){
dbg ("hcd alloc fail");
retval = -ENOMEM;
clean_2:
if (driver->flags & HCD_MEMORY) {
iounmap (base);
goto clean_1;
} else {
release_region (resource, len);
err ("init %s fail, %d", dev->slot_name, retval);
return retval;
}
}
pci_set_drvdata(dev, hcd);
hcd->driver = driver;
hcd->description = driver->description;
hcd->pdev = dev;
info ("%s @ %s, %s", hcd->description, dev->slot_name, dev->name);
pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
if (latency) {
pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
if (limit && limit < latency) {
dbg ("PCI latency reduced to max %d", limit);
pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
}
}
#ifndef __sparc__
sprintf (buf, "%d", dev->irq);
#else
bufp = __irq_itoa(dev->irq);
#endif
if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
!= 0) {
err ("request interrupt %s failed", bufp);
retval = -EBUSY;
driver->hcd_free (hcd);
goto clean_2;
}
hcd->irq = dev->irq;
hcd->regs = base;
hcd->region = region;
info ("irq %s, %s %p", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
base);
usb_bus_init (&hcd->self);
hcd->self.op = &usb_hcd_operations;
hcd->self.hcpriv = (void *) hcd;
hcd->self.bus_name = dev->slot_name;
hcd->product_desc = dev->name;
INIT_LIST_HEAD (&hcd->dev_list);
usb_register_bus (&hcd->self);
if ((retval = driver->start (hcd)) < 0)
usb_hcd_pci_remove (dev);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_probe);
/* may be called without controller electrically present */
/* may be called with controller, bus, and devices active */
/**
* usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_pci_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
* Store this function in the HCD's struct pci_driver as remove().
*/
void usb_hcd_pci_remove (struct pci_dev *dev)
{
struct usb_hcd *hcd;
struct usb_device *hub;
hcd = pci_get_drvdata(dev);
if (!hcd)
return;
info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
if (in_interrupt ()) BUG ();
hub = hcd->self.root_hub;
hcd->state = USB_STATE_QUIESCING;
dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
usb_disconnect (&hub);
hcd->driver->stop (hcd);
hcd->state = USB_STATE_HALT;
free_irq (hcd->irq, hcd);
if (hcd->driver->flags & HCD_MEMORY) {
iounmap (hcd->regs);
release_mem_region (pci_resource_start (dev, 0),
pci_resource_len (dev, 0));
} else {
release_region (pci_resource_start (dev, hcd->region),
pci_resource_len (dev, hcd->region));
}
usb_deregister_bus (&hcd->self);
if (atomic_read (&hcd->self.refcnt) != 1)
err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
hcd->driver->hcd_free (hcd);
}
EXPORT_SYMBOL (usb_hcd_pci_remove);
#ifdef CONFIG_PM
/*
* Some "sleep" power levels imply updating struct usb_driver
* to include a callback asking hcds to do their bit by checking
* if all the drivers can suspend. Gets involved with remote wakeup.
*
* If there are pending urbs, then HCs will need to access memory,
* causing extra power drain. New sleep()/wakeup() PM calls might
* be needed, beyond PCI suspend()/resume(). The root hub timer
* still be accessing memory though ...
*
* FIXME: USB should have some power budgeting support working with
* all kinds of hubs.
*
* FIXME: This assumes only D0->D3 suspend and D3->D0 resume.
* D1 and D2 states should do something, yes?
*
* FIXME: Should provide generic enable_wake(), calling pci_enable_wake()
* for all supported states, so that USB remote wakeup can work for any
* devices that support it (and are connected via powered hubs).
*
* FIXME: resume doesn't seem to work right any more...
*/
// 2.4 kernels have issued concurrent resumes (w/APM)
// we defend against that error; PCI doesn't yet.
/**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended
*
* Store this function in the HCD's struct pci_driver as suspend().
*/
int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
{
struct usb_hcd *hcd;
int retval;
hcd = pci_get_drvdata(dev);
info ("suspend %s to state %d", hcd->self.bus_name, state);
pci_save_state (dev, hcd->pci_state);
// FIXME for all connected devices, leaf-to-root:
// driver->suspend()
// proposed "new 2.5 driver model" will automate that
/* driver may want to disable DMA etc */
retval = hcd->driver->suspend (hcd, state);
hcd->state = USB_STATE_SUSPENDED;
pci_set_power_state (dev, state);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
/**
* usb_hcd_pci_resume - power management resume of a PCI-based HCD
* @dev: USB Host Controller being resumed
*
* Store this function in the HCD's struct pci_driver as resume().
*/
int usb_hcd_pci_resume (struct pci_dev *dev)
{
struct usb_hcd *hcd;
int retval;
hcd = pci_get_drvdata(dev);
info ("resume %s", hcd->self.bus_name);
/* guard against multiple resumes (APM bug?) */
atomic_inc (&hcd->resume_count);
if (atomic_read (&hcd->resume_count) != 1) {
err ("concurrent PCI resumes for %s", hcd->self.bus_name);
retval = 0;
goto done;
}
retval = -EBUSY;
if (hcd->state != USB_STATE_SUSPENDED) {
dbg ("can't resume, not suspended!");
goto done;
}
hcd->state = USB_STATE_RESUMING;
pci_set_power_state (dev, 0);
pci_restore_state (dev, hcd->pci_state);
retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) {
dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
usb_hc_died (hcd);
// FIXME: recover, reset etc.
} else {
// FIXME for all connected devices, root-to-leaf:
// driver->resume ();
// proposed "new 2.5 driver model" will automate that
}
done:
atomic_dec (&hcd->resume_count);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_resume);
#endif /* CONFIG_PM */
This diff is collapsed.
...@@ -50,9 +50,9 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -50,9 +50,9 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
int irq; /* irq allocated */ int irq; /* irq allocated */
void *regs; /* device memory/io */ void *regs; /* device memory/io */
#ifdef CONFIG_PCI
/* a few non-PCI controllers exist, mostly for OHCI */ /* a few non-PCI controllers exist, mostly for OHCI */
struct pci_dev *pdev; /* pci is typical */ struct pci_dev *pdev; /* pci is typical */
#ifdef CONFIG_PCI
int region; /* pci region for regs */ int region; /* pci region for regs */
u32 pci_state [16]; /* for PM state save */ u32 pci_state [16]; /* for PM state save */
atomic_t resume_count; /* multiple resumes issue */ atomic_t resume_count; /* multiple resumes issue */
...@@ -161,6 +161,8 @@ struct hc_driver { ...@@ -161,6 +161,8 @@ struct hc_driver {
}; };
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
extern void usb_bus_init (struct usb_bus *bus);
extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
struct pci_dev; struct pci_dev;
...@@ -179,6 +181,11 @@ extern int usb_hcd_pci_resume (struct pci_dev *dev); ...@@ -179,6 +181,11 @@ extern int usb_hcd_pci_resume (struct pci_dev *dev);
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/* generic bus glue, needed for host controllers that don't use PCI */
extern struct usb_operations usb_hcd_operations;
extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
extern void usb_hc_died (struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Enumeration is only for the hub driver, or HCD virtual root hubs */ /* Enumeration is only for the hub driver, or HCD virtual root hubs */
......
...@@ -182,15 +182,170 @@ struct urb * usb_get_urb(struct urb *urb) ...@@ -182,15 +182,170 @@ struct urb * usb_get_urb(struct urb *urb)
*/ */
int usb_submit_urb(struct urb *urb, int mem_flags) int usb_submit_urb(struct urb *urb, int mem_flags)
{ {
int pipe, temp, max;
struct usb_device *dev;
struct usb_operations *op;
int is_out;
if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) { if (!urb || urb->hcpriv || !urb->complete)
if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) { return -EINVAL;
err("%s: pipe %x has invalid size (<= 0)", __FUNCTION__, urb->pipe); if (!(dev = urb->dev) || !dev->bus || dev->devnum <= 0)
return -ENODEV;
if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
urb->bandwidth = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
temp = usb_pipetype (pipe);
is_out = usb_pipeout (pipe);
/* (actually HCDs may need to duplicate this, endpoint might yet
* stall due to queued bulk/intr transactions that complete after
* we check)
*/
if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out))
return -EPIPE;
/* FIXME there should be a sharable lock protecting us against
* config/altsetting changes and disconnects, kicking in here.
* (here == before maxpacket, and eventually endpoint type,
* checks get made.)
*/
max = usb_maxpacket (dev, pipe, is_out);
if (max <= 0) {
dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)",
__FUNCTION__,
usb_pipeendpoint (pipe), is_out ? "OUT" : "IN",
dev->bus->bus_name, dev->devpath,
max);
return -EMSGSIZE;
}
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) {
int mult;
switch (temp) {
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
mult = 1 + ((max >> 11) & 0x03);
max &= 0x03ff;
max *= mult;
}
}
/* periodic transfers limit size per frame/uframe */
switch (temp) {
case PIPE_ISOCHRONOUS: {
int n, len;
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
len = urb->iso_frame_desc [n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
}
}
break;
case PIPE_INTERRUPT:
if (urb->transfer_buffer_length > max)
return -EMSGSIZE; return -EMSGSIZE;
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */
if (urb->transfer_buffer_length < 0)
return -EMSGSIZE;
#ifdef DEBUG
/* stuff that drivers shouldn't do, but which shouldn't
* cause problems in HCDs if they get it wrong.
*/
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
/* enforce simple/standard policy */
allowed = USB_ASYNC_UNLINK; // affects later unlinks
allowed |= USB_NO_FSBR; // only affects UHCI
switch (temp) {
case PIPE_CONTROL:
allowed |= USB_DISABLE_SPD;
break;
case PIPE_BULK:
allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
| USB_ZERO_PACKET | URB_NO_INTERRUPT;
break;
case PIPE_INTERRUPT:
allowed |= USB_DISABLE_SPD;
break;
case PIPE_ISOCHRONOUS:
allowed |= USB_ISO_ASAP;
break;
}
urb->transfer_flags &= allowed;
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
err ("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
}
#endif
/*
* Force periodic transfer intervals to be legal values that are
* a power of two (so HCDs don't need to).
*
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (temp) {
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
/* too big? */
switch (dev->speed) {
case USB_SPEED_HIGH: /* units are microframes */
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
temp = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (temp == PIPE_INTERRUPT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
temp = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
temp = 1024;
}
break;
default:
return -EINVAL;
} }
return urb->dev->bus->op->submit_urb(urb, mem_flags); /* power of two? */
while (temp > urb->interval)
temp >>= 1;
urb->interval = temp;
} }
return -ENODEV;
return op->submit_urb (urb, mem_flags);
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
......
This diff is collapsed.
...@@ -42,12 +42,6 @@ static void ohci_hcd_free (struct usb_hcd *hcd) ...@@ -42,12 +42,6 @@ static void ohci_hcd_free (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifndef CONFIG_PCI
# error "usb-ohci currently requires PCI-based controllers"
/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
#endif
/* Recover a TD/ED using its collision chain */ /* Recover a TD/ED using its collision chain */
static inline void * static inline void *
dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma) dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -37,9 +37,9 @@ struct ed { ...@@ -37,9 +37,9 @@ struct ed {
u8 int_period; u8 int_period;
u8 int_branch; u8 int_branch;
u8 int_load; u8 int_load;
}; } intr_info;
u16 last_iso; /* isochronous */ u16 last_iso; /* isochronous */
}; } intriso;
u8 state; /* ED_{NEW,UNLINK,OPER} */ u8 state; /* ED_{NEW,UNLINK,OPER} */
#define ED_NEW 0x00 /* unused, no dummy td */ #define ED_NEW 0x00 /* unused, no dummy td */
...@@ -331,6 +331,11 @@ struct hash_list_t { ...@@ -331,6 +331,11 @@ struct hash_list_t {
struct ohci_hcd { struct ohci_hcd {
spinlock_t lock; spinlock_t lock;
/*
* parent device
*/
struct device *parent_dev;
/* /*
* I/O memory used to communicate with the HC (uncached); * I/O memory used to communicate with the HC (uncached);
*/ */
...@@ -348,12 +353,10 @@ struct ohci_hcd { ...@@ -348,12 +353,10 @@ struct ohci_hcd {
struct ed *ed_controltail; /* last in ctrl list */ struct ed *ed_controltail; /* last in ctrl list */
struct ed *ed_isotail; /* last in iso list */ struct ed *ed_isotail; /* last in iso list */
#ifdef CONFIG_PCI
struct pci_pool *td_cache; struct pci_pool *td_cache;
struct pci_pool *ed_cache; struct pci_pool *ed_cache;
struct hash_list_t td_hash [TD_HASH_SIZE]; struct hash_list_t td_hash [TD_HASH_SIZE];
struct hash_list_t ed_hash [ED_HASH_SIZE]; struct hash_list_t ed_hash [ED_HASH_SIZE];
#endif
/* /*
* driver state * driver state
......
...@@ -1502,10 +1502,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) ...@@ -1502,10 +1502,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
break; break;
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
if (urb->bandwidth == 0) { /* not yet checked/allocated */ if (urb->bandwidth == 0) { /* not yet checked/allocated */
if (urb->number_of_packets <= 0) {
ret = -EINVAL;
break;
}
bustime = usb_check_bandwidth(urb->dev, urb); bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0) { if (bustime < 0) {
ret = bustime; ret = bustime;
......
...@@ -52,7 +52,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) ...@@ -52,7 +52,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
// FIXME: Shouldn't this return the length of the data too? /* size of returned buffer is part of USB spec */
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength) u16 wIndex, char *buf, u16 wLength)
{ {
......
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
#endif #endif
#endif #endif
int __devinit
hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
ohci_t **ohci, const char *name, const char *slot_name);
extern void hc_remove_ohci(ohci_t *ohci);
extern int hc_start (ohci_t * ohci, struct device *parent_dev);
extern int hc_reset (ohci_t * ohci);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -103,7 +109,8 @@ static void hc_restart (ohci_t *ohci) ...@@ -103,7 +109,8 @@ static void hc_restart (ohci_t *ohci)
ohci->ed_controltail = NULL; ohci->ed_controltail = NULL;
ohci->ed_bulktail = NULL; ohci->ed_bulktail = NULL;
if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { if ((temp = hc_reset (ohci)) < 0 ||
(temp = hc_start (ohci, &ohci->ohci_dev->dev)) < 0) {
err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp); err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
} else } else
dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name); dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
...@@ -171,6 +178,7 @@ static void __devexit ...@@ -171,6 +178,7 @@ static void __devexit
ohci_pci_remove (struct pci_dev *dev) ohci_pci_remove (struct pci_dev *dev)
{ {
ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev);
void *membase = ohci->regs;
dbg ("remove %s controller usb-%s%s%s", dbg ("remove %s controller usb-%s%s%s",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
...@@ -181,6 +189,9 @@ ohci_pci_remove (struct pci_dev *dev) ...@@ -181,6 +189,9 @@ ohci_pci_remove (struct pci_dev *dev)
hc_remove_ohci(ohci); hc_remove_ohci(ohci);
/* unmap the IO address space */
iounmap (membase);
release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0)); release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -203,6 +203,9 @@ static struct fb_ops clps7111fb_ops = { ...@@ -203,6 +203,9 @@ static struct fb_ops clps7111fb_ops = {
fb_get_cmap: gen_get_cmap, fb_get_cmap: gen_get_cmap,
fb_setcolreg: clps7111fb_setcolreg, fb_setcolreg: clps7111fb_setcolreg,
fb_blank: clps7111fb_blank, fb_blank: clps7111fb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
}; };
static int static int
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment