diff options
Diffstat (limited to 'drivers')
216 files changed, 10361 insertions, 6190 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index feab124d8e0..cbfc81579c9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->dev.kobj.name)); + kobject_name(&device->dev.kobj))); return -ENODEV; } /* diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 1e8287b4f40..1f6fb38de01 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS unsigned long reason; reason = pr->power.timer_broadcast_on_state < INT_MAX ? CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; clockevents_notify(reason, &pr->id); -#else - cpumask_t mask = cpumask_of_cpu(pr->id); - - if (pr->power.timer_broadcast_on_state < INT_MAX) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); - else - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif } /* Power(C) State timer broadcast control */ @@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS - int state = cx - pr->power.states; if (state >= pr->power.timer_broadcast_on_state) { @@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, CLOCK_EVT_NOTIFY_BROADCAST_EXIT; clockevents_notify(reason, &pr->id); } -#endif } #else diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64620d66874..5b4d462117c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } -static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct acpi_device *acpi_dev = to_acpi_device(dev); + int len; - strcpy(buffer, "MODALIAS="); - if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) { - envp[0] = buffer; - envp[1] = NULL; - } + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d05891f1628..b8a2095cb5e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od) { unsigned long state; struct acpi_video_device *vd = - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); acpi_video_device_get_state(vd, &state); return (int)state; } @@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od) { unsigned long state = od->request_state; struct acpi_video_device *vd= - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); return acpi_video_device_set_state(vd, state); } diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 268e301775f..6b94fb7be5f 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) { struct amba_device *pcdev = to_amba_device(dev); - int retval = 0, i = 0, len = 0; + int retval = 0; - retval = add_uevent_var(envp, nr_env, &i, - buf, bufsz, &len, - "AMBA_ID=%08x", pcdev->periphid); - envp[i] = NULL; + retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); return retval; } #else diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5d6312e3349..d7da109c24f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,5 +1,13 @@ menu "Generic Driver Options" +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on HOTPLUG + default "/sbin/hotplug" + help + Path to uevent helper program forked by the kernel for + every uevent. + config STANDALONE bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL default y diff --git a/drivers/base/base.h b/drivers/base/base.h index 47eb02d9f1a..10b2fb6c9ce 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -18,8 +18,6 @@ extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); -extern struct bus_type *get_bus(struct bus_type * bus); -extern void put_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 61c67526a65..9a19b071c57 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,17 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static struct bus_type *bus_get(struct bus_type *bus) +{ + return bus ? container_of(kset_get(&bus->subsys), + struct bus_type, subsys) : NULL; +} + +static void bus_put(struct bus_type *bus) +{ + kset_put(&bus->subsys); +} + static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj) */ } -static struct kobj_type ktype_driver = { +static struct kobj_type driver_ktype = { .sysfs_ops = &driver_sysfs_ops, .release = driver_release, }; @@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = { int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; - if (get_bus(bus)) { + if (bus_get(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } else error = -EINVAL; return error; @@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { - if (get_bus(bus)) { + if (bus_get(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } } @@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data) static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv, err = count; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); @@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); static ssize_t driver_bind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv, err = -ENODEV; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); @@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } */ int bus_add_device(struct device * dev) { - struct bus_type * bus = get_bus(dev->bus); + struct bus_type * bus = bus_get(dev->bus); int error = 0; if (bus) { @@ -459,7 +470,7 @@ out_subsys: out_id: device_remove_attrs(bus, dev); out_put: - put_bus(dev->bus); + bus_put(dev->bus); return error; } @@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev) } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); - put_bus(dev->bus); + bus_put(dev->bus); } } @@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_unbind); } +static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); +static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, + show_drivers_autoprobe, store_drivers_autoprobe); + static int add_probe_files(struct bus_type *bus) { int retval; - bus->drivers_probe_attr.attr.name = "drivers_probe"; - bus->drivers_probe_attr.attr.mode = S_IWUSR; - bus->drivers_probe_attr.store = store_drivers_probe; - retval = bus_create_file(bus, &bus->drivers_probe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_probe); if (retval) goto out; - bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; - bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; - bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; - bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; - retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_probe); out: return retval; } static void remove_probe_files(struct bus_type *bus) { - bus_remove_file(bus, &bus->drivers_autoprobe_attr); - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_autoprobe); + bus_remove_file(bus, &bus_attr_drivers_probe); } #else static inline int add_bind_files(struct device_driver *drv) { return 0; } @@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; } static inline void remove_probe_files(struct bus_type *bus) {} #endif +static ssize_t driver_uevent_store(struct device_driver *drv, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&drv->kobj, action); + return count; +} +static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); + /** * bus_add_driver - Add a driver to the bus. * @drv: driver. @@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {} */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = get_bus(drv->bus); + struct bus_type * bus = bus_get(drv->bus); int error = 0; if (!bus) @@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { + printk(KERN_ERR "%s: uevent attr (%s) failed\n", + __FUNCTION__, drv->name); + } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ @@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv) out_unregister: kobject_unregister(&drv->kobj); out_put_bus: - put_bus(bus); + bus_put(bus); return error; } @@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); + driver_remove_file(drv, &driver_attr_uevent); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); module_remove_driver(drv); kobject_unregister(&drv->kobj); - put_bus(drv->bus); + bus_put(drv->bus); } @@ -729,18 +754,6 @@ int device_reprobe(struct device *dev) } EXPORT_SYMBOL_GPL(device_reprobe); -struct bus_type *get_bus(struct bus_type *bus) -{ - return bus ? container_of(subsys_get(&bus->subsys), - struct bus_type, subsys) : NULL; -} - -void put_bus(struct bus_type * bus) -{ - subsys_put(&bus->subsys); -} - - /** * find_bus - locate bus by name. * @name: name of bus. @@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } +static ssize_t bus_uevent_store(struct bus_type *bus, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&bus->subsys.kobj, action); + return count; +} +static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); + /** * bus_register - register a bus with the system. * @bus: bus. @@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus) if (retval) goto out; - subsys_set_kset(bus, bus_subsys); + bus->subsys.kobj.kset = &bus_subsys; + retval = subsystem_register(&bus->subsys); if (retval) goto out; + retval = bus_create_file(bus, &bus_attr_uevent); + if (retval) + goto bus_uevent_fail; + kobject_set_name(&bus->devices.kobj, "devices"); bus->devices.kobj.parent = &bus->subsys.kobj; retval = kset_register(&bus->devices); @@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus) kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &ktype_driver; + bus->drivers.ktype = &driver_ktype; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; @@ -866,6 +895,8 @@ bus_probe_files_fail: bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: + bus_remove_file(bus, &bus_attr_uevent); +bus_uevent_fail: subsystem_unregister(&bus->subsys); out: return retval; @@ -876,7 +907,7 @@ out: * @bus: bus. * * Unregister the child subsystems and the bus itself. - * Finally, we call put_bus() to release the refcount + * Finally, we call bus_put() to release the refcount */ void bus_unregister(struct bus_type * bus) { @@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus) remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); + bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); } diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d2222618b7..a863bb091e1 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = { .store = class_attr_store, }; -static struct kobj_type ktype_class = { +static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &ktype_class, NULL); +static decl_subsys(class, &class_ktype, NULL); int class_create_file(struct class * cls, const struct class_attribute * attr) @@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(subsys_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), struct class, subsys); return NULL; } static void class_put(struct class * cls) { if (cls) - subsys_put(&cls->subsys); + kset_put(&cls->subsys); } @@ -149,7 +149,7 @@ int class_register(struct class * cls) if (error) return error; - subsys_set_kset(cls, class_subsys); + cls->subsys.kobj.kset = &class_subsys; error = subsystem_register(&cls->subsys); if (!error) { @@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) /* needed to allow these devices to have parent class devices */ static int class_device_create_uevent(struct class_device *class_dev, - char **envp, int num_envp, - char *buffer, int buffer_size) + struct kobj_uevent_env *env) { pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); return 0; @@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj) } } -static struct kobj_type ktype_class_device = { +static struct kobj_type class_device_ktype = { .sysfs_ops = &class_dev_sysfs_ops, .release = class_dev_release, }; @@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_class_device) { + if (ktype == &class_device_ktype) { struct class_device *class_dev = to_class_dev(kobj); if (class_dev->class) return 1; @@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) { } #endif -static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int class_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct class_device *class_dev = to_class_dev(kobj); struct device *dev = class_dev->dev; - int i = 0; - int length = 0; int retval = 0; pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); if (MAJOR(class_dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(class_dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(class_dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); } if (dev) { const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - if (class_dev->uevent) { /* have the class device specific function add its stuff */ - retval = class_dev->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->uevent(class_dev, env); if (retval) pr_debug("class_dev->uevent() returned %d\n", retval); } else if (class_dev->class->uevent) { /* have the class specific function add its stuff */ - retval = class_dev->class->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->class->uevent(class_dev, env); if (retval) pr_debug("class->uevent() returned %d\n", retval); } @@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops); +static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); static int class_device_add_attrs(struct class_device * cd) @@ -883,7 +861,7 @@ int __init classes_init(void) /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ - subsystem_init(&class_obj_subsys); + kset_init(&class_obj_subsys); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6fc236..c1343414d28 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj) } } -static struct kobj_type ktype_device = { +static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, }; @@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_device) { + if (ktype == &device_ktype) { struct device *dev = to_dev(kobj); if (dev->uevent_suppress) return 0; @@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) return NULL; } -static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dev_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct device *dev = to_dev(kobj); - int i = 0; - int length = 0; int retval = 0; /* add the major/minor if present */ if (MAJOR(dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); } if (dev->type && dev->type->name) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVTYPE=%s", dev->type->name); + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DRIVER=%s", dev->driver->name); + add_uevent_var(env, "DRIVER=%s", dev->driver->name); #ifdef CONFIG_SYSFS_DEPRECATED if (dev->class) { @@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, path = kobject_get_path(&parent->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", parent->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); if (parent->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", parent->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + parent->driver->name); } } else if (dev->bus) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } #endif - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - + /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { - /* have the bus specific function add its stuff */ - retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->bus->uevent(dev, env); if (retval) pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); } + /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { - /* have the class specific function add its stuff */ - retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("%s: class uevent() returned %d\n", __FUNCTION__, retval); } + /* have the device type specific fuction add its stuff */ if (dev->type && dev->type->uevent) { - /* have the device type specific fuction add its stuff */ - retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->type->uevent(dev, env); if (retval) pr_debug("%s: dev_type uevent() returned %d\n", __FUNCTION__, retval); @@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, { struct kobject *top_kobj; struct kset *kset; - char *envp[32]; - char *data = NULL; - char *pos; + struct kobj_uevent_env *env = NULL; int i; size_t count = 0; int retval; /* search the kset, the device belongs to */ top_kobj = &dev->kobj; - if (!top_kobj->kset && top_kobj->parent) { - do { - top_kobj = top_kobj->parent; - } while (!top_kobj->kset && top_kobj->parent); - } + while (!top_kobj->kset && top_kobj->parent) + top_kobj = top_kobj->parent; if (!top_kobj->kset) goto out; + kset = top_kobj->kset; if (!kset->uevent_ops || !kset->uevent_ops->uevent) goto out; @@ -278,43 +248,29 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, if (!kset->uevent_ops->filter(kset, &dev->kobj)) goto out; - data = (char *)get_zeroed_page(GFP_KERNEL); - if (!data) + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; /* let the kset specific function add its keys */ - pos = data; - memset(envp, 0, sizeof(envp)); - retval = kset->uevent_ops->uevent(kset, &dev->kobj, - envp, ARRAY_SIZE(envp), - pos, PAGE_SIZE); + retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); if (retval) goto out; /* copy keys to file */ - for (i = 0; envp[i]; i++) { - pos = &buf[count]; - count += sprintf(pos, "%s\n", envp[i]); - } + for (i = 0; i < env->envp_idx; i++) + count += sprintf(&buf[count], "%s\n", env->envp[i]); out: - free_page((unsigned long)data); + kfree(env); return count; } static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - size_t len = count; enum kobject_action action; - if (len && buf[len-1] == '\n') - len--; - - for (action = 0; action < KOBJ_MAX; action++) { - if (strncmp(kobject_actions[action], buf, len) != 0) - continue; - if (kobject_actions[action][len] != '\0') - continue; + if (kobject_action_type(buf, count, &action) == 0) { kobject_uevent(&dev->kobj, action); goto out; } @@ -449,7 +405,7 @@ static struct device_attribute devt_attr = * devices_subsys - structure to be registered with kobject core. */ -decl_subsys(devices, &ktype_device, &device_uevent_ops); +decl_subsys(devices, &device_ktype, &device_uevent_ops); /** diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4e3e3..0295855a3ee 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_dev_release(struct device *dev); -static int firmware_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { struct firmware_priv *fw_priv = dev_get_drvdata(dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "FIRMWARE=%s", fw_priv->fw_id)) + if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "TIMEOUT=%i", loading_timeout)) + if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; - envp[i] = NULL; return 0; } @@ -297,8 +292,7 @@ firmware_class_timeout(u_long data) static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) { - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); + snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); } static int fw_register_device(struct device **dev_p, const char *fw_name, diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b96795d2f..cb99daeae93 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env) { int retval = 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 869ff8c0014..fb560924148 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. - * - * This device will be marked as not supporting hotpluggable drivers; no - * device add/remove uevents will be generated. In the unusual case that - * the device isn't being dynamically allocated as a legacy "probe the - * hardware" driver, infrastructure code should reverse this marking. */ -struct platform_device *platform_device_alloc(const char *name, unsigned int id) +struct platform_device *platform_device_alloc(const char *name, int id) { struct platform_object *pa; @@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; - - /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in - * legacy probe-the-hardware drivers, which don't properly split - * out device enumeration logic from drivers. - */ - pa->pdev.dev.uevent_suppress = 1; } return pa ? &pa->pdev : NULL; @@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, + pdev->id); else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); @@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * the Linux driver model. In particular, when such drivers are built * as modules, they can't be "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, unsigned int id, +struct platform_device *platform_device_register_simple(char *name, int id, struct resource *res, unsigned int num) { struct platform_device *pdev; @@ -530,7 +520,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct platform_device *pdev = to_platform_device(dev); - int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); + int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = { __ATTR_NULL, }; -static int platform_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); + add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 9caeaea753a..a803733c839 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,5 @@ obj-y := shutdown.o -obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o +obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o obj-$(CONFIG_PM_TRACE) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eb9f38d0aa5..0ab4ab21f56 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -20,19 +20,24 @@ */ #include <linux/device.h> +#include <linux/kallsyms.h> #include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/resume-trace.h> +#include "../base.h" #include "power.h" LIST_HEAD(dpm_active); -LIST_HEAD(dpm_off); -LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_off); +static LIST_HEAD(dpm_off_irq); -DEFINE_MUTEX(dpm_mtx); -DEFINE_MUTEX(dpm_list_mtx); +static DEFINE_MUTEX(dpm_mtx); +static DEFINE_MUTEX(dpm_list_mtx); int (*platform_enable_wakeup)(struct device *dev, int is_on); + int device_pm_add(struct device *dev) { int error; @@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev) } +/*------------------------- Resume routines -------------------------*/ + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ + +static int resume_device(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + down(&dev->sem); + + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->bus->resume(dev); + } + + if (!error && dev->type && dev->type->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->type->resume(dev); + } + + if (!error && dev->class && dev->class->resume) { + dev_dbg(dev,"class resume\n"); + error = dev->class->resume(dev); + } + + up(&dev->sem); + + TRACE_RESUME(error); + return error; +} + + +static int resume_device_early(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev,"EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + TRACE_RESUME(error); + return error; +} + +/* + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume + */ +static void dpm_resume(void) +{ + mutex_lock(&dpm_list_mtx); + while(!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.next; + struct device * dev = to_device(entry); + + get_device(dev); + list_move_tail(entry, &dpm_active); + + mutex_unlock(&dpm_list_mtx); + resume_device(dev); + mutex_lock(&dpm_list_mtx); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); +} + + +/** + * device_resume - Restore state of each device in system. + * + * Walk the dpm_off list, remove each entry, resume the device, + * then add it to the dpm_active list. + */ + +void device_resume(void) +{ + might_sleep(); + mutex_lock(&dpm_mtx); + dpm_resume(); + mutex_unlock(&dpm_mtx); +} + +EXPORT_SYMBOL_GPL(device_resume); + + +/** + * dpm_power_up - Power on some devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_active list. + * + * Interrupts must be disabled when calling this. + */ + +static void dpm_power_up(void) +{ + while(!list_empty(&dpm_off_irq)) { + struct list_head * entry = dpm_off_irq.next; + struct device * dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices then devices that required we shut them down + * with interrupts disabled. + * Called with interrupts disabled. + */ + +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} + +EXPORT_SYMBOL_GPL(device_power_up); + + +/*------------------------- Suspend routines -------------------------*/ + +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All list on the suspend path are done in reverse order, so we operate + * on the leaves of the device tree (or forests, depending on how you want + * to look at it ;) first. As nodes are removed from the back of the list, + * they are inserted into the front of their destintation lists. + * + * Things are the reverse on the resume path - iterations are done in + * forward order, and nodes are inserted at the back of their destination + * lists. This way, the ancestors will be accessed before their descendents. + */ + +static inline char *suspend_verb(u32 event) +{ + switch (event) { + case PM_EVENT_SUSPEND: return "suspend"; + case PM_EVENT_FREEZE: return "freeze"; + case PM_EVENT_PRETHAW: return "prethaw"; + default: return "(unknown suspend event)"; + } +} + + +static void +suspend_device_dbg(struct device *dev, pm_message_t state, char *info) +{ + dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), + ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? + ", may wakeup" : ""); +} + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ + +static int suspend_device(struct device * dev, pm_message_t state) +{ + int error = 0; + + down(&dev->sem); + if (dev->power.power_state.event) { + dev_dbg(dev, "PM: suspend %d-->%d\n", + dev->power.power_state.event, state.event); + } + + if (dev->class && dev->class->suspend) { + suspend_device_dbg(dev, state, "class "); + error = dev->class->suspend(dev, state); + suspend_report_result(dev->class->suspend, error); + } + + if (!error && dev->type && dev->type->suspend) { + suspend_device_dbg(dev, state, "type "); + error = dev->type->suspend(dev, state); + suspend_report_result(dev->type->suspend, error); + } + + if (!error && dev->bus && dev->bus->suspend) { + suspend_device_dbg(dev, state, ""); + error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); + } + up(&dev->sem); + return error; +} + + +/* + * This is called with interrupts off, only a single CPU + * running. We can't acquire a mutex or semaphore (and we don't + * need the protection) + */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; + + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_suspend - Save state and stop all devices in system. + * @state: Power state to put each device in. + * + * Walk the dpm_active list, call ->suspend() for each device, and move + * it to the dpm_off list. + * + * (For historical reasons, if it returns -EAGAIN, that used to mean + * that the device would be called again with interrupts disabled. + * These days, we use the "suspend_late()" callback for that, so we + * print a warning and consider it an error). + * + * If we get a different error, try and back out. + * + * If we hit a failure with any of the devices, call device_resume() + * above to bring the suspended devices back to life. + * + */ + +int device_suspend(pm_message_t state) +{ + int error = 0; + + might_sleep(); + mutex_lock(&dpm_mtx); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active) && error == 0) { + struct list_head * entry = dpm_active.prev; + struct device * dev = to_device(entry); + + get_device(dev); + mutex_unlock(&dpm_list_mtx); + + error = suspend_device(dev, state); + + mutex_lock(&dpm_list_mtx); + + /* Check if the device got removed */ + if (!list_empty(&dev->power.entry)) { + /* Move it to the dpm_off list */ + if (!error) + list_move(&dev->power.entry, &dpm_off); + } + if (error) + printk(KERN_ERR "Could not suspend device %s: " + "error %d%s\n", + kobject_name(&dev->kobj), error, + error == -EAGAIN ? " (please convert to suspend_late)" : ""); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + if (error) + dpm_resume(); + + mutex_unlock(&dpm_mtx); + return error; +} + +EXPORT_SYMBOL_GPL(device_suspend); + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Walk the dpm_off_irq list, calling ->power_down() for each device that + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. + */ + +int device_power_down(pm_message_t state) +{ + int error = 0; + struct device * dev; + + while (!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.prev; + + dev = to_device(entry); + error = suspend_device_late(dev, state); + if (error) + goto Error; + list_move(&dev->power.entry, &dpm_off_irq); + } + + error = sysdev_suspend(state); + Done: + return error; + Error: + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", kobject_name(&dev->kobj), error); + dpm_power_up(); + goto Done; +} + +EXPORT_SYMBOL_GPL(device_power_down); + +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8ba0830cbc0..5c4efd493fa 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -11,32 +11,11 @@ extern void device_shutdown(void); * main.c */ -/* - * Used to synchronize global power management operations. - */ -extern struct mutex dpm_mtx; - -/* - * Used to serialize changes to the dpm_* lists. - */ -extern struct mutex dpm_list_mtx; - -/* - * The PM lists. - */ -extern struct list_head dpm_active; -extern struct list_head dpm_off; -extern struct list_head dpm_off_irq; - - -static inline struct dev_pm_info * to_pm_info(struct list_head * entry) -{ - return container_of(entry, struct dev_pm_info, entry); -} +extern struct list_head dpm_active; /* The active device list */ static inline struct device * to_device(struct list_head * entry) { - return container_of(to_pm_info(entry), struct device, power); + return container_of(entry, struct device, power.entry); } extern int device_pm_add(struct device *); @@ -49,19 +28,6 @@ extern void device_pm_remove(struct device *); extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); -/* - * resume.c - */ - -extern void dpm_resume(void); -extern void dpm_power_up(void); -extern int resume_device(struct device *); - -/* - * suspend.c - */ -extern int suspend_device(struct device *, pm_message_t); - #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c deleted file mode 100644 index 00fd84ae6e6..00000000000 --- a/drivers/base/power/resume.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * resume.c - Functions for waking devices up. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include <linux/device.h> -#include <linux/resume-trace.h> -#include "../base.h" -#include "power.h" - - -/** - * resume_device - Restore state for one device. - * @dev: Device. - * - */ - -int resume_device(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - down(&dev->sem); - - if (dev->bus && dev->bus->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->bus->resume(dev); - } - - if (!error && dev->type && dev->type->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->type->resume(dev); - } - - if (!error && dev->class && dev->class->resume) { - dev_dbg(dev,"class resume\n"); - error = dev->class->resume(dev); - } - - up(&dev->sem); - - TRACE_RESUME(error); - return error; -} - - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume - */ -void dpm_resume(void) -{ - mutex_lock(&dpm_list_mtx); - while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); - - mutex_unlock(&dpm_list_mtx); - resume_device(dev); - mutex_lock(&dpm_list_mtx); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); -} - - -/** - * device_resume - Restore state of each device in system. - * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. - */ - -void device_resume(void) -{ - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); - - -/** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. - * - * Interrupts must be disabled when calling this. - */ - -void dpm_power_up(void) -{ - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); - - list_move_tail(entry, &dpm_off); - resume_device_early(dev); - } -} - - -/** - * device_power_up - Turn on all devices that need special attention. - * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. - */ - -void device_power_up(void) -{ - sysdev_resume(); - dpm_power_up(); -} - -EXPORT_SYMBOL_GPL(device_power_up); - - diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c deleted file mode 100644 index 26df9b23173..00000000000 --- a/drivers/base/power/suspend.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * suspend.c - Functions for putting devices to sleep. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include <linux/device.h> -#include <linux/kallsyms.h> -#include <linux/pm.h> -#include "../base.h" -#include "power.h" - -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - -static inline char *suspend_verb(u32 event) -{ - switch (event) { - case PM_EVENT_SUSPEND: return "suspend"; - case PM_EVENT_FREEZE: return "freeze"; - case PM_EVENT_PRETHAW: return "prethaw"; - default: return "(unknown suspend event)"; - } -} - - -static void -suspend_device_dbg(struct device *dev, pm_message_t state, char *info) -{ - dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), - ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? - ", may wakeup" : ""); -} - -/** - * suspend_device - Save state of one device. - * @dev: Device. - * @state: Power state device is entering. - */ - -int suspend_device(struct device * dev, pm_message_t state) -{ - int error = 0; - - down(&dev->sem); - if (dev->power.power_state.event) { - dev_dbg(dev, "PM: suspend %d-->%d\n", - dev->power.power_state.event, state.event); - } - - if (dev->class && dev->class->suspend) { - suspend_device_dbg(dev, state, "class "); - error = dev->class->suspend(dev, state); - suspend_report_result(dev->class->suspend, error); - } - - if (!error && dev->type && dev->type->suspend) { - suspend_device_dbg(dev, state, "type "); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); - } - - if (!error && dev->bus && dev->bus->suspend) { - suspend_device_dbg(dev, state, ""); - error = dev->bus->suspend(dev, state); - suspend_report_result(dev->bus->suspend, error); - } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } - return error; -} - -/** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. - * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. - * - * (For historical reasons, if it returns -EAGAIN, that used to mean - * that the device would be called again with interrupts disabled. - * These days, we use the "suspend_late()" callback for that, so we - * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * - */ - -int device_suspend(pm_message_t state) -{ - int error = 0; - - might_sleep(); - mutex_lock(&dpm_mtx); - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); - - get_device(dev); - mutex_unlock(&dpm_list_mtx); - - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) - printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - - mutex_unlock(&dpm_mtx); - return error; -} - -EXPORT_SYMBOL_GPL(device_suspend); - -/** - * device_power_down - Shut down special devices. - * @state: Power state to enter. - * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. - */ - -int device_power_down(pm_message_t state) -{ - int error = 0; - struct device * dev; - - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; - - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); - } - - error = sysdev_suspend(state); - Done: - return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; -} - -EXPORT_SYMBOL_GPL(device_power_down); - -void __suspend_report_result(const char *function, void *fn, int ret) -{ - if (ret) { - printk(KERN_ERR "%s(): ", function); - print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); - printk("%d\n", ret); - } -} -EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 18febe26caa..ac7ff6d0c6e 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls) kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); cls->kset.kobj.parent = &system_subsys.kobj; - kset_set_kset_s(cls, system_subsys); + cls->kset.kobj.kset = &system_subsys; return kset_register(&cls->kset); } @@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls) EXPORT_SYMBOL_GPL(sysdev_class_register); EXPORT_SYMBOL_GPL(sysdev_class_unregister); - -static LIST_HEAD(sysdev_drivers); static DEFINE_MUTEX(sysdev_drivers_lock); /** * sysdev_driver_register - Register auxillary driver - * @cls: Device class driver belongs to. + * @cls: Device class driver belongs to. * @drv: Driver. * - * If @cls is valid, then @drv is inserted into @cls->drivers to be + * @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount * of @cls is incremented. - * Otherwise, @drv is inserted into sysdev_drivers, and called for - * each device. */ -int sysdev_driver_register(struct sysdev_class * cls, - struct sysdev_driver * drv) +int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) { + int err = 0; + mutex_lock(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); @@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls, list_for_each_entry(dev, &cls->kset.list, kobj.entry) drv->add(dev); } - } else - list_add_tail(&drv->entry, &sysdev_drivers); + } else { + err = -EINVAL; + printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); + WARN_ON(1); + } mutex_unlock(&sysdev_drivers_lock); - return 0; + return err; } @@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev) * code that should have called us. */ - /* Notify global drivers */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->add) - drv->add(sysdev); - } - /* Notify class auxillary drivers */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) @@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev) struct sysdev_driver * drv; mutex_lock(&sysdev_drivers_lock); - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->remove) - drv->remove(sysdev); - } - list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); @@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev) * * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the globals, the auxillaries, + * each driver registered for the device - the auxillaries, * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down @@ -320,13 +309,7 @@ void sysdev_shutdown(void) struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); @@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev) if (drv->resume) drv->resume(dev); } - - /* Call global drivers. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->resume) - drv->resume(dev); - } } /** @@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state) list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto gbl_driver; - } - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state); @@ -436,18 +404,7 @@ aux_driver: if (err_drv->resume) err_drv->resume(sysdev); } - drv = NULL; -gbl_driver: - if (drv) - printk(KERN_ERR "sysdev driver suspend failed for %s\n", - kobject_name(&sysdev->kobj)); - list_for_each_entry(err_drv, &sysdev_drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } /* resume other sysdevs in current class */ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { if (err_dev == sysdev) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4245b7f80a4..ca4d7f0d09b 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE default "4096" help The default value is 4096 kilobytes. Only change this if you know - what are you doing. If you are using IBM S/390, then set this to - 8192. + what are you doing. config BLK_DEV_RAM_BLOCKSIZE int "Default RAM disk block size (bytes)" diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 9b8278e1f4f..acbfe1c49b4 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k"); printk(banner); goto out; @@ -527,7 +527,7 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8d74b8745e6..bd94d5f9e62 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -411,8 +411,8 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, NULL, + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - class_device_create(ip2_class, NULL, + "ipl%d", i); + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); + "stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index c2aa44ee6eb..0246a2b8ce4 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry->dev = dev; mutex_lock(®_list_mutex); - class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); + device_create(ipmi_class, device, dev, "ipmi%d", if_num); list_add(&entry->link, ®_list); mutex_unlock(®_list_mutex); } @@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num) break; } } - class_device_destroy(ipmi_class, dev); + device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); } @@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void) mutex_lock(®_list_mutex); list_for_each_entry_safe(entry, entry2, ®_list, link) { list_del(&entry->link); - class_device_destroy(ipmi_class, entry->dev); + device_destroy(ipmi_class, entry->dev); kfree(entry); } mutex_unlock(®_list_mutex); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 3c66f402f9d..1f27be1ec3d 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void) istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) - class_device_create(istallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), - NULL, "staliomem%d", i); + device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_deinit: @@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void) unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); for (j = 0; j < 4; j++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, - j)); + device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); pci_unregister_driver(&stli_pcidriver); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 62051f8b091..c59e2a0996c 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, - "lp%d", nr); + device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -971,7 +970,7 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); + device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } class_destroy(lp_class); } diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 4177f6db83e..cc5d77797de 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, - "cmm%d", i); + device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i); return 0; } @@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmm_class, MKDEV(major, devno)); + device_destroy(cmm_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index b24a3e7bbb9..a0b9c8728d5 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, - "cmx%d", i); + device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i); return 0; } @@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmx_class, MKDEV(major, devno)); + device_destroy(cmx_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index de14aea34e1..73de77105fe 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +module_param(legacy_count, int, 0); + static void __init legacy_pty_init(void) { + if (legacy_count <= 0) + return; - pty_driver = alloc_tty_driver(NR_PTYS); + pty_driver = alloc_tty_driver(legacy_count); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(NR_PTYS); + pty_slave_driver = alloc_tty_driver(legacy_count); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 1f0d7c60c94..bbfa0e241cb 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = { .owner = THIS_MODULE, }; -static struct cdev raw_cdev = { - .kobj = {.name = "raw", }, - .owner = THIS_MODULE, -}; +static struct cdev raw_cdev; static int __init raw_init(void) { diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 52753e723ea..b9c1dba6bd0 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -441,8 +441,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, NULL, dev, NULL, - "%s", devname); + device_create(snsc_class, NULL, dev, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 4a80b2f864e..45758d5b56e 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void) if (IS_ERR(stallion_class)) printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) - class_device_create(stallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), NULL, - "staliomem%d", i); + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_unrtty: @@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 35b40b99653..cef55c40654 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), port->dev, "par%d", nr); + device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, + TIPAR_MINOR + nr), "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -534,7 +534,7 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); + device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); } class_destroy(tipar_class); diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index f1d60f0cef8..db7a731e236 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), "iseries!vt%d", i); - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), + "iseries!nvt%d", i); printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", i, viotape_unitinfo[i].rsrcname, @@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 993fa7b8925..721f86f4f00 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS If in doubt, say N. -# Note that it is not currently possible to set the other governors (such as ondemand) -# as the default, since if they fail to initialise, cpufreq will be -# left in an undefined state. - choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 @@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE program shall be able to set the CPU dynamically without having to enable the userspace governor manually. +config CPU_FREQ_DEFAULT_GOV_ONDEMAND + bool "ondemand" + select CPU_FREQ_GOV_ONDEMAND + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'ondemand' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the ondemand + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. + +config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE + bool "conservative" + select CPU_FREQ_GOV_CONSERVATIVE + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'conservative' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. endchoice config CPU_FREQ_GOV_PERFORMANCE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c01b7..5e626b12b97 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); + /* Set governor before ->init, so that driver could check it */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ @@ -828,7 +830,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; - strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); + kobject_set_name(&policy->kobj, "cpufreq"); ret = kobject_register(&policy->kobj); if (ret) { @@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) unsigned int ret_freq = 0; if (policy) { - if (unlikely(lock_policy_rwsem_read(cpu))) - return ret_freq; - ret_freq = policy->cur; - - unlock_policy_rwsem_read(cpu); cpufreq_cpu_put(policy); } @@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, { int ret; + /* Only must be defined when default governor is known to have latency + restrictions, like e.g. conservative or ondemand. + That this is the case is already ensured in Kconfig + */ +#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE + struct cpufreq_governor *gov = &cpufreq_gov_performance; +#else + struct cpufreq_governor *gov = NULL; +#endif + + if (policy->governor->max_transition_latency && + policy->cpuinfo.transition_latency > + policy->governor->max_transition_latency) { + if (!gov) + return -EINVAL; + else { + printk(KERN_WARNING "%s governor failed, too long" + " transition latency of HW, fallback" + " to %s governor\n", + policy->governor->name, + gov->name); + policy->governor = gov; + } + } + if (!try_module_get(policy->governor->owner)) return -EINVAL; @@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); -static int cpufreq_cpu_callback(struct notifier_block *nfb, +static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 26f440ccc3f..4bd33ce8a6f 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -58,7 +58,7 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) - return -EINVAL; if (this_dbs_info->enable) /* Already enabled */ break; @@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "conservative", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_conservative = { + .name = "conservative", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_conservative); static int __init cpufreq_gov_dbs_init(void) { - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_conservative); } static void __exit cpufreq_gov_dbs_exit(void) @@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void) /* Make sure that the scheduled work is indeed not running */ flush_scheduled_work(); - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_conservative); } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index e794527e492..369f4459515 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -47,7 +47,7 @@ static unsigned int def_sampling_rate; (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, if ((!cpu_online(cpu)) || (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) { - printk(KERN_WARNING "ondemand governor failed to load " - "due to too long transition latency\n"); - return -EINVAL; - } if (this_dbs_info->enable) /* Already enabled */ break; @@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_ondemand = { + .name = "ondemand", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_ondemand); static int __init cpufreq_gov_dbs_init(void) { @@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void) printk(KERN_ERR "Creation of kondemand failed\n"); return -EFAULT; } - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_ondemand); } static void __exit cpufreq_gov_dbs_exit(void) { - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_ondemand); destroy_workqueue(kondemand_wq); } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 917b9bab9cc..8a45d0f93e2 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } -static void -cpufreq_stats_free_table (unsigned int cpu) +static void __cpuexit cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = cpufreq_stats_table[cpu]; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); @@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, return 0; } -static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) +static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; @@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block cpufreq_stat_cpu_notifier = +static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata = { .notifier_call = cpufreq_stat_cpu_callback, }; @@ -356,8 +356,7 @@ __init cpufreq_stats_init(void) register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_ONLINE, (void *)(long)cpu); + cpufreq_update_policy(cpu); } return 0; } @@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void) CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_DEAD, (void *)(long)cpu); + cpufreq_stats_free_table(cpu); } } MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>"); -MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats" +MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats " "through sysfs filesystem"); MODULE_LICENSE ("GPL"); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4a0576bd06f..3706b2bc098 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = { * /sys/devices/system/edac/mc */ static struct kset mc_kset = { - .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, + .kobj = {.ktype = &ktype_mc_set_attribs }, .ktype = &ktype_mci, }; @@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void) } /* Init the MC's kobject */ + kobject_set_name(&mc_kset.kobj, "mc"); mc_kset.kobj.parent = &edac_class->kset.kobj; /* register the mc_kset */ diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index d944647c82c..4d4a4739390 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } -static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct eisa_device *edev = to_eisa_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); return 0; } diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2b658634163..56681b3b297 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) } static int -fw_unit_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) { struct fw_unit *unit = fw_unit(dev); char modalias[64]; - int length = 0; - int i = 0; get_modalias(unit, modalias, sizeof(modalias)); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", modalias)) + if (add_uevent_var(env, "MODALIAS=%s", modalias)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 59c3b5aa89f..b6e1eb77d14 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -13,21 +13,31 @@ #include <linux/device.h> #include <linux/autoconf.h> -#define DEFINE_DMI_ATTR(_name, _mode, _show) \ -static struct device_attribute sys_dmi_##_name##_attr = \ - __ATTR(_name, _mode, _show, NULL); - -#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ -static ssize_t sys_dmi_##_name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ -{ \ - ssize_t len; \ - len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \ - page[len-1] = '\n'; \ - return len; \ -} \ -DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show); +struct dmi_device_attribute{ + struct device_attribute dev_attr; + int field; +}; +#define to_dmi_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct dmi_device_attribute, dev_attr) + +static ssize_t sys_dmi_field_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + int field = to_dmi_dev_attr(attr)->field; + ssize_t len; + len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field)); + page[len-1] = '\n'; + return len; +} + +#define DMI_ATTR(_name, _mode, _show, _field) \ + { .dev_attr = __ATTR(_name, _mode, _show, NULL), \ + .field = _field } + +#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ +static struct dmi_device_attribute sys_dmi_##_name##_attr = \ + DMI_ATTR(_name, _mode, sys_dmi_field_show, _field); DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR); DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION); @@ -121,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev, return r+1; } -DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show); +static struct device_attribute sys_dmi_modalias_attr = + __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL); static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2]; @@ -134,14 +145,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = { NULL }; -static int dmi_dev_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { - strcpy(buffer, "MODALIAS="); - get_modalias(buffer+9, buffer_size-9); - envp[0] = buffer; - envp[1] = NULL; - + ssize_t len; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = get_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } @@ -157,7 +171,7 @@ static struct device *dmi_dev; #define ADD_DMI_ATTR(_name, _field) \ if (dmi_get_system_info(_field)) \ - sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr; + sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; extern int dmi_available; diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 0fb730ee1da..6942e065e60 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj) kfree(dev); } -static struct kobj_type ktype_edd = { +static struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, .default_attrs = def_attrs, }; -static decl_subsys(edd,&ktype_edd,NULL); +static decl_subsys(edd, &edd_ktype, NULL); /** diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index bfd2d67df68..858a7b95933 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = { NULL, }; -static struct kobj_type ktype_efivar = { +static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, .default_attrs = def_attrs, @@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = { NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &ktype_efivar, NULL); +static decl_subsys(vars, &efivar_ktype, NULL); static decl_subsys(efi, NULL, NULL); /* diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d663e6960d9..910a62de190 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; /* by definition, legacy drivers can't hotplug */ if (dev->driver || !client->driver_name) return 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) return -ENOMEM; - envp[i] = NULL; dev_dbg(dev, "uevent\n"); return 0; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index e96212ce572..a96a8b1b353 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = { __ATTR_NULL }; -static int ide_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) { ide_drive_t *drive = to_ide_device(dev); - int i = 0; - int length = 0; - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MEDIA=%s", media_string(drive)); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DRIVENAME=%s", drive->name); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=ide:m-%s", media_string(drive)); - envp[i] = NULL; + + add_uevent_var(env, "MEDIA=%s", media_string(drive)); + add_uevent_var(env, "DRIVENAME=%s", drive->name); + add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive)); return 0; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2ffd53461db..1939fee616e 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -153,8 +153,7 @@ struct host_info { }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env); static void nodemgr_resume_ne(struct node_entry *ne); static void nodemgr_remove_ne(struct node_entry *ne); static struct node_entry *find_entry_by_guid(u64 guid); @@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { struct unit_directory *ud; - int i = 0; - int length = 0; int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; @@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, #define PUT_ENVP(fmt,val) \ do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &length, \ - fmt, val); \ + retval = add_uevent_var(env, fmt, val); \ if (retval) \ return retval; \ } while (0) @@ -1201,15 +1195,12 @@ do { \ #undef PUT_ENVP - envp[i] = NULL; - return 0; } #else -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 70b77ae6742..3d405068132 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev) kfree(dev); } -static int ib_device_uevent(struct class_device *cdev, char **envp, - int num_envp, char *buf, int size) +static int ib_device_uevent(struct class_device *cdev, + struct kobj_uevent_env *env) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s", dev->name)) + if (add_uevent_var(env, "NAME=%s", dev->name)) return -ENOMEM; /* * It would be nice to pass the node GUID with the event... */ - envp[i] = NULL; return 0; } diff --git a/drivers/input/input.c b/drivers/input/input.c index 5fe75558662..5dc361c954e 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -859,87 +859,66 @@ static void input_dev_release(struct device *device) * Input uevent interface - loading event handlers based on * device bitfields. */ -static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_bm_var(struct kobj_uevent_env *env, const char *name, unsigned long *bitmap, int max) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "%s=", name)) return -ENOMEM; - *cur_len += input_print_bitmap(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - bitmap, max, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_bitmap(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + bitmap, max, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } -static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, struct input_dev *dev) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), - "MODALIAS="); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - *cur_len += input_print_modalias(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - dev, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + dev, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ do { \ - int err = input_add_uevent_bm_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - name, bm, max); \ + int err = input_add_uevent_bm_var(env, name, bm, max); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ do { \ - int err = input_add_uevent_modalias_var(envp, \ - num_envp, &i, \ - buffer, buffer_size, &len, \ - dev); \ + int err = input_add_uevent_modalias_var(env, dev); \ if (err) \ return err; \ } while (0) -static int input_dev_uevent(struct device *device, char **envp, - int num_envp, char *buffer, int buffer_size) +static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct input_dev *dev = to_input_dev(device); - int i = 0; - int len = 0; INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", dev->id.bustype, dev->id.vendor, @@ -971,7 +950,6 @@ static int input_dev_uevent(struct device *device, char **envp, INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); - envp[i] = NULL; return 0; } diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de8..c19f77fbaf2 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -17,17 +17,18 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/platform_device.h> -#include <asm/8253pit.h> #include <asm/io.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcspkr"); #ifdef CONFIG_X86 /* Use the global PIT lock ! */ #include <asm/i8253.h> #else +#include <asm/8253pit.h> static DEFINE_SPINLOCK(i8253_lock); #endif diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 372ca493119..b3bc15acd3f 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #define SERIO_ADD_UEVENT_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { struct serio *serio; - int i = 0; - int len = 0; if (!dev) return -ENODEV; @@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); - envp[i] = NULL; return 0; } @@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf #else -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index b04a178e502..f8b79783c8b 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -20,7 +20,6 @@ #include <linux/isapnp.h> #include <linux/interrupt.h> -extern const char *CardType[]; static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; #define AVM_FRITZ_PCI 1 @@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -#ifdef CONFIG_PCI -static struct pci_dev *dev_avm __devinitdata = NULL; -#endif -#ifdef __ISAPNP__ -static struct pnp_card *pnp_avm_c __devinitdata = NULL; -#endif - -int __devinit -setup_avm_pcipnp(struct IsdnCard *card) +static int __devinit avm_setup_rest(struct IsdnCardState *cs) { u_int val, ver; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, avm_pci_rev); - printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_FRITZPCI) - return (0); - if (card->para[1]) { - /* old manual method */ - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_avm_d = NULL; - if ((pnp_avm_c = pnp_find_card( - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; - - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (!cs->irq) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return(0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } - } - } else { - printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); - } -#endif -#ifdef CONFIG_PCI - if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - if (pci_enable_device(dev_avm)) - return(0); - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ -ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; if (!request_region(cs->hw.avm.cfg_reg, 32, (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], + "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", cs->hw.avm.cfg_reg, cs->hw.avm.cfg_reg + 31); return (0); @@ -860,3 +774,137 @@ ready: ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); return (1); } + +#ifndef __ISAPNP__ + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pnp_card *pnp_avm_c __devinitdata = NULL; + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + struct pnp_dev *pnp_avm_d = NULL; + + if (!isapnp_present()) + return(1); /* no-op: success */ + + if ((pnp_avm_c = pnp_find_card( + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; + + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { + printk(KERN_ERR "FritzPnP:No IRQ\n"); + return(0); + } + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPnP:No IO address\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PNP; + + return (2); /* goto 'ready' label */ + } + } + + return (1); +} + +#endif /* __ISAPNP__ */ + +#ifndef CONFIG_PCI + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pci_dev *dev_avm __devinitdata = NULL; + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { + + if (pci_enable_device(dev_avm)) + return(0); + + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + + cs->irq_flags |= IRQF_SHARED; + + return (1); +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_avm_pcipnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + int rc; + + strcpy(tmp, avm_pci_rev); + printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); + + if (cs->typ != ISDN_CTYPE_FRITZPCI) + return (0); + + if (card->para[1]) { + /* old manual method */ + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->subtyp = AVM_FRITZ_PNP; + goto ready; + } + + rc = avm_pnp_setup(cs); + if (rc < 1) + return (0); + if (rc == 2) + goto ready; + + rc = avm_pci_setup(cs); + if (rc < 1) + return (0); + +ready: + return avm_setup_rest(cs); +} diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 6339bb443f6..99ef3b43fcd 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -20,8 +20,6 @@ #include <linux/pci.h> #include "bkm_ax.h" -#ifdef CONFIG_PCI - #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; @@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0; static u_char pci_device_fn __devinitdata = 0; static u_char pci_irq __devinitdata = 0; -#endif /* CONFIG_PCI */ - int __devinit setup_sct_quadro(struct IsdnCard *card) { -#ifdef CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; u_int found = 0; @@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card) sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); -#else - printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); -#endif /* CONFIG_PCI */ } diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 6eebeb441bf..82674507874 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -25,8 +25,6 @@ #include <linux/pci.h> #include <linux/isapnp.h> -extern const char *CardType[]; - static const char *Diva_revision = "$Revision: 1.33.2.6 $"; #define byteout(addr,val) outb(val,addr) @@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_diva __devinitdata = NULL; -static struct pci_dev *dev_diva_u __devinitdata = NULL; -static struct pci_dev *dev_diva201 __devinitdata = NULL; -static struct pci_dev *dev_diva202 __devinitdata = NULL; - -#ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] __devinitdata = { - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { 0, } -}; - -static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; -static struct pnp_card *pnp_c __devinitdata = NULL; -#endif - - -int __devinit -setup_diva(struct IsdnCard *card) +static int __devinit setup_diva_common(struct IsdnCardState *cs) { - int bytecnt = 8; + int bytecnt; u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Diva_revision); - printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_DIEHLDIVA) - return(0); - cs->hw.diva.status = 0; - if (card->para[1]) { - cs->hw.diva.ctrl_reg = 0; - cs->hw.diva.cfg_reg = card->para[1]; - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - if ((val == 1) || (val==2)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - } - cs->irq = card->para[0]; - } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.diva.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0xA1)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = - card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = - card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_HSCX_ADR; - } - goto ready; - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Diva PnP: no ISAPnP card found\n"); - } - } -#endif -#ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { - if (pci_enable_device(dev_diva)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { - if (pci_enable_device(dev_diva_u)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { - if (pci_enable_device(dev_diva201)) - return(0); - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = dev_diva201->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); - } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { - if (pci_enable_device(dev_diva202)) - return(0); - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = dev_diva202->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); - } else { - printk(KERN_WARNING "Diva: No PCI card found\n"); - return(0); - } - - if (!cs->irq) { - printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - - if (!cs->hw.diva.cfg_reg) { - printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Diva: unable to config DIVA PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI) ) { - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = 0; - cs->hw.diva.hscx = 0; - cs->hw.diva.isac_adr = 0; - cs->hw.diva.hscx_adr = 0; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - bytecnt = 0; - } else { - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - bytecnt = 32; - } - } -#ifdef __ISAPNP__ -ready: -#endif + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) + bytecnt = 8; + else + bytecnt = 32; printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", @@ -1145,7 +933,7 @@ ready: if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { printk(KERN_WARNING "HiSax: %s config port %lx-%lx already in use\n", - CardType[card->typ], + "diva", cs->hw.diva.cfg_reg, cs->hw.diva.cfg_reg + bytecnt); iounmap_diva(cs); @@ -1206,3 +994,290 @@ ready: } return (1); } + +#ifdef CONFIG_ISA + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + if (!card->para[1]) + return (-1); /* card not found; continue search */ + + cs->hw.diva.ctrl_reg = 0; + cs->hw.diva.cfg_reg = card->para[1]; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if ((val == 1) || (val==2)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } + cs->irq = card->para[0]; + + return (1); /* card found */ +} + +#else /* if !CONFIG_ISA */ + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_ISA */ + +#ifdef __ISAPNP__ +static struct isapnp_device_id diva_ids[] __devinitdata = { + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { 0, } +}; + +static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; +static struct pnp_card *pnp_c __devinitdata = NULL; + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return (-1); /* card not found; continue search */ + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.diva.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0xA1)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = + card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = + card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_HSCX_ADR; + } + return (1); /* card found */ + } else { + printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c=NULL; + } + + return (-1); /* card not found; continue search */ +} + +#else /* if !ISAPNP */ + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* ISAPNP */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_diva __devinitdata = NULL; +static struct pci_dev *dev_diva_u __devinitdata = NULL; +static struct pci_dev *dev_diva201 __devinitdata = NULL; +static struct pci_dev *dev_diva202 __devinitdata = NULL; + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { + if (pci_enable_device(dev_diva)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva_u->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return(0); + cs->subtyp = DIVA_IPAC_PCI; + cs->irq = dev_diva201->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); + } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { + if (pci_enable_device(dev_diva202)) + return(0); + cs->subtyp = DIVA_IPACX_PCI; + cs->irq = dev_diva202->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); + } else { + return (-1); /* card not found; continue search */ + } + + if (!cs->irq) { + printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + + if (!cs->hw.diva.cfg_reg) { + printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) { + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = 0; + cs->hw.diva.hscx = 0; + cs->hw.diva.isac_adr = 0; + cs->hw.diva.hscx_adr = 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; + } + + return (1); /* card found */ +} + +#else /* if !CONFIG_PCI */ + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_diva(struct IsdnCard *card) +{ + int rc, have_card = 0; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Diva_revision); + printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_DIEHLDIVA) + return(0); + cs->hw.diva.status = 0; + + rc = setup_diva_isa(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_isapnp(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_pci(card); + if (!rc) + return rc; + if (rc > 0) + have_card = 1; + +ready: + if (!have_card) { + printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n"); + return(0); + } + + return setup_diva_common(card->cs); +} diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index fab3e4ea059..0c1351b2384 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -30,8 +30,6 @@ #include <linux/serial.h> #include <linux/serial_reg.h> -extern const char *CardType[]; - static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; static const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", @@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs) return (CARD_portlist[i]); } -static struct pci_dev *dev_qs1000 __devinitdata = NULL; -static struct pci_dev *dev_qs3000 __devinitdata = NULL; +static int __devinit +setup_elsa_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[0]; + printk(KERN_INFO "Elsa: Microlink IO probing\n"); + if (cs->hw.elsa.base) { + if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, + cs->typ))) { + printk(KERN_WARNING + "Elsa: no Elsa Microlink at %#lx\n", + cs->hw.elsa.base); + return (0); + } + } else + cs->hw.elsa.base = probe_elsa(cs); + + if (!cs->hw.elsa.base) { + printk(KERN_WARNING + "No Elsa Microlink found\n"); + return (0); + } + + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + val = bytein(cs->hw.elsa.cfg); + if (cs->subtyp == ELSA_PC) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; + } else if (cs->subtyp == ELSA_PCC8) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; + } else { + const u_char CARD_IrqTab[8] = + {15, 10, 15, 3, 11, 5, 11, 9}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; + } + val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; + if (val < 3) + val |= 8; + val += 'A' - 3; + if (val == 'B' || val == 'C') + val ^= 1; + if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) + val = 'C'; + printk(KERN_INFO + "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + val, cs->irq); + val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; + if (val) { + printk(KERN_WARNING + "Elsa: Microlink S0 bus power bad\n"); + cs->hw.elsa.status |= ELSA_BAD_PWR; + } + + return (1); +} #ifdef __ISAPNP__ static struct isapnp_device_id elsa_ids[] __devinitdata = { @@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif +#endif /* __ISAPNP__ */ -int __devinit -setup_elsa(struct IsdnCard *card) +static int __devinit +setup_elsa_isapnp(struct IsdnCard *card) { - int bytecnt; - u_char val; struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, Elsa_revision); - printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - cs->hw.elsa.ctrl_reg = 0; - cs->hw.elsa.status = 0; - cs->hw.elsa.MFlag = 0; - cs->subtyp = 0; - if (cs->typ == ISDN_CTYPE_ELSA) { - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, - cs->typ))) { - printk(KERN_WARNING - "Elsa: no Elsa Microlink at %#lx\n", - cs->hw.elsa.base); - return (0); - } - } else - cs->hw.elsa.base = probe_elsa(cs); - if (cs->hw.elsa.base) { - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u_char CARD_IrqTab[8] = - {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) - val = 'C'; - printk(KERN_INFO - "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING - "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - } else { - printk(KERN_WARNING - "No Elsa Microlink found\n"); - return (0); - } - } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { #ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); + if (!card->para[1] && isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - if (ipid->function == ISAPNP_FUNCTION(0x133)) - cs->subtyp = ELSA_QS1000; - else - cs->subtyp = ELSA_QS3000; - break; - } else { - printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); return(0); } + if (ipid->function == ISAPNP_FUNCTION(0x133)) + cs->subtyp = ELSA_QS1000; + else + cs->subtyp = ELSA_QS3000; + break; + } else { + printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); + return(0); } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); - return(0); } + ipid++; + pnp_c=NULL; + } + if (!ipid->card_vendor) { + printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); + return(0); } -#endif - if (card->para[1] && card->para[0]) { - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - if (!cs->subtyp) - cs->subtyp = ELSA_QS1000; - } else { - printk(KERN_ERR "Elsa PnP: no parameter\n"); - } - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) { + } +#endif /* __ISAPNP__ */ + + if (card->para[1] && card->para[0]) { cs->hw.elsa.base = card->para[1]; cs->irq = card->para[0]; - val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - cs->hw.elsa.hscx = cs->hw.elsa.base + 2; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + if (!cs->subtyp) + cs->subtyp = ELSA_QS1000; + } else { + printk(KERN_ERR "Elsa PnP: no parameter\n"); + } + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); + + return (1); +} + +static void __devinit +setup_elsa_pcmcia(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[1]; + cs->irq = card->para[0]; + val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); + if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ + cs->subtyp = ELSA_PCMCIA_IPAC; + cs->hw.elsa.ale = cs->hw.elsa.base + 0; + cs->hw.elsa.isac = cs->hw.elsa.base + 2; + cs->hw.elsa.hscx = cs->hw.elsa.base + 2; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = ELSA_PCMCIA; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + } + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->hw.elsa.ctrl = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); +} + #ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (pci_enable_device(dev_qs1000)) - return(0); - cs->subtyp = ELSA_QS1000PCI; - cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (pci_enable_device(dev_qs3000)) - return(0); - cs->subtyp = ELSA_QS3000PCI; - cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); - } else { - printk(KERN_WARNING "Elsa: No PCI card found\n"); +static struct pci_dev *dev_qs1000 __devinitdata = NULL; +static struct pci_dev *dev_qs3000 __devinitdata = NULL; + +static int __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { + if (pci_enable_device(dev_qs1000)) return(0); - } - if (!cs->irq) { - printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + cs->subtyp = ELSA_QS1000PCI; + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) return(0); - } + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); + } else { + printk(KERN_WARNING "Elsa: No PCI card found\n"); + return(0); + } + if (!cs->irq) { + printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + return(0); + } + + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { + printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); + return(0); + } + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); + } + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx/0x%x IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->hw.elsa.cfg, + cs->irq); + + return (1); +} - if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { - printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); - return(0); - } - if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { - printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); - printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); - printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base +1; - cs->hw.elsa.hscx = cs->hw.elsa.base +1; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); #else - printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n"); - return (0); + +static void __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + return (1); +} #endif /* CONFIG_PCI */ - } else - return (0); + +static int __devinit +setup_elsa_common(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + int bytecnt; switch (cs->subtyp) { case ELSA_PC: @@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card) here, it would fail. */ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { printk(KERN_WARNING - "HiSax: %s config port %#lx-%#lx already in use\n", - CardType[card->typ], + "HiSax: ELSA config port %#lx-%#lx already in use\n", cs->hw.elsa.base, cs->hw.elsa.base + bytecnt); return (0); @@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card) if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { printk(KERN_WARNING - "HiSax: %s pci port %x-%x already in use\n", - CardType[card->typ], + "HiSax: ELSA pci port %x-%x already in use\n", cs->hw.elsa.cfg, cs->hw.elsa.cfg + 0x80); release_region(cs->hw.elsa.base, bytecnt); @@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card) } return (1); } + +int __devinit +setup_elsa(struct IsdnCard *card) +{ + int rc; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Elsa_revision); + printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.elsa.ctrl_reg = 0; + cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; + cs->subtyp = 0; + + if (cs->typ == ISDN_CTYPE_ELSA) { + rc = setup_elsa_isa(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { + rc = setup_elsa_isapnp(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) + setup_elsa_pcmcia(card); + + else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + rc = setup_elsa_pci(card); + if (!rc) + return (0); + + } else + return (0); + + return setup_elsa_common(card); +} diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index ad06f3cc60f..03dfc32166a 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_sedl __devinitdata = NULL; - #ifdef __ISAPNP__ static struct isapnp_device_id sedl_ids[] __devinitdata = { { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), @@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return -1; + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0x2)) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + *bytecnt = 16; + } else { + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } + + return (1); + } else { + printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c = NULL; + } + + printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); + return -1; +} +#else + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + return -1; +} +#endif /* __ISAPNP__ */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_sedl __devinitdata = NULL; + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u16 sub_vendor_id, sub_id; + + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return(0); + cs->irq = dev_sedl->irq; + if (!cs->irq) { + printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); + } else { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + cs->hw.sedl.bus = SEDL_BUS_PCI; + sub_vendor_id = dev_sedl->subsystem_vendor; + sub_id = dev_sedl->subsystem_device; + printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", + sub_vendor_id, sub_id); + printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", + cs->hw.sedl.cfg_reg); + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PCI; + } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = HST_SAPHIR3; + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); + } + + cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + mdelay(2); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + mdelay(10); + + return (1); +} + +#else + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + return (1); +} + +#endif /* CONFIG_PCI */ int __devinit setup_sedlbauer(struct IsdnCard *card) { - int bytecnt, ver, val; + int bytecnt = 8, ver, val, rc; struct IsdnCardState *cs = card->cs; char tmp[64]; - u16 sub_vendor_id, sub_id; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); @@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card) bytecnt = 16; } } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0x2)) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - bytecnt = 16; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } - goto ready; - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); - } - } -#endif -/* Probe for Sedlbauer speed pci */ -#ifdef CONFIG_PCI - if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { - if (pci_enable_device(dev_sedl)) - return(0); - cs->irq = dev_sedl->irq; - if (!cs->irq) { - printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); - } else { - printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.sedl.bus = SEDL_BUS_PCI; - sub_vendor_id = dev_sedl->subsystem_vendor; - sub_id = dev_sedl->subsystem_device; - printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); - printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", - cs->hw.sedl.cfg_reg); - if (sub_id != PCI_SUB_ID_SEDLBAUER) { - printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return(0); - } - if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PCI; - } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = HST_SAPHIR3; - } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; - } else { - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return(0); - } + rc = setup_sedlbauer_isapnp(card, &bytecnt); + if (!rc) + return (0); + if (rc > 0) + goto ready; + + /* Probe for Sedlbauer speed pci */ + rc = setup_sedlbauer_pci(card); + if (!rc) + return (0); + bytecnt = 256; - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - mdelay(10); -#else - printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ } -#ifdef __ISAPNP__ ready: -#endif /* In case of the sedlbauer pcmcia card, this region is in use, * reserved for us by the card manager. So we do not check it diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index d09f6d033f1..4393003ae16 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card) #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif + strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) return (0); -#ifdef CONFIG_PCI + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) return(0); @@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card) printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); } -#else - printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ /* Initialize Zoran PCI controller */ writel(0x00000000, cs->hw.teles0.membase + 0x28); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 3aeceaf9769..39129b94f8b 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card) printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) return (0); -#ifdef CONFIG_PCI + while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, @@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card) cs->hw.w6692.iobase + 255); return (0); } -#else - printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: W6692 unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ printk(KERN_INFO "HiSax: %s config irq:%d I/O:%x\n", diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 9e01748a176..b7cc5c2f08c 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -20,10 +20,15 @@ #include "hysdn_defs.h" static struct pci_device_id hysdn_pci_tbl[] = { - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); @@ -34,128 +39,7 @@ MODULE_LICENSE("GPL"); static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ - -/**********************************************/ -/* table assigning PCI-sub ids to board types */ -/* the last entry contains all 0 */ -/**********************************************/ -static struct { - unsigned short subid; /* PCI sub id */ - unsigned char cardtyp; /* card type assigned */ -} pci_subid_map[] = { - - { - PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO - }, - { - 0, 0 - } /* terminating entry */ -}; - - -/*********************************************************************/ -/* search_cards searches for available cards in the pci config data. */ -/* If a card is found, the card structure is allocated and the cards */ -/* ressources are reserved. cardmax is incremented. */ -/*********************************************************************/ -static void -search_cards(void) -{ - struct pci_dev *akt_pcidev = NULL; - hysdn_card *card, *card_last; - int i; - - card_root = NULL; - card_last = NULL; - while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - akt_pcidev)) != NULL) { - if (pci_enable_device(akt_pcidev)) - continue; - - if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { - printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); - return; - } - card->myid = cardmax; /* set own id */ - card->bus = akt_pcidev->bus->number; - card->devfn = akt_pcidev->devfn; /* slot + function */ - card->subsysid = akt_pcidev->subsystem_device; - card->irq = akt_pcidev->irq; - card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); - card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); - card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); - card->brdtype = BD_NONE; /* unknown */ - card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ - card->faxchans = 0; /* default no fax channels */ - card->bchans = 2; /* and 2 b-channels */ - for (i = 0; pci_subid_map[i].subid; i++) - if (pci_subid_map[i].subid == card->subsysid) { - card->brdtype = pci_subid_map[i].cardtyp; - break; - } - if (card->brdtype != BD_NONE) { - if (ergo_inithardware(card)) { - printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); - kfree(card); - continue; - } - } else { - printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); - kfree(card); /* release mem */ - continue; - } - cardmax++; - card->next = NULL; /*end of chain */ - if (card_last) - card_last->next = card; /* pointer to next card */ - else - card_root = card; - card_last = card; /* new chain end */ - } /* device found */ -} /* search_cards */ - -/************************************************************************************/ -/* free_resources frees the acquired PCI resources and returns the allocated memory */ -/************************************************************************************/ -static void -free_resources(void) -{ - hysdn_card *card; - - while (card_root) { - card = card_root; - if (card->releasehardware) - card->releasehardware(card); /* free all hardware resources */ - card_root = card_root->next; /* remove card from chain */ - kfree(card); /* return mem */ - - } /* while card_root */ -} /* free_resources */ - -/**************************************************************************/ -/* stop_cards disables (hardware resets) all cards and disables interrupt */ -/**************************************************************************/ -static void -stop_cards(void) -{ - hysdn_card *card; - - card = card_root; /* first in chain */ - while (card) { - if (card->stopcard) - card->stopcard(card); - card = card->next; /* remove card from chain */ - } /* while card */ -} /* stop_cards */ +static hysdn_card *card_last = NULL; /* pointer to first card */ /****************************************************************************/ @@ -191,31 +75,138 @@ hysdn_getrev(const char *revision) /* and the module is added to the list in /proc/modules, otherwise an error */ /* is assumed and the module will not be kept in memory. */ /****************************************************************************/ + +static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev, + const struct pci_device_id *ent) +{ + hysdn_card *card; + int rc; + + rc = pci_enable_device(akt_pcidev); + if (rc) + return rc; + + if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { + printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); + rc = -ENOMEM; + goto err_out; + } + card->myid = cardmax; /* set own id */ + card->bus = akt_pcidev->bus->number; + card->devfn = akt_pcidev->devfn; /* slot + function */ + card->subsysid = akt_pcidev->subsystem_device; + card->irq = akt_pcidev->irq; + card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); + card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); + card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); + card->brdtype = BD_NONE; /* unknown */ + card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ + card->faxchans = 0; /* default no fax channels */ + card->bchans = 2; /* and 2 b-channels */ + card->brdtype = ent->driver_data; + + if (ergo_inithardware(card)) { + printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); + rc = -EBUSY; + goto err_out_card; + } + + cardmax++; + card->next = NULL; /*end of chain */ + if (card_last) + card_last->next = card; /* pointer to next card */ + else + card_root = card; + card_last = card; /* new chain end */ + + pci_set_drvdata(akt_pcidev, card); + return 0; + +err_out_card: + kfree(card); +err_out: + pci_disable_device(akt_pcidev); + return rc; +} + +static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev) +{ + hysdn_card *card = pci_get_drvdata(akt_pcidev); + + pci_set_drvdata(akt_pcidev, NULL); + + if (card->stopcard) + card->stopcard(card); + +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_release(card); +#endif + + if (card->releasehardware) + card->releasehardware(card); /* free all hardware resources */ + + if (card == card_root) { + card_root = card_root->next; + if (!card_root) + card_last = NULL; + } else { + hysdn_card *tmp = card_root; + while (tmp) { + if (tmp->next == card) + tmp->next = card->next; + card_last = tmp; + tmp = tmp->next; + } + } + + kfree(card); + pci_disable_device(akt_pcidev); +} + +static struct pci_driver hysdn_pci_driver = { + .name = "hysdn", + .id_table = hysdn_pci_tbl, + .probe = hysdn_pci_init_one, + .remove = __devexit_p(hysdn_pci_remove_one), +}; + +static int hysdn_have_procfs; + static int __init hysdn_init(void) { char tmp[50]; + int rc; strcpy(tmp, hysdn_init_revision); printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); strcpy(tmp, hysdn_net_revision); printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); - search_cards(); + + rc = pci_register_driver(&hysdn_pci_driver); + if (rc) + return rc; + printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); - if (hysdn_procconf_init()) { - free_resources(); /* proc file_sys not created */ - return (-1); - } + if (!hysdn_procconf_init()) + hysdn_have_procfs = 1; + #ifdef CONFIG_HYSDN_CAPI if(cardmax > 0) { if(hycapi_init()) { printk(KERN_ERR "HYCAPI: init failed\n"); - return(-1); + + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + return -ESPIPE; } } #endif /* CONFIG_HYSDN_CAPI */ - return (0); /* no error */ + + return 0; /* no error */ } /* init_module */ @@ -230,20 +221,15 @@ hysdn_init(void) static void __exit hysdn_exit(void) { + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + #ifdef CONFIG_HYSDN_CAPI - hysdn_card *card; -#endif /* CONFIG_HYSDN_CAPI */ - stop_cards(); -#ifdef CONFIG_HYSDN_CAPI - card = card_root; /* first in chain */ - while (card) { - hycapi_capi_release(card); - card = card->next; /* remove card from chain */ - } /* while card */ hycapi_cleanup(); #endif /* CONFIG_HYSDN_CAPI */ - hysdn_procconf_release(); - free_resources(); + printk(KERN_NOTICE "HYSDN: module unloaded\n"); } /* cleanup_module */ diff --git a/drivers/md/md.c b/drivers/md/md.c index e8f102ea9b0..acf1b81b47c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) mddev->gendisk = disk; mutex_unlock(&disks_mutex); mddev->kobj.parent = &disk->kobj; - mddev->kobj.k_name = NULL; - snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); + kobject_set_name(&mddev->kobj, "%s", "md"); mddev->kobj.ktype = &md_ktype; if (kobject_register(&mddev->kobj)) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 56231d8edc0..18738faecbb 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops = .open = dvb_device_open, }; -static struct cdev dvb_device_cdev = { - .kobj = {.name = "dvb", }, - .owner = THIS_MODULE, -}; +static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7a78d6b3473..2ee3c3049e8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct device *cd,char **envp, - int numenvp,char *buf,int size) +static int pvr2_sysfs_hotplug(struct device *d, + struct kobj_uevent_env *env) { /* Even though we don't do anything here, we still need this function because sysfs will still try to call it. */ diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d195fb088f4..8f77949f93d 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv) return 0; } -static int tifm_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env) { struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - int i = 0; - int length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "TIFM_CARD_TYPE=%s", - tifm_media_type_name(sock->type, 1))) + if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1))) return -ENOMEM; return 0; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8d6f6014870..b0c22cad942 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv) } static int -mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, - int buf_size) +mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct mmc_card *card = dev_to_mmc_card(dev); const char *type; - int i = 0, length = 0; + int retval = 0; switch (card->type) { case MMC_TYPE_MMC: @@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, } if (type) { - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_TYPE=%s", type)) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_TYPE=%s", type); + if (retval) + return retval; } - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_NAME=%s", mmc_card_name(card))) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); - envp[i] = NULL; - - return 0; + return retval; } static int mmc_bus_probe(struct device *dev) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 64fbc9759a3..c65d203a846 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); - led_trigger_unregister(host->led); + led_trigger_unregister_simple(host->led); spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d68accea380..78ed633ceb8 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) REG_RD(bp, BNX2_HC_COMMAND); } - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) + if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) + if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) work_done += bnx2_rx_int(bp, budget - work_done); return work_done; @@ -2665,6 +2665,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget) { struct bnx2 *bp = container_of(napi, struct bnx2, napi); int work_done = 0; + struct status_block *sblk = bp->status_blk; while (1) { work_done = bnx2_poll_work(bp, work_done, budget); @@ -2672,16 +2673,19 @@ static int bnx2_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; + /* bp->last_status_idx is used below to tell the hw how + * much work has been processed, so we must read it before + * checking for more work. + */ + bp->last_status_idx = sblk->status_idx; + rmb(); if (likely(!bnx2_has_work(bp))) { - bp->last_status_idx = bp->status_blk->status_idx; - rmb(); - netif_rx_complete(bp->dev, napi); if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; + break; } REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4ac161e1ca1..7d7758f3ad8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ pool_count[i], pool_size[i], pool_active[i]); kobj->parent = &dev->dev.kobj; - sprintf(kobj->name, "pool%d", i); + kobject_set_name(kobj, "pool%d", i); kobj->ktype = &ktype_veth_pool; kobject_register(kobj); } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e795c33b982..30b1cca8144 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) - return 0; + return work_done; } /* run RX thread, within the bounds set by NAPI. @@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3 *tp = container_of(napi, struct tg3, napi); int work_done = 0; + struct tg3_hw_status *sblk = tp->hw_status; while (1) { work_done = tg3_poll_work(tp, work_done, budget); @@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; - if (likely(!tg3_has_work(tp))) { - struct tg3_hw_status *sblk = tp->hw_status; - - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - tp->last_tag = sblk->status_tag; - rmb(); - } else - sblk->status &= ~SD_STATUS_UPDATED; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + /* tp->last_tag is used in tg3_restart_ints() below + * to tell the hw how much work has been processed, + * so we must read it before checking for more work. + */ + tp->last_tag = sblk->status_tag; + rmb(); + } else + sblk->status &= ~SD_STATUS_UPDATED; + if (likely(!tg3_has_work(tp))) { netif_rx_complete(tp->dev, napi); tg3_restart_ints(tp); break; @@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget) return work_done; tx_recovery: + /* work_done is guaranteed to be less than budget. */ netif_rx_complete(tp->dev, napi); schedule_work(&tp->reset_task); - return 0; + return work_done; } static void tg3_irq_quiesce(struct tg3 *tp) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1c97e7dd130..2b5352a7dff 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -3,12 +3,9 @@ #include <linux/module.h> #include "pci.h" -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pci_dev *pdev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp, if (!pdev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_CLASS=%04X", pdev->class)) + if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) + if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SLOT_NAME=%s", pci_name(pdev))) + if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; - - envp[i] = NULL; - return 0; } diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index bd433ef6bfc..f0eba534f80 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -694,66 +694,6 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, if ((slot == NULL) || (info == NULL)) return -ENODEV; - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_power.attr); - if (retval) - return retval; - } - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_attention.attr); - if (retval) - return retval; - } - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_latch.attr); - if (retval) - return retval; - } - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_presence.attr); - if (retval) - return retval; - } - - if ((has_address_file(slot) == 0) && - (slot->info->address != info->address)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_address.attr); - if (retval) - return retval; - } - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); - if (retval) - return retval; - } - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); - if (retval) - return retval; - } - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); return 0; diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index df076064a3e..a080fedf033 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = { }; struct kset dlpar_io_kset = { - .kobj = {.name = DLPAR_KOBJ_NAME, - .ktype = &ktype_dlpar_io, + .kobj = {.ktype = &ktype_dlpar_io, .parent = &pci_hotplug_slots_subsys.kobj}, .ktype = &ktype_dlpar_io, }; int dlpar_sysfs_init(void) { + kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); if (kset_register(&dlpar_io_kset)) { printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - dlpar_io_kset.kobj.name); + kobject_name(&dlpar_io_kset.kobj)); return -EINVAL; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index c43ecedce67..6e2760b6c20 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -531,8 +531,7 @@ void pci_dev_put(struct pci_dev *dev) } #ifndef CONFIG_HOTPLUG -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 5360d73d494..6fda33de84e 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,7 +1,6 @@ /* Functions internal to the PCI core code */ -extern int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 568f1877315..05ca2ed9eb5 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev, dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", - dev->dev.kobj.name, dev->irq); + kobject_name(&dev->dev.kobj), dev->irq); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f8b13f0270d..a0aca46ce87 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int pcmcia_socket_uevent(struct device *dev, + struct kobj_uevent_env *env) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); - int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "SOCKET_NO=%u", s->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", s->sock)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a99607142fc..55baa1f0fcb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_HOTPLUG -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; - int i, length = 0; + int i; u32 hash[4] = { 0, 0, 0, 0}; if (!dev) @@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); } - i = 0; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "SOCKET_NO=%u", - p_dev->socket->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE_NO=%02X", - p_dev->device_no)) + if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" + if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" "pa%08Xpb%08Xpc%08Xpd%08X", p_dev->has_manf_id ? p_dev->manf_id : 0, p_dev->has_card_id ? p_dev->card_id : 0, @@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[3])) return -ENOMEM; - envp[i] = NULL; - return 0; } #else -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 383107ba4bd..f6722ba0dd1 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; - mst_pcmcia_device->dev.uevent_suppress = 0; mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; ret = platform_device_add(mst_pcmcia_device); @@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init); module_exit(mst_pcmcia_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a2daa3f531b..d5c33bd78d6 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; - sharpsl_pcmcia_device->dev.uevent_suppress = 0; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; @@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit); MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index a9880d468ee..f38ba482be7 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -14,8 +14,7 @@ extern int power_supply_create_attrs(struct power_supply *psy); extern void power_supply_remove_attrs(struct power_supply *psy); -extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); #else diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index de3155b2128..249f61bae63 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp) return ret; } -int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) { struct power_supply *psy = dev_get_drvdata(dev); - int i = 0, length = 0, ret = 0, j; + int ret = 0, j; char *prop_buf; char *attrname; @@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_NAME=%s", psy->name); + ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); if (ret) return ret; @@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; @@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; } - envp[i] = NULL; out: free_page((unsigned long)prop_buf); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index aeda5268244..d427daeef51 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -53,6 +53,7 @@ #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/interrupt.h> +#include <linux/log2.h> #include <asm/ccwdev.h> #include <linux/workqueue.h> #include <asm/debug.h> @@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem) static inline int dasd_check_blocksize(int bsize) { - if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0) + if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize)) return -EMEDIUMTYPE; return 0; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0fbacc8b106..f231bc21b1c 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_end_io(bio, 0); + bio_endio(bio, 0); return 0; fail: bio_io_error(bio); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6000bdee408..0e1f35c9ed9 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev) struct raw3215_info *raw; int line; + /* Console is special. */ + if (raw3215[0] && (cdev->dev.driver_data == raw3215[0])) + return 0; raw = kmalloc(sizeof(struct raw3215_info) + RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); if (raw == NULL) diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index fd3479119eb..0b040557db0 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -22,6 +22,7 @@ #include <asm/ebcdic.h> #include "raw3270.h" +#include "tty3270.h" #include "ctrlchar.h" #define CON3270_OUTPUT_BUFFER_SIZE 1024 @@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count) spin_unlock_irqrestore(&cp->view.lock,flags); } -extern struct tty_driver *tty3270_driver; - static struct tty_driver * con3270_device(struct console *c, int *index) { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index fa62e694405..25629b92dec 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t { #define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); +static void __sclp_make_read_req(void); static int sclp_init_mask(int calculate); static int sclp_init(void); @@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb) return 0; } -static inline void __sclp_make_read_req(void); static void __sclp_queue_read_req(void) @@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data) } /* Prepare read event data request. Called while sclp_lock is locked. */ -static inline void -__sclp_make_read_req(void) +static void __sclp_make_read_req(void) { struct sccb_header *sccb; diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9f244c591ee..da25f8e2415 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -708,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device, c_info = &TAPE_3590_CRYPT_INFO(device); - if (sense->masst == MSENSE_UNASSOCIATED) { + DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst); + switch (sense->macst) { + case 0x04: + case 0x05: + case 0x06: tape_med_state_set(device, MS_UNLOADED); TAPE_3590_CRYPT_INFO(device).medium_status = 0; return; - } - if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { - PRINT_ERR("Unknown medium state: %x\n", sense->masst); + case 0x08: + case 0x09: + tape_med_state_set(device, MS_LOADED); + break; + default: + tape_med_state_set(device, MS_UNKNOWN); return; } - tape_med_state_set(device, MS_LOADED); c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; if (sense->flags & MSENSE_CRYPT_MASK) { PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); @@ -835,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) /* Probably result of halt ssch */ return TAPE_IO_PENDING; else if (irb->scsw.dstat == 0x85) - /* Device Ready -> check medium state */ - tape_3590_schedule_work(device, TO_MSEN); - else if (irb->scsw.dstat & DEV_STAT_ATTENTION) + /* Device Ready */ + DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); - else { + } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); tape_dump_sense(device, NULL, irb); } + /* check medium state */ + tape_3590_schedule_work(device, TO_MSEN); return TAPE_IO_SUCCESS; } diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index bc33068b9ce..70b1980a08b 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -25,8 +25,8 @@ #include <asm/ebcdic.h> #include <asm/uaccess.h> - #include "raw3270.h" +#include "tty3270.h" #include "keyboard.h" #define TTY3270_CHAR_BUF_SIZE 256 @@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix) static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy) { - tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx)); - cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy)); + int max_cx = max(0, cx); + int max_cy = max(0, cy); + + tp->cx = min_t(int, tp->view.cols - 1, max_cx); + cy = min_t(int, tp->view.rows - 3, max_cy); if (cy != tp->cy) { tty3270_convert_line(tp, tp->cy); tp->cy = cy; diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h new file mode 100644 index 00000000000..799da57f039 --- /dev/null +++ b/drivers/s390/char/tty3270.h @@ -0,0 +1,16 @@ +/* + * drivers/s390/char/tty3270.h + * + * Copyright IBM Corp. 2007 + * + */ + +#ifndef __DRIVERS_S390_CHAR_TTY3270_H +#define __DRIVERS_S390_CHAR_TTY3270_H + +#include <linux/tty.h> +#include <linux/tty_driver.h> + +extern struct tty_driver *tty3270_driver; + +#endif /* __DRIVERS_S390_CHAR_TTY3270_H */ diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 680b9b58b80..6f40facb1c4 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout, "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "=d" (err) : "d"(__func), "d"(__timeout), - "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc"); + : "+d" (err) : "d"(__func), "d"(__timeout), + "d"(__cmdp), "d"(__cmdl) : "1", "cc"); return err; } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3712ede1672..7073daf7798 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count) if (count == 0) return 0; - flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */ + flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ asm volatile ( "0: mvcle %1,%2,0x0\n" "1: jo 0b\n" " lhi %0,0x0\n" "2:\n" EX_TABLE(1b,2b) - : "+d" (rc) - : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2) + : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), + "+d" (_len2), "=m" (*((long*)dest)) + : "m" (*((long*)src)) : "cc", "memory"); __raw_local_irq_ssm(flags); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5176a..5baa517c3b6 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv) return 0; } static int -ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, - int buffer_size) +ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) { /* TODO */ return 0; @@ -152,16 +151,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) return 0; } -/* - * try to add a new ccwgroup device for one driver - * argc and argv[] are a list of bus_id's of devices - * belonging to the driver. +/** + * ccwgroup_create() - create and register a ccw group device + * @root: parent device for the new device + * @creator_id: identifier of creating driver + * @cdrv: ccw driver of slave devices + * @argc: number of slave devices + * @argv: bus ids of slave devices + * + * Create and register a new ccw group device as a child of @root. Slave + * devices are obtained from the list of bus ids given in @argv[] and must all + * belong to @cdrv. + * Returns: + * %0 on success and an error code on failure. + * Context: + * non-atomic */ -int -ccwgroup_create(struct device *root, - unsigned int creator_id, - struct ccw_driver *cdrv, - int argc, char *argv[]) +int ccwgroup_create(struct device *root, unsigned int creator_id, + struct ccw_driver *cdrv, int argc, char *argv[]) { struct ccwgroup_device *gdev; int i; @@ -390,8 +397,13 @@ static struct bus_type ccwgroup_bus_type = { .remove = ccwgroup_remove, }; -int -ccwgroup_driver_register (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_register() - register a ccw group driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + */ +int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) { /* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; @@ -406,8 +418,13 @@ __ccwgroup_match_all(struct device *dev, void *data) return 1; } -void -ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_unregister() - deregister a ccw group driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) { struct device *dev; @@ -427,8 +444,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) driver_unregister(&cdriver->driver); } -int -ccwgroup_probe_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_probe_ccwdev() - probe function for slave devices + * @cdev: ccw device to be probed + * + * This is a dummy probe function for ccw devices that are slave devices in + * a ccw group device. + * Returns: + * always %0 + */ +int ccwgroup_probe_ccwdev(struct ccw_device *cdev) { return 0; } @@ -452,8 +477,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) return NULL; } -void -ccwgroup_remove_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_remove_ccwdev() - remove function for slave devices + * @cdev: ccw device to be removed + * + * This is a remove function for ccw devices that are slave devices in a ccw + * group device. It sets the ccw device offline and also deregisters the + * embedding ccw group device. + */ +void ccwgroup_remove_ccwdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 920dd71e643..42c1f4659ad 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -14,7 +14,7 @@ #include <linux/jiffies.h> #include <linux/wait.h> #include <linux/mutex.h> -#include <asm/errno.h> +#include <linux/errno.h> #include <asm/chpid.h> #include <asm/sclp.h> @@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue; /* Return channel_path struct for given chpid. */ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) { - return css[chpid.cssid]->chps[chpid.id]; + return channel_subsystems[chpid.cssid]->chps[chpid.id]; } /* Set vary state for given chpid. */ @@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch) opm = 0; chp_id_init(&chpid); - for (i=0; i < 8; i++) { + for (i = 0; i < 8; i++) { opm <<= 1; chpid.id = sch->schib.pmcw.chpid[i]; if (chp_get_status(chpid) != 0) @@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on) sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, chpid.id); - CIO_TRACE_EVENT( 2, dbf_text); + CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); if (!on && !status) { @@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct channel_path *chp; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); if (!chp->cmg_chars) return 0; @@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj, { struct channel_path *chp; struct channel_subsystem *css; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); css = to_css(chp->dev.parent); size = sizeof(struct cmg_entry); @@ -353,7 +357,7 @@ static ssize_t chp_shared_show(struct device *dev, static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); -static struct attribute * chp_attrs[] = { +static struct attribute *chp_attrs[] = { &dev_attr_status.attr, &dev_attr_configure.attr, &dev_attr_type.attr, @@ -395,7 +399,7 @@ int chp_new(struct chp_id chpid) /* fill in status, etc. */ chp->chpid = chpid; chp->state = 1; - chp->dev.parent = &css[chpid.cssid]->device; + chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, chpid.id); @@ -430,18 +434,18 @@ int chp_new(struct chp_id chpid) device_unregister(&chp->dev); goto out_free; } - mutex_lock(&css[chpid.cssid]->mutex); - if (css[chpid.cssid]->cm_enabled) { + mutex_lock(&channel_subsystems[chpid.cssid]->mutex); + if (channel_subsystems[chpid.cssid]->cm_enabled) { ret = chp_add_cmg_attr(chp); if (ret) { sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); device_unregister(&chp->dev); - mutex_unlock(&css[chpid.cssid]->mutex); + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); goto out_free; } } - css[chpid.cssid]->chps[chpid.id] = chp; - mutex_unlock(&css[chpid.cssid]->mutex); + channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); return ret; out_free: kfree(chp); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f2708d65be5..46905345159 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; /* multipath mode */ + /* clean up possible residual cmf stuff */ + sch->schib.pmcw.mme = 0; + sch->schib.pmcw.mbfc = 0; + sch->schib.pmcw.mbi = 0; + sch->schib.mba = 0; return 0; out: if (!cio_is_console(schid)) diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 34a796913b0..b960f66843e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -45,7 +45,8 @@ #include "ioasm.h" #include "chsc.h" -/* parameter to enable cmf during boot, possible uses are: +/* + * parameter to enable cmf during boot, possible uses are: * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be * used on any subchannel * "s390cmf=<num>" -- enable cmf and allocate enough memory to measure @@ -73,18 +74,20 @@ enum cmb_index { * enum cmb_format - types of supported measurement block formats * * @CMF_BASIC: traditional channel measurement blocks supported - * by all machines that we run on + * by all machines that we run on * @CMF_EXTENDED: improved format that was introduced with the z990 - * machine - * @CMF_AUTODETECT: default: use extended format when running on a z990 - * or later machine, otherwise fall back to basic format - **/ + * machine + * @CMF_AUTODETECT: default: use extended format when running on a machine + * supporting extended format, otherwise fall back to + * basic format + */ enum cmb_format { CMF_BASIC, CMF_EXTENDED, CMF_AUTODETECT = -1, }; -/** + +/* * format - actual format for all measurement blocks * * The format module parameter can be set to a value of 0 (zero) @@ -105,20 +108,21 @@ module_param(format, bool, 0444); * either with the help of a special pool or with kmalloc * @free: free memory allocated with @alloc * @set: enable or disable measurement + * @read: read a measurement entry at an index * @readall: read a measurement block in a common format * @reset: clear the data in the associated measurement block and * reset its time stamp * @align: align an allocated block so that the hardware can use it */ struct cmb_operations { - int (*alloc) (struct ccw_device*); - void(*free) (struct ccw_device*); - int (*set) (struct ccw_device*, u32); - u64 (*read) (struct ccw_device*, int); - int (*readall)(struct ccw_device*, struct cmbdata *); - void (*reset) (struct ccw_device*); - void * (*align) (void *); - + int (*alloc) (struct ccw_device *); + void (*free) (struct ccw_device *); + int (*set) (struct ccw_device *, u32); + u64 (*read) (struct ccw_device *, int); + int (*readall)(struct ccw_device *, struct cmbdata *); + void (*reset) (struct ccw_device *); + void *(*align) (void *); +/* private: */ struct attribute_group *attr_group; }; static struct cmb_operations *cmbops; @@ -130,9 +134,11 @@ struct cmb_data { unsigned long long last_update; /* when last_block was updated */ }; -/* our user interface is designed in terms of nanoseconds, +/* + * Our user interface is designed in terms of nanoseconds, * while the hardware measures total times in its own - * unit.*/ + * unit. + */ static inline u64 time_to_nsec(u32 value) { return ((u64)value) * 128000ull; @@ -159,12 +165,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) return ret; } -/* activate or deactivate the channel monitor. When area is NULL, +/* + * Activate or deactivate the channel monitor. When area is NULL, * the monitor is deactivated. The channel monitor needs to * be active in order to measure subchannels, which also need - * to be enabled. */ -static inline void -cmf_activate(void *area, unsigned int onoff) + * to be enabled. + */ +static inline void cmf_activate(void *area, unsigned int onoff) { register void * __gpr2 asm("2"); register long __gpr1 asm("1"); @@ -175,8 +182,8 @@ cmf_activate(void *area, unsigned int onoff) asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); } -static int -set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) +static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, + unsigned long address) { int ret; int retry; @@ -466,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev) * * @mem: pointer to CMBs (only in basic measurement mode) * @list: contains a linked list of all subchannels + * @num_channels: number of channels to be measured * @lock: protect concurrent access to @mem and @list */ struct cmb_area { @@ -481,28 +489,36 @@ static struct cmb_area cmb_area = { .num_channels = 1024, }; - /* ****** old style CMB handling ********/ -/** int maxchannels - * +/* * Basic channel measurement blocks are allocated in one contiguous * block of memory, which can not be moved as long as any channel * is active. Therefore, a maximum number of subchannels needs to * be defined somewhere. This is a module parameter, defaulting to * a resonable value of 1024, or 32 kb of memory. * Current kernels don't allow kmalloc with more than 128kb, so the - * maximum is 4096 + * maximum is 4096. */ module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); /** * struct cmb - basic channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @reserved: unused in basic measurement mode + * + * The measurement block as used by the hardware. The fields are described + * further in z/Architecture Principles of Operation, chapter 17. * - * cmb as used by the hardware the fields are described in z/Architecture - * Principles of Operation, chapter 17. - * The area to be a contiguous array and may not be reallocated or freed. + * The cmb area made up from these blocks must be a contiguous array and may + * not be reallocated or freed. * Only one cmb area can be present in the system. */ struct cmb { @@ -516,8 +532,9 @@ struct cmb { u32 reserved[2]; }; -/* insert a single device into the cmb_area list - * called with cmb_area.lock held from alloc_cmb +/* + * Insert a single device into the cmb_area list. + * Called with cmb_area.lock held from alloc_cmb. */ static int alloc_cmb_single(struct ccw_device *cdev, struct cmb_data *cmb_data) @@ -532,9 +549,11 @@ static int alloc_cmb_single(struct ccw_device *cdev, goto out; } - /* find first unused cmb in cmb_area.mem. - * this is a little tricky: cmb_area.list - * remains sorted by ->cmb->hw_data pointers */ + /* + * Find first unused cmb in cmb_area.mem. + * This is a little tricky: cmb_area.list + * remains sorted by ->cmb->hw_data pointers. + */ cmb = cmb_area.mem; list_for_each_entry(node, &cmb_area.list, cmb_list) { struct cmb_data *data; @@ -558,8 +577,7 @@ out: return ret; } -static int -alloc_cmb (struct ccw_device *cdev) +static int alloc_cmb(struct ccw_device *cdev) { int ret; struct cmb *mem; @@ -670,7 +688,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme) return set_schib_wait(cdev, mme, 0, offset); } -static u64 read_cmb (struct ccw_device *cdev, int index) +static u64 read_cmb(struct ccw_device *cdev, int index) { struct cmb *cmb; u32 val; @@ -720,7 +738,7 @@ out: return ret; } -static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data) { struct cmb *cmb; struct cmb_data *cmb_data; @@ -793,14 +811,25 @@ static struct cmb_operations cmbops_basic = { .align = align_cmb, .attr_group = &cmf_attr_group, }; - + /* ******** extended cmb handling ********/ /** * struct cmbe - extended channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @device_busy_time: time of device busy + * @initial_command_response_time: initial command response time + * @reserved: unused * - * cmb as used by the hardware, may be in any 64 bit physical location, - * the fields are described in z/Architecture Principles of Operation, + * The measurement block as used by the hardware. May be in any 64 bit physical + * location. + * The fields are described further in z/Architecture Principles of Operation, * third edition, chapter 17. */ struct cmbe { @@ -816,10 +845,12 @@ struct cmbe { u32 reserved[7]; }; -/* kmalloc only guarantees 8 byte alignment, but we need cmbe +/* + * kmalloc only guarantees 8 byte alignment, but we need cmbe * pointers to be naturally aligned. Make sure to allocate - * enough space for two cmbes */ -static inline struct cmbe* cmbe_align(struct cmbe *c) + * enough space for two cmbes. + */ +static inline struct cmbe *cmbe_align(struct cmbe *c) { unsigned long addr; addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) & @@ -827,7 +858,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c) return (struct cmbe*)addr; } -static int alloc_cmbe (struct ccw_device *cdev) +static int alloc_cmbe(struct ccw_device *cdev) { struct cmbe *cmbe; struct cmb_data *cmb_data; @@ -873,7 +904,7 @@ out_free: return ret; } -static void free_cmbe (struct ccw_device *cdev) +static void free_cmbe(struct ccw_device *cdev) { struct cmb_data *cmb_data; @@ -912,7 +943,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme) } -static u64 read_cmbe (struct ccw_device *cdev, int index) +static u64 read_cmbe(struct ccw_device *cdev, int index) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -970,7 +1001,7 @@ out: return ret; } -static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -1047,17 +1078,16 @@ static struct cmb_operations cmbops_extended = { .align = align_cmbe, .attr_group = &cmf_attr_group_ext, }; - -static ssize_t -cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) +static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { return sprintf(buf, "%lld\n", (unsigned long long) cmf_read(to_ccwdev(dev), idx)); } -static ssize_t -cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_sample_interval(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ccw_device *cdev; long interval; @@ -1079,8 +1109,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%ld\n", interval); } -static ssize_t -cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_utilization(struct device *dev, + struct device_attribute *attr, + char *buf) { struct cmbdata data; u64 utilization; @@ -1112,14 +1143,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char } #define cmf_attr(name) \ -static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(name, 0444, show_ ## name, NULL); +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(name, 0444, show_##name, NULL); #define cmf_attr_avg(name) \ -static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL); +static ssize_t show_avg_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL); cmf_attr(ssch_rsch_count); cmf_attr(sample_count); @@ -1131,7 +1164,8 @@ cmf_attr_avg(device_active_only_time); cmf_attr_avg(device_busy_time); cmf_attr_avg(initial_command_response_time); -static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL); +static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, + NULL); static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL); static struct attribute *cmf_attributes[] = { @@ -1172,12 +1206,16 @@ static struct attribute_group cmf_attr_group_ext = { .attrs = cmf_attributes_ext, }; -static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0); } -static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c) +static ssize_t cmb_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t c) { struct ccw_device *cdev; int ret; @@ -1202,9 +1240,16 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); -/* enable_cmf/disable_cmf: module interface for cmf (de)activation */ -int -enable_cmf(struct ccw_device *cdev) +/** + * enable_cmf() - switch on the channel measurement for a specific device + * @cdev: The ccw device to be enabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ +int enable_cmf(struct ccw_device *cdev) { int ret; @@ -1225,8 +1270,16 @@ enable_cmf(struct ccw_device *cdev) return ret; } -int -disable_cmf(struct ccw_device *cdev) +/** + * disable_cmf() - switch off the channel measurement for a specific device + * @cdev: The ccw device to be disabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ +int disable_cmf(struct ccw_device *cdev) { int ret; @@ -1238,14 +1291,32 @@ disable_cmf(struct ccw_device *cdev) return ret; } -u64 -cmf_read(struct ccw_device *cdev, int index) +/** + * cmf_read() - read one value from the current channel measurement block + * @cdev: the channel to be read + * @index: the index of the value to be read + * + * Returns the value read or %0 if the value cannot be read. + * + * Context: + * any + */ +u64 cmf_read(struct ccw_device *cdev, int index) { return cmbops->read(cdev, index); } -int -cmf_readall(struct ccw_device *cdev, struct cmbdata *data) +/** + * cmf_readall() - read the current channel measurement block + * @cdev: the channel to be read + * @data: a pointer to a data block that will be filled + * + * Returns %0 on success, a negative error value otherwise. + * + * Context: + * any + */ +int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) { return cmbops->readall(cdev, data); } @@ -1257,15 +1328,16 @@ int cmf_reenable(struct ccw_device *cdev) return cmbops->set(cdev, 2); } -static int __init -init_cmf(void) +static int __init init_cmf(void) { char *format_string; char *detect_string = "parameter"; - /* We cannot really autoprobe this. If the user did not give a parameter, - see if we are running on z990 or up, otherwise fall back to basic mode. */ - + /* + * If the user did not give a parameter, see if we are running on a + * machine supporting extended measurement blocks, otherwise fall back + * to basic mode. + */ if (format == CMF_AUTODETECT) { if (!css_characteristics_avail || !css_general_characteristics.ext_mb) { @@ -1284,7 +1356,7 @@ init_cmf(void) cmbops = &cmbops_basic; break; case CMF_EXTENDED: - format_string = "extended"; + format_string = "extended"; cmbops = &cmbops_extended; break; default: diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5635e656c1a..5d83dd47146 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/list.h> +#include <linux/reboot.h> #include "css.h" #include "cio.h" @@ -27,7 +28,7 @@ int css_init_done = 0; static int need_reprobe = 0; static int max_ssid = 0; -struct channel_subsystem *css[__MAX_CSSID + 1]; +struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; int css_characteristics_avail = 0; @@ -177,7 +178,7 @@ static int css_register_subchannel(struct subchannel *sch) int ret; /* Initialize the subchannel structure */ - sch->dev.parent = &css[0]->device; + sch->dev.parent = &channel_subsystems[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; sch->dev.groups = subch_attr_groups; @@ -606,30 +607,55 @@ static int __init setup_css(int nr) { u32 tod_high; int ret; + struct channel_subsystem *css; - memset(css[nr], 0, sizeof(struct channel_subsystem)); - css[nr]->pseudo_subchannel = - kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL); - if (!css[nr]->pseudo_subchannel) + css = channel_subsystems[nr]; + memset(css, 0, sizeof(struct channel_subsystem)); + css->pseudo_subchannel = + kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL); + if (!css->pseudo_subchannel) return -ENOMEM; - css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device; - css[nr]->pseudo_subchannel->dev.release = css_subchannel_release; - sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct"); - ret = cio_create_sch_lock(css[nr]->pseudo_subchannel); + css->pseudo_subchannel->dev.parent = &css->device; + css->pseudo_subchannel->dev.release = css_subchannel_release; + sprintf(css->pseudo_subchannel->dev.bus_id, "defunct"); + ret = cio_create_sch_lock(css->pseudo_subchannel); if (ret) { - kfree(css[nr]->pseudo_subchannel); + kfree(css->pseudo_subchannel); return ret; } - mutex_init(&css[nr]->mutex); - css[nr]->valid = 1; - css[nr]->cssid = nr; - sprintf(css[nr]->device.bus_id, "css%x", nr); - css[nr]->device.release = channel_subsystem_release; + mutex_init(&css->mutex); + css->valid = 1; + css->cssid = nr; + sprintf(css->device.bus_id, "css%x", nr); + css->device.release = channel_subsystem_release; tod_high = (u32) (get_clock() >> 32); - css_generate_pgid(css[nr], tod_high); + css_generate_pgid(css, tod_high); return 0; } +static int css_reboot_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + int ret, i; + + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + if (css->cm_enabled) + if (chsc_secm(css, 0)) + ret = NOTIFY_BAD; + } + + return ret; +} + +static struct notifier_block css_reboot_notifier = { + .notifier_call = css_reboot_event, +}; + /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the @@ -670,51 +696,63 @@ init_channel_subsystem (void) } /* Setup css structure. */ for (i = 0; i <= __MAX_CSSID; i++) { - css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); - if (!css[i]) { + struct channel_subsystem *css; + + css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); + if (!css) { ret = -ENOMEM; goto out_unregister; } + channel_subsystems[i] = css; ret = setup_css(i); if (ret) goto out_free; - ret = device_register(&css[i]->device); + ret = device_register(&css->device); if (ret) goto out_free_all; if (css_characteristics_avail && css_chsc_characteristics.secm) { - ret = device_create_file(&css[i]->device, + ret = device_create_file(&css->device, &dev_attr_cm_enable); if (ret) goto out_device; } - ret = device_register(&css[i]->pseudo_subchannel->dev); + ret = device_register(&css->pseudo_subchannel->dev); if (ret) goto out_file; } + ret = register_reboot_notifier(&css_reboot_notifier); + if (ret) + goto out_pseudo; css_init_done = 1; ctl_set_bit(6, 28); for_each_subchannel(__init_channel_subsystem, NULL); return 0; +out_pseudo: + device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev); out_file: - device_remove_file(&css[i]->device, &dev_attr_cm_enable); + device_remove_file(&channel_subsystems[i]->device, + &dev_attr_cm_enable); out_device: - device_unregister(&css[i]->device); + device_unregister(&channel_subsystems[i]->device); out_free_all: - kfree(css[i]->pseudo_subchannel->lock); - kfree(css[i]->pseudo_subchannel); + kfree(channel_subsystems[i]->pseudo_subchannel->lock); + kfree(channel_subsystems[i]->pseudo_subchannel); out_free: - kfree(css[i]); + kfree(channel_subsystems[i]); out_unregister: while (i > 0) { + struct channel_subsystem *css; + i--; - device_unregister(&css[i]->pseudo_subchannel->dev); + css = channel_subsystems[i]; + device_unregister(&css->pseudo_subchannel->dev); if (css_characteristics_avail && css_chsc_characteristics.secm) - device_remove_file(&css[i]->device, + device_remove_file(&css->device, &dev_attr_cm_enable); - device_unregister(&css[i]->device); + device_unregister(&css->device); } out_bus: bus_unregister(&css_bus_type); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 5d65e83ca66..81215ef3243 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -167,7 +167,7 @@ struct channel_subsystem { #define to_css(dev) container_of(dev, struct channel_subsystem, device) extern struct bus_type css_bus_type; -extern struct channel_subsystem *css[]; +extern struct channel_subsystem *channel_subsystems[]; /* Some helper functions for disconnected state. */ int device_is_disconnected(struct subchannel *); @@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *); extern struct workqueue_struct *slow_path_wq; -int subchannel_add_files (struct device *); extern struct attribute_group *subch_attr_groups[]; #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92eac8e..7ee57f084a8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -21,6 +21,7 @@ #include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/param.h> /* HZ */ +#include <asm/cmb.h> #include "cio.h" #include "cio_debug.h" @@ -78,49 +79,38 @@ static int snprint_alias(char *buf, size_t size, /* Set up environment variables for ccw device uevent. Return 0 on success, * non-zero otherwise. */ -static int ccw_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); - int i = 0; - int len = 0; int ret; char modalias_buf[30]; /* CU_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_TYPE=%04X", id->cu_type); + ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type); if (ret) return ret; /* CU_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_MODEL=%02X", id->cu_model); + ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model); if (ret) return ret; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_TYPE=%04X", id->dev_type); + ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type); if (ret) return ret; /* DEV_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_MODEL=%02X", id->dev_model); + ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model); if (ret) return ret; /* MODALIAS= */ snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "MODALIAS=%s", modalias_buf); - if (ret) - return ret; - envp[i] = NULL; - return 0; + ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf); + return ret; } struct bus_type ccw_bus_type; @@ -357,8 +347,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) cdev->private->dev_id.devno); } -int -ccw_device_set_offline(struct ccw_device *cdev) +/** + * ccw_device_set_offline() - disable a ccw device for I/O + * @cdev: target ccw device + * + * This function calls the driver's set_offline() function for @cdev, if + * given, and then disables @cdev. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_offline(struct ccw_device *cdev) { int ret; @@ -396,8 +396,19 @@ ccw_device_set_offline(struct ccw_device *cdev) return ret; } -int -ccw_device_set_online(struct ccw_device *cdev) +/** + * ccw_device_set_online() - enable a ccw device for I/O + * @cdev: target ccw device + * + * This function first enables @cdev and then calls the driver's set_online() + * function for @cdev, if given. If set_online() returns an error, @cdev is + * disabled again. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_online(struct ccw_device *cdev) { int ret; @@ -947,8 +958,7 @@ out: wake_up(&ccw_device_init_wq); } -void -ccw_device_call_sch_unregister(struct work_struct *work) +static void ccw_device_call_sch_unregister(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; @@ -1101,6 +1111,7 @@ io_subchannel_probe (struct subchannel *sch) * device, e.g. the console. */ cdev = sch->dev.driver_data; + cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); /* @@ -1326,8 +1337,19 @@ __ccwdev_check_busid(struct device *dev, void *id) } -struct ccw_device * -get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) +/** + * get_ccwdev_by_busid() - obtain device from a bus id + * @cdrv: driver the device is owned by + * @bus_id: bus id of the device to be searched + * + * This function searches all devices owned by @cdrv for a device with a bus + * id matching @bus_id. + * Returns: + * If a match is found, its reference count of the found device is increased + * and it is returned; else %NULL is returned. + */ +struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, + const char *bus_id) { struct device *dev; struct device_driver *drv; @@ -1401,16 +1423,34 @@ ccw_device_remove (struct device *dev) return 0; } +static void ccw_device_shutdown(struct device *dev) +{ + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); + if (cdev->drv && cdev->drv->shutdown) + cdev->drv->shutdown(cdev); + disable_cmf(cdev); +} + struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, .uevent = ccw_uevent, .probe = ccw_device_probe, .remove = ccw_device_remove, + .shutdown = ccw_device_shutdown, }; -int -ccw_driver_register (struct ccw_driver *cdriver) +/** + * ccw_driver_register() - register a ccw driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + * Returns: + * %0 on success and a negative error value on failure. + */ +int ccw_driver_register(struct ccw_driver *cdriver) { struct device_driver *drv = &cdriver->driver; @@ -1420,8 +1460,13 @@ ccw_driver_register (struct ccw_driver *cdriver) return driver_register(drv); } -void -ccw_driver_unregister (struct ccw_driver *cdriver) +/** + * ccw_driver_unregister() - deregister a ccw driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccw_driver_unregister(struct ccw_driver *cdriver) { driver_unregister(&cdriver->driver); } diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index b66338b7657..0d408960043 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); void ccw_device_do_unreg_rereg(struct work_struct *); -void ccw_device_call_sch_unregister(struct work_struct *); void ccw_device_move_to_orphanage(struct work_struct *); int ccw_device_is_orphan(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8633dc53769..8867443b806 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev) if (cdev->private->pgid[last].inf.ps.state1 == SNID_STATE1_RESET) /* No previous pgid found */ - memcpy(&cdev->private->pgid[0], &css[0]->global_pgid, + memcpy(&cdev->private->pgid[0], + &channel_subsystems[0]->global_pgid, sizeof(struct pgid)); else /* Use existing pgid */ @@ -543,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) } -static void -ccw_device_nopath_notify(struct work_struct *work) -{ - struct ccw_device_private *priv; - struct ccw_device *cdev; - struct subchannel *sch; - int ret; - unsigned long flags; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev; - spin_lock_irqsave(cdev->ccwlock, flags); - sch = to_subchannel(cdev->dev.parent); - /* Extra sanity. */ - if (sch->lpm) - goto out_unlock; - if (sch->driver && sch->driver->notify) { - spin_unlock_irqrestore(cdev->ccwlock, flags); - ret = sch->driver->notify(&sch->dev, CIO_NO_PATH); - spin_lock_irqsave(cdev->ccwlock, flags); - } else - ret = 0; - if (!ret) { - if (get_device(&sch->dev)) { - /* Driver doesn't want to keep device. */ - cio_disable_subchannel(sch); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, - &cdev->private->kick_work); - } else - put_device(&sch->dev); - } - } else { - cio_disable_subchannel(sch); - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - } -out_unlock: - spin_unlock_irqrestore(cdev->ccwlock, flags); -} - void ccw_device_verify_done(struct ccw_device *cdev, int err) { @@ -631,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) default: /* Reset oper notify indication after verify error. */ cdev->private->flags.donotify = 0; - if (cdev->online) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else + if (cdev->online) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -690,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err) break; default: cdev->private->flags.donotify = 0; - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -765,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event) } /* - * Handle not operational event while offline. + * Handle not operational event in non-special state. */ -static void -ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) +static void ccw_device_generic_notoper(struct ccw_device *cdev, + enum dev_event dev_event) { struct subchannel *sch; cdev->private->state = DEV_STATE_NOT_OPER; sch = to_subchannel(cdev->dev.parent); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); -} - -/* - * Handle not operational event while online. - */ -static void -ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) -{ - struct subchannel *sch; - int ret; - - sch = to_subchannel(cdev->dev.parent); - if (sch->driver->notify) { - spin_unlock_irq(cdev->ccwlock); - ret = sch->driver->notify(&sch->dev, - sch->lpm ? CIO_GONE : CIO_NO_PATH); - spin_lock_irq(cdev->ccwlock); - } else - ret = 0; - if (ret) { - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - return; - } - cdev->private->state = DEV_STATE_NOT_OPER; - cio_disable_subchannel(sch); - if (sch->schib.scsw.actl != 0) { - // FIXME: not-oper indication to device driver ? - ccw_device_call_handler(cdev); - } - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); + css_schedule_eval(sch->schid); } /* @@ -915,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_TIMEOUT_KILL; return; } - if (ret == -ENODEV) { - struct subchannel *sch; - - sch = to_subchannel(cdev->dev.parent); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - } else if (cdev->handler) + if (ret == -ENODEV) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-ETIMEDOUT)); } @@ -1233,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_SENSE_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, @@ -1245,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_OFFLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_delay_verify, }, [DEV_STATE_ONLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_irq, [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_W4SENSE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_w4sense, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_DISBAND_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_BOXED] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, [DEV_EVENT_VERIFY] = ccw_device_nop, }, /* states to wait for i/o completion before doing something */ [DEV_STATE_CLEAR_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_TIMEOUT_KILL] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 14eba854b15..7fd2dadc329 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -25,6 +25,16 @@ #include "device.h" #include "chp.h" +/** + * ccw_device_set_options_mask() - set some options and unset the rest + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, all flags not specified in @flags + * are cleared. + * Returns: + * %0 on success, -%EINVAL on an invalid flag combination. + */ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) { /* @@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_set_options() - set some options + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, the remainder is left untouched. + * Returns: + * %0 on success, -%EINVAL if an invalid flag combination would ensue. + */ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) { /* @@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_clear_options() - clear some options + * @cdev: device for which the options are to be cleared + * @flags: options to be cleared + * + * All flags specified in @flags are cleared, the remainder is left untouched. + */ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) { cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0; @@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; } -int -ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_clear() - terminate I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_clear() calls csch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags) +/** + * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags) { struct subchannel *sch; int ret; @@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } - -int -ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags, int expires) +/** + * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags, int expires) { int ret; @@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } -int -ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags) +/** + * ccw_device_start() - start a s390 channel program + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, unsigned long flags) { return ccw_device_start_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags); } -int -ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags, - int expires) +/** + * ccw_device_start_timeout() - start a s390 channel program with timeout + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, + unsigned long flags, int expires) { return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags, @@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, } -int -ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_halt() - halt I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_halt() calls hsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_resume(struct ccw_device *cdev) +/** + * ccw_device_resume() - resume channel program execution + * @cdev: target ccw device + * + * ccw_device_resume() calls rsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_resume(struct ccw_device *cdev) { struct subchannel *sch; @@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev) return 1; } -/* - * Search for CIW command in extended sense data. +/** + * ccw_device_get_ciw() - Search for CIW command in extended sense data. + * @cdev: ccw device to inspect + * @ct: command type to look for + * + * During SenseID, command information words (CIWs) describing special + * commands available to the device may have been stored in the extended + * sense data. This function searches for CIWs of a specified command + * type in the extended sense data. + * Returns: + * %NULL if no extended sense data has been stored or if no CIW of the + * specified command type could be found, + * else a pointer to the CIW of the specified command type. */ -struct ciw * -ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) +struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) { int ciw_cnt; @@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) return NULL; } -__u8 -ccw_device_get_path_mask(struct ccw_device *cdev) +/** + * ccw_device_get_path_mask() - get currently available paths + * @cdev: ccw device to be queried + * Returns: + * %0 if no subchannel for the device is available, + * else the mask of currently available paths for the ccw device's subchannel. + */ +__u8 ccw_device_get_path_mask(struct ccw_device *cdev) { struct subchannel *sch; @@ -357,8 +539,7 @@ out_unlock: return ret; } -void * -ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) +void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) { struct subchannel *sch; struct chp_id chpid; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index d8d479876ec..40a3208c7cf 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q) } static void -qdio_outbound_processing(struct qdio_q *q) +qdio_outbound_processing(unsigned long q) { - __qdio_outbound_processing(q); + __qdio_outbound_processing((struct qdio_q *) q); } /************************* INBOUND ROUTINES *******************************/ @@ -1449,9 +1449,10 @@ out: } static void -tiqdio_inbound_processing(struct qdio_q *q) +tiqdio_inbound_processing(unsigned long q) { - __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); + __tiqdio_inbound_processing((struct qdio_q *) q, + atomic_read(&spare_indicator_usecount)); } static void @@ -1494,9 +1495,9 @@ again: } static void -qdio_inbound_processing(struct qdio_q *q) +qdio_inbound_processing(unsigned long q) { - __qdio_inbound_processing(q); + __qdio_inbound_processing((struct qdio_q *) q); } /************************* MAIN ROUTINES *******************************/ @@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->handler=input_handler; q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind; - q->tasklet.data=(unsigned long)q; /* q->is_thinint_q isn't valid at this time, but - * irq_ptr->is_thinint_irq is */ - q->tasklet.func=(void(*)(unsigned long)) - ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: - &qdio_inbound_processing); + * irq_ptr->is_thinint_irq is + */ + if (irq_ptr->is_thinint_irq) + tasklet_init(&q->tasklet, tiqdio_inbound_processing, + (unsigned long) q); + else + tasklet_init(&q->tasklet, qdio_inbound_processing, + (unsigned long) q); /* actually this is not used for inbound queues. yet. */ atomic_set(&q->busy_siga_counter,0); @@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->last_move_ftc=0; q->handler=output_handler; - q->tasklet.data=(unsigned long)q; - q->tasklet.func=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.function=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.data = (long)q; - init_timer(&q->timer); + tasklet_init(&q->tasklet, qdio_outbound_processing, + (unsigned long) q); + setup_timer(&q->timer, qdio_outbound_processing, + (unsigned long) q); atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; @@ -3726,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count #endif /* CONFIG_64BIT */ } } else { - QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n"); + QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n"); return -EINVAL; } return count; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd2201451..67aaff3e668 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * uevent function for AP devices. It sets up a single environment * variable DEV_TYPE which contains the hardware device type. */ -static int ap_uevent (struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); - int retval = 0, length = 0, i = 0; + int retval = 0; if (!ap_dev) return -ENODEV; /* Set up DEV_TYPE environment variable. */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEV_TYPE=%04X", ap_dev->device_type); + retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type); if (retval) return retval; /* Add MODALIAS= */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=ap:t%02X", ap_dev->device_type); + retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type); - envp[i] = NULL; return retval; } @@ -1231,8 +1225,9 @@ static void ap_reset_domain(void) { int i; - for (i = 0; i < AP_DEVICES; i++) - ap_reset_queue(AP_MKQID(i, ap_domain_index)); + if (ap_domain_index != -1) + for (i = 0; i < AP_DEVICES; i++) + ap_reset_queue(AP_MKQID(i, ap_domain_index)); } static void ap_reset_all(void) diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c index 2a9349ad68b..44253fdd413 100644 --- a/drivers/s390/crypto/zcrypt_mono.c +++ b/drivers/s390/crypto/zcrypt_mono.c @@ -45,7 +45,7 @@ /** * The module initialization code. */ -int __init zcrypt_init(void) +static int __init zcrypt_init(void) { int rc; @@ -86,7 +86,7 @@ out: /** * The module termination code. */ -void __exit zcrypt_exit(void) +static void __exit zcrypt_exit(void) { zcrypt_cex2a_exit(); zcrypt_pcixcc_exit(); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 64948788d30..70b9ddc8cf9 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, }; struct { struct type6_hdr hdr; - struct ica_CPRBX cprbx; + struct CPRBX cprbx; } __attribute__((packed)) *msg = ap_msg->message; int rcblen = CEIL4(xcRB->request_control_blk_length); @@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev, } if (service_rc == 8 && service_rs == 770) { PDEBUG("Invalid key length on PCIXCC/CEX2C\n"); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; - return -EAGAIN; + return -EINVAL; } if (service_rc == 8 && service_rs == 783) { PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n"); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } + if (service_rc == 12 && service_rs == 769) { + PDEBUG("Invalid key on PCIXCC/CEX2C\n"); + return -EINVAL; + } PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n", service_rc, service_rs); zdev->online = 0; diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index a78ff307fd1..8cb7d7a6973 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h @@ -28,51 +28,6 @@ #ifndef _ZCRYPT_PCIXCC_H_ #define _ZCRYPT_PCIXCC_H_ -/** - * CPRBX - * Note that all shorts and ints are big-endian. - * All pointer fields are 16 bytes long, and mean nothing. - * - * A request CPRB is followed by a request_parameter_block. - * - * The request (or reply) parameter block is organized thus: - * function code - * VUD block - * key block - */ -struct CPRBX { - unsigned short cprb_len; /* CPRB length 220 */ - unsigned char cprb_ver_id; /* CPRB version id. 0x02 */ - unsigned char pad_000[3]; /* Alignment pad bytes */ - unsigned char func_id[2]; /* function id 0x5432 */ - unsigned char cprb_flags[4]; /* Flags */ - unsigned int req_parml; /* request parameter buffer len */ - unsigned int req_datal; /* request data buffer */ - unsigned int rpl_msgbl; /* reply message block length */ - unsigned int rpld_parml; /* replied parameter block len */ - unsigned int rpl_datal; /* reply data block len */ - unsigned int rpld_datal; /* replied data block len */ - unsigned int req_extbl; /* request extension block len */ - unsigned char pad_001[4]; /* reserved */ - unsigned int rpld_extbl; /* replied extension block len */ - unsigned char req_parmb[16]; /* request parm block 'address' */ - unsigned char req_datab[16]; /* request data block 'address' */ - unsigned char rpl_parmb[16]; /* reply parm block 'address' */ - unsigned char rpl_datab[16]; /* reply data block 'address' */ - unsigned char req_extb[16]; /* request extension block 'addr'*/ - unsigned char rpl_extb[16]; /* reply extension block 'addres'*/ - unsigned short ccp_rtcode; /* server return code */ - unsigned short ccp_rscode; /* server reason code */ - unsigned int mac_data_len; /* Mac Data Length */ - unsigned char logon_id[8]; /* Logon Identifier */ - unsigned char mac_value[8]; /* Mac Value */ - unsigned char mac_content_flgs;/* Mac content flag byte */ - unsigned char pad_002; /* Alignment */ - unsigned short domain; /* Domain */ - unsigned char pad_003[12]; /* Domain masks */ - unsigned char pad_004[36]; /* reserved */ -} __attribute__((packed)); - int zcrypt_pcixcc_init(void); void zcrypt_pcixcc_exit(void); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 1c8f71a5985..c0d1c0eb320 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *); static int zfcp_ccw_set_online(struct ccw_device *); static int zfcp_ccw_set_offline(struct ccw_device *); static int zfcp_ccw_notify(struct ccw_device *, int); -static void zfcp_ccw_shutdown(struct device *); +static void zfcp_ccw_shutdown(struct ccw_device *); static struct ccw_device_id zfcp_ccw_device_id[] = { {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, @@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = { .set_online = zfcp_ccw_set_online, .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, - .driver = { - .shutdown = zfcp_ccw_shutdown, - }, + .shutdown = zfcp_ccw_shutdown, }; MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); @@ -277,12 +275,12 @@ zfcp_ccw_register(void) * Makes sure that QDIO queues are down when the system gets stopped. */ static void -zfcp_ccw_shutdown(struct device *dev) +zfcp_ccw_shutdown(struct ccw_device *cdev) { struct zfcp_adapter *adapter; down(&zfcp_data.config_sema); - adapter = dev_get_drvdata(dev); + adapter = dev_get_drvdata(&cdev->dev); zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); up(&zfcp_data.config_sema); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 5f3212440f6..ffa3bf75694 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <asm/debug.h> #include <linux/ctype.h> +#include <asm/debug.h> #include "zfcp_ext.h" static u32 dbfsize = 4; @@ -35,17 +35,17 @@ static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; - struct timespec xtime; + struct timespec dbftime; int len = 0; stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); sec = stck >> 12; do_div(sec, 1000000); - xtime.tv_sec = sec; + dbftime.tv_sec = sec; stck -= (sec * 1000000) << 12; - xtime.tv_nsec = ((stck * 1000) >> 12); + dbftime.tv_nsec = ((stck * 1000) >> 12); len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n", - label, xtime.tv_sec, xtime.tv_nsec); + label, dbftime.tv_sec, dbftime.tv_nsec); return len; } diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d8cd75ce2d9..16b4418ab25 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); -static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); +static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); @@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, static void zfcp_erp_action_ready(struct zfcp_erp_action *); static int zfcp_erp_action_exists(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *); +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); +static void zfcp_erp_action_to_running(struct zfcp_erp_action *); static void zfcp_erp_memwait_handler(unsigned long); @@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data) * action gets an appropriate flag and will be processed * accordingly */ -void zfcp_erp_timeout_handler(unsigned long data) +static void zfcp_erp_timeout_handler(unsigned long data) { struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; struct zfcp_adapter *adapter = erp_action->adapter; @@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action, return retval; } -static inline int +static int zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) { return @@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) * returns: 0 - successful setup * !0 - failed setup */ -int +static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) { int retval; @@ -3248,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) zfcp_erp_action_dismiss(&unit->erp_action); } -static inline void -zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; @@ -3258,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) list_move(&erp_action->list, &erp_action->adapter->erp_running_head); } -static inline void -zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 34cdce6738a..ede9986d349 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -277,16 +277,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } -static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct scsi_device *sdev = to_scsi_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); return 0; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e84d2159794..bcb8dd5fb0b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0; } -static int spi_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias); - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=%s", spi->modalias); return 0; } diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index ac49b15fa76..516a6400db4 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ -obj-$(CONFIG_USB_ADUTUX) += misc/ -obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ -obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ -obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ -obj-$(CONFIG_USB_CYTHERM) += misc/ -obj-$(CONFIG_USB_EMI26) += misc/ -obj-$(CONFIG_USB_EMI62) += misc/ -obj-$(CONFIG_USB_FTDI_ELAN) += misc/ -obj-$(CONFIG_USB_IDMOUSE) += misc/ -obj-$(CONFIG_USB_LCD) += misc/ -obj-$(CONFIG_USB_LD) += misc/ -obj-$(CONFIG_USB_LED) += misc/ -obj-$(CONFIG_USB_LEGOTOWER) += misc/ -obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ -obj-$(CONFIG_USB_RIO500) += misc/ -obj-$(CONFIG_USB_SISUSBVGA) += misc/ -obj-$(CONFIG_USB_TEST) += misc/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ -obj-$(CONFIG_USB_USS720) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ +obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a73e714288e..a51eeedc18d 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { - dbg("too big transfer requested"); + if (printk_ratelimit()) + usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n", + wbuflen, rbuflen); ret = -ENOMEM; goto fail; } @@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->rcv_done); ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting read urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } @@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->snd_done); ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting write urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); if (ret < 0) { - dbg("sending cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); if (ret < 0) { - dbg("receiving cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret); goto fail; } if (actlen % CMD_PACKET_SIZE || !actlen) { - dbg("response is not a positive multiple of %d: %#x", - CMD_PACKET_SIZE, actlen); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n", + cm, actlen); ret = -EIO; goto fail; } @@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, /* check the return status and copy the data to the output buffer, if needed */ for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { if (rbuf[offb] != cm) { - dbg("wrong cm %#x in response", rbuf[offb]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n", + rbuf[offb], cm); ret = -EIO; goto fail; } if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { - dbg("response failed: %#x", rbuf[offb + 1]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "response to cm %#x failed: %#x\n", + cm, rbuf[offb + 1]); ret = -EIO; goto fail; } @@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); if (l > stride || l > (len - offb) / 2) { - dbg("wrong data length %#x in response", l); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", + cm, l); ret = -EIO; goto cleanup; } while (l--) { offd = le32_to_cpu(buf[offb++]); if (offd >= size) { - dbg("wrong index %#x in response", offd); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n", + offd, cm); ret = -EIO; goto cleanup; } diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index eb0615abff6..8b132c4a503 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, { unsigned char *buffer; struct usbatm_data *usbatm = instance->usbatm; - struct usb_interface *intf; struct usb_device *usb_dev = usbatm->usb_dev; int actual_length; int ret = 0; @@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, goto out; } - if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { + if (!usb_ifnum_to_if(usb_dev, 2)) { ret = -ENODEV; usb_dbg(usbatm, "%s: interface not found!\n", __func__); goto out_free; diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 29807d048b0..389c5b164eb 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2,7 +2,8 @@ * Copyright (c) 2003, 2004 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. * - * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr> + * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr> + * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl> * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -107,18 +108,51 @@ #define uea_info(usb_dev, format,args...) \ dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args) -struct uea_cmvs { +struct intr_pkt; + +/* cmv's from firmware */ +struct uea_cmvs_v1 { u32 address; u16 offset; u32 data; } __attribute__ ((packed)); +struct uea_cmvs_v2 { + u32 group; + u32 address; + u32 offset; + u32 data; +} __attribute__ ((packed)); + +/* information about currently processed cmv */ +struct cmv_dsc_e1 { + u8 function; + u16 idx; + u32 address; + u16 offset; +}; + +struct cmv_dsc_e4 { + u16 function; + u16 offset; + u16 address; + u16 group; +}; + +union cmv_dsc { + struct cmv_dsc_e1 e1; + struct cmv_dsc_e4 e4; +}; + struct uea_softc { struct usb_device *usb_dev; struct usbatm_data *usbatm; int modem_index; unsigned int driver_info; + int annex; +#define ANNEXA 0 +#define ANNEXB 1 int booting; int reset; @@ -127,20 +161,23 @@ struct uea_softc { struct task_struct *kthread; u32 data; - wait_queue_head_t cmv_ack_wait; + u32 data1; + int cmv_ack; + union cmv_dsc cmv_dsc; struct work_struct task; + struct workqueue_struct *work_q; u16 pageno; u16 ovl; const struct firmware *dsp_firm; struct urb *urb_int; - u8 cmv_function; - u16 cmv_idx; - u32 cmv_address; - u16 cmv_offset; + void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); + void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); + int (*stat) (struct uea_softc *); + int (*send_cmvs) (struct uea_softc *); /* keep in sync with eaglectl */ struct uea_stats { @@ -174,10 +211,34 @@ struct uea_softc { #define ELSA_PID_PSTFIRM 0x3350 #define ELSA_PID_PREFIRM 0x3351 +#define ELSA_PID_A_PREFIRM 0x3352 +#define ELSA_PID_A_PSTFIRM 0x3353 +#define ELSA_PID_B_PREFIRM 0x3362 +#define ELSA_PID_B_PSTFIRM 0x3363 + /* - * Sagem USB IDs + * Devolo IDs : pots if (pid & 0x10) */ -#define EAGLE_VID 0x1110 +#define DEVOLO_VID 0x1039 +#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110 +#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111 + +#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100 +#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101 + +#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130 +#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131 + +#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120 +#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121 + +/* + * Reference design USB IDs + */ +#define ANALOG_VID 0x1110 +#define ADI930_PID_PREFIRM 0x9001 +#define ADI930_PID_PSTFIRM 0x9000 + #define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */ #define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */ @@ -187,12 +248,12 @@ struct uea_softc { #define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */ #define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */ -/* - * Eagle III Pid - */ #define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */ #define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */ +#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */ +#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */ + /* * USR USB IDs */ @@ -208,11 +269,15 @@ struct uea_softc { #define PREFIRM 0 #define PSTFIRM (1<<7) +#define AUTO_ANNEX_A (1<<8) +#define AUTO_ANNEX_B (1<<9) + enum { ADI930 = 0, EAGLE_I, EAGLE_II, - EAGLE_III + EAGLE_III, + EAGLE_IV }; /* macros for both struct usb_device_id and struct uea_softc */ @@ -221,15 +286,18 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(usb_dev) \ - (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(x) \ + ((x)->annex & ANNEXB) #define INS_TO_USBDEV(ins) ins->usb_dev #define GET_STATUS(data) \ ((data >> 8) & 0xf) + #define IS_OPERATIONAL(sc) \ - (GET_STATUS(sc->stats.phy.state) == 2) + ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \ + (GET_STATUS(sc->stats.phy.state) == 2) : \ + (sc->stats.phy.state == 7)) /* * Set of macros to handle unaligned data in the firmware blob. @@ -259,7 +327,8 @@ enum { #define UEA_INTR_PIPE 0x04 #define UEA_ISO_DATA_PIPE 0x08 -#define UEA_SET_BLOCK 0x0001 +#define UEA_E1_SET_BLOCK 0x0001 +#define UEA_E4_SET_BLOCK 0x002c #define UEA_SET_MODE 0x0003 #define UEA_SET_2183_DATA 0x0004 #define UEA_SET_TIMEOUT 0x0011 @@ -275,71 +344,179 @@ enum { #define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000) #define UEA_MPRX_MAILBOX (0x3fdf | 0x4000) -/* structure describing a block within a DSP page */ -struct block_info { +/* block information in eagle4 dsp firmware */ +struct block_index { + __le32 PageOffset; + __le32 NotLastBlock; + __le32 dummy; + __le32 PageSize; + __le32 PageAddress; + __le16 dummy1; + __le16 PageNumber; +} __attribute__ ((packed)); + +#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) +#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) + +#define E4_L1_STRING_HEADER 0x10 +#define E4_MAX_PAGE_NUMBER 0x58 +#define E4_NO_SWAPPAGE_HEADERS 0x31 + +/* l1_code is eagle4 dsp firmware format */ +struct l1_code { + u8 string_header[E4_L1_STRING_HEADER]; + u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; + struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; + u8 code [0]; +} __attribute__ ((packed)); + +/* structures describing a block within a DSP page */ +struct block_info_e1 { __le16 wHdr; -#define UEA_BIHDR 0xabcd __le16 wAddress; __le16 wSize; __le16 wOvlOffset; __le16 wOvl; /* overlay */ __le16 wLast; } __attribute__ ((packed)); -#define BLOCK_INFO_SIZE 12 +#define E1_BLOCK_INFO_SIZE 12 + +struct block_info_e4 { + __be16 wHdr; + __u8 bBootPage; + __u8 bPageNumber; + __be32 dwSize; + __be32 dwAddress; + __be16 wReserved; +} __attribute__ ((packed)); +#define E4_BLOCK_INFO_SIZE 14 -/* structure representing a CMV (Configuration and Management Variable) */ -struct cmv { - __le16 wPreamble; -#define PREAMBLE 0x535c - __u8 bDirection; -#define MODEMTOHOST 0x01 -#define HOSTTOMODEM 0x10 - __u8 bFunction; -#define FUNCTION_TYPE(f) ((f) >> 4) -#define MEMACCESS 0x1 -#define ADSLDIRECTIVE 0x7 +#define UEA_BIHDR 0xabcd +#define UEA_RESERVED 0xffff + +/* constants describing cmv type */ +#define E1_PREAMBLE 0x535c +#define E1_MODEMTOHOST 0x01 +#define E1_HOSTTOMODEM 0x10 + +#define E1_MEMACCESS 0x1 +#define E1_ADSLDIRECTIVE 0x7 +#define E1_FUNCTION_TYPE(f) ((f) >> 4) +#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f) + +#define E4_MEMACCESS 0 +#define E4_ADSLDIRECTIVE 0xf +#define E4_FUNCTION_TYPE(f) ((f) >> 8) +#define E4_FUNCTION_SIZE(f) ((f) & 0x0f) +#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f) -#define FUNCTION_SUBTYPE(f) ((f) & 0x0f) /* for MEMACCESS */ -#define REQUESTREAD 0x0 -#define REQUESTWRITE 0x1 -#define REPLYREAD 0x2 -#define REPLYWRITE 0x3 +#define E1_REQUESTREAD 0x0 +#define E1_REQUESTWRITE 0x1 +#define E1_REPLYREAD 0x2 +#define E1_REPLYWRITE 0x3 + +#define E4_REQUESTREAD 0x0 +#define E4_REQUESTWRITE 0x4 +#define E4_REPLYREAD (E4_REQUESTREAD | 1) +#define E4_REPLYWRITE (E4_REQUESTWRITE | 1) + /* for ADSLDIRECTIVE */ -#define KERNELREADY 0x0 -#define MODEMREADY 0x1 +#define E1_KERNELREADY 0x0 +#define E1_MODEMREADY 0x1 -#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) - __le16 wIndex; - __le32 dwSymbolicAddress; -#define MAKESA(a, b, c, d) \ +#define E4_KERNELREADY 0x0 +#define E4_MODEMREADY 0x1 + +#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) +#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf)) + +#define E1_MAKESA(a, b, c, d) \ (((c) & 0xff) << 24 | \ ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) -#define GETSA1(a) ((a >> 8) & 0xff) -#define GETSA2(a) (a & 0xff) -#define GETSA3(a) ((a >> 24) & 0xff) -#define GETSA4(a) ((a >> 16) & 0xff) - -#define SA_CNTL MAKESA('C', 'N', 'T', 'L') -#define SA_DIAG MAKESA('D', 'I', 'A', 'G') -#define SA_INFO MAKESA('I', 'N', 'F', 'O') -#define SA_OPTN MAKESA('O', 'P', 'T', 'N') -#define SA_RATE MAKESA('R', 'A', 'T', 'E') -#define SA_STAT MAKESA('S', 'T', 'A', 'T') + +#define E1_GETSA1(a) ((a >> 8) & 0xff) +#define E1_GETSA2(a) (a & 0xff) +#define E1_GETSA3(a) ((a >> 24) & 0xff) +#define E1_GETSA4(a) ((a >> 16) & 0xff) + +#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L') +#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G') +#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O') +#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N') +#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E') +#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T') + +#define E4_SA_CNTL 1 +#define E4_SA_STAT 2 +#define E4_SA_INFO 3 +#define E4_SA_TEST 4 +#define E4_SA_OPTN 5 +#define E4_SA_RATE 6 +#define E4_SA_DIAG 7 +#define E4_SA_CNFG 8 + +/* structures representing a CMV (Configuration and Management Variable) */ +struct cmv_e1 { + __le16 wPreamble; + __u8 bDirection; + __u8 bFunction; + __le16 wIndex; + __le32 dwSymbolicAddress; __le16 wOffsetAddress; __le32 dwData; } __attribute__ ((packed)); -#define CMV_SIZE 16 -/* structure representing swap information */ -struct swap_info { +struct cmv_e4 { + __be16 wGroup; + __be16 wFunction; + __be16 wOffset; + __be16 wAddress; + __be32 dwData [6]; +} __attribute__ ((packed)); + +/* structures representing swap information */ +struct swap_info_e1 { __u8 bSwapPageNo; __u8 bOvl; /* overlay */ } __attribute__ ((packed)); -/* structure representing interrupt data */ +struct swap_info_e4 { + __u8 bSwapPageNo; +} __attribute__ ((packed)); + +/* structures representing interrupt data */ +#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo +#define e1_bOvl u.e1.s1.swapinfo.bOvl +#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo + +#define INT_LOADSWAPPAGE 0x0001 +#define INT_INCOMINGCMV 0x0002 + +union intr_data_e1 { + struct { + struct swap_info_e1 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e1 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + +union intr_data_e4 { + struct { + struct swap_info_e4 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e4 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + struct intr_pkt { __u8 bType; __u8 bNotification; @@ -347,43 +524,48 @@ struct intr_pkt { __le16 wIndex; __le16 wLength; __le16 wInterrupt; -#define INT_LOADSWAPPAGE 0x0001 -#define INT_INCOMINGCMV 0x0002 union { - struct { - struct swap_info swapinfo; - __le16 wDataSize; - } __attribute__ ((packed)) s1; - - struct { - struct cmv cmv; - __le16 wDataSize; - } __attribute__ ((packed)) s2; - } __attribute__ ((packed)) u; -#define bSwapPageNo u.s1.swapinfo.bSwapPageNo -#define bOvl u.s1.swapinfo.bOvl + union intr_data_e1 e1; + union intr_data_e4 e4; + } u; } __attribute__ ((packed)); -#define INTR_PKT_SIZE 28 + +#define E1_INTR_PKT_SIZE 28 +#define E4_INTR_PKT_SIZE 64 static struct usb_driver uea_driver; static DEFINE_MUTEX(uea_mutex); -static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"}; +static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"}; static int modem_index; static unsigned int debug; -static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; +static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; +static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); -module_param_array(use_iso, bool, NULL, 0644); -MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic"); +module_param_array(altsetting, uint, NULL, 0644); +MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, " + "1=isoc slowest, ... , 8=isoc fastest (default)"); module_param_array(sync_wait, bool, NULL, 0644); MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); MODULE_PARM_DESC(cmv_file, "file name with configuration and management variables"); +module_param_array(annex, uint, NULL, 0644); +MODULE_PARM_DESC(annex, + "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); + +#define uea_wait(sc, cond, timeo) \ +({ \ + int _r = wait_event_interruptible_timeout(sc->sync_q, \ + (cond) || kthread_should_stop(), timeo); \ + if (kthread_should_stop()) \ + _r = -ENODEV; \ + _r; \ +}) #define UPDATE_ATM_STAT(type, val) \ do { \ @@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) case EAGLE_III: fw_name = FW_DIR "eagleIII.fw"; break; + case EAGLE_IV: + fw_name = FW_DIR "eagleIV.fw"; + break; } ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); @@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) /* * Make sure that the DSP code provided is safe to use. */ -static int check_dsp(u8 *dsp, unsigned int len) +static int check_dsp_e1(u8 *dsp, unsigned int len) { u8 pagecount, blockcount; u16 blocksize; @@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len) return 0; } +static int check_dsp_e4(u8 *dsp, int len) +{ + int i; + struct l1_code *p = (struct l1_code *) dsp; + unsigned int sum = p->code - dsp; + + if (len < sum) + return 1; + + if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 && + strcmp("STRATIPHY ANEXB", p->string_header) != 0) + return 1; + + for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) { + struct block_index *blockidx; + u8 blockno = p->page_number_to_block_index[i]; + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + continue; + + do { + u64 l; + + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + return 1; + + blockidx = &p->page_header[blockno++]; + if ((u8 *)(blockidx + 1) - dsp >= len) + return 1; + + if (le16_to_cpu(blockidx->PageNumber) != i) + return 1; + + l = E4_PAGE_BYTES(blockidx->PageSize); + sum += l; + l += le32_to_cpu(blockidx->PageOffset); + if (l > len) + return 1; + + /* zero is zero regardless endianes */ + } while (blockidx->NotLastBlock); + } + + return (sum == len) ? 0 : 1; +} + /* * send data to the idma pipe * */ @@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc) int ret; char *dsp_name; - if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc->usb_dev)) + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (IS_ISDN(sc)) + dsp_name = FW_DIR "DSP4i.bin"; + else + dsp_name = FW_DIR "DSP4p.bin"; + } else if (UEA_CHIP_VERSION(sc) == ADI930) { + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", - dsp_name, ret); + dsp_name, ret); return ret; } - if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size); + else + ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size); + + if (ret) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", dsp_name); release_firmware(sc->dsp_firm); @@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(struct work_struct *work) +static void uea_load_page_e1(struct work_struct *work) { struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; - struct block_info bi; + struct block_info_e1 bi; u8 *p; u8 pagecount, blockcount; @@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work) bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE)) + if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE)) goto bad2; /* send block data through the IDMA pipe */ @@ -735,17 +975,114 @@ bad1: uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } +static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) +{ + struct block_info_e4 bi; + struct block_index *blockidx; + struct l1_code *p = (struct l1_code *) sc->dsp_firm->data; + u8 blockno = p->page_number_to_block_index[pageno]; + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = boot; + bi.bPageNumber = pageno; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + + do { + u8 *blockoffset; + unsigned int blocksize; + + blockidx = &p->page_header[blockno]; + blocksize = E4_PAGE_BYTES(blockidx->PageSize); + blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); + + bi.dwSize = cpu_to_be32(blocksize); + bi.dwAddress = swab32(blockidx->PageAddress); + + uea_dbg(INS_TO_USBDEV(sc), + "sending block %u for DSP page %u size %u adress %x\n", + blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + goto bad; + + /* send block data through the IDMA pipe */ + if (uea_idma_write(sc, blockoffset, blocksize)) + goto bad; + + blockno++; + } while (blockidx->NotLastBlock); + + return; + +bad: + uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno); + return; +} + +static void uea_load_page_e4(struct work_struct *work) +{ + struct uea_softc *sc = container_of(work, struct uea_softc, task); + u8 pageno = sc->pageno; + int i; + struct block_info_e4 bi; + struct l1_code *p; + + uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno); + + /* reload firmware when reboot start and it's loaded already */ + if (pageno == 0 && sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + + if (sc->dsp_firm == NULL && request_dsp(sc) < 0) + return; + + p = (struct l1_code *) sc->dsp_firm->data; + if (pageno >= p->page_header[0].PageNumber) { + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); + return; + } + + if (pageno != 0) { + __uea_load_page_e4(sc, pageno, 0); + return; + } + + uea_dbg(INS_TO_USBDEV(sc), + "sending Main DSP page %u\n", p->page_header[0].PageNumber); + + for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) { + if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize)) + __uea_load_page_e4(sc, i, 1); + } + + uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n"); + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = 0; + bi.bPageNumber = 0xff; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); + bi.dwAddress = swab32(p->page_header[0].PageAddress); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n"); +} + static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; - wake_up(&sc->cmv_ack_wait); + wake_up(&sc->sync_q); } static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, - sc->cmv_ack, ACK_TIMEOUT); + int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT); + sc->cmv_ack = 0; uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", @@ -792,33 +1129,68 @@ static int uea_request(struct uea_softc *sc, return 0; } -static int uea_cmv(struct uea_softc *sc, +static int uea_cmv_e1(struct uea_softc *sc, u8 function, u32 address, u16 offset, u32 data) { - struct cmv cmv; + struct cmv_e1 cmv; int ret; uea_enters(INS_TO_USBDEV(sc)); uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " "offset : 0x%04x, data : 0x%08x\n", - FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), - GETSA1(address), GETSA2(address), GETSA3(address), - GETSA4(address), offset, data); + E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function), + E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address), + E1_GETSA4(address), offset, data); + /* we send a request, but we expect a reply */ - sc->cmv_function = function | 0x2; - sc->cmv_idx++; - sc->cmv_address = address; - sc->cmv_offset = offset; + sc->cmv_dsc.e1.function = function | 0x2; + sc->cmv_dsc.e1.idx++; + sc->cmv_dsc.e1.address = address; + sc->cmv_dsc.e1.offset = offset; - cmv.wPreamble = cpu_to_le16(PREAMBLE); - cmv.bDirection = HOSTTOMODEM; + cmv.wPreamble = cpu_to_le16(E1_PREAMBLE); + cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; - cmv.wIndex = cpu_to_le16(sc->cmv_idx); + cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); - ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); + ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); + if (ret < 0) + return ret; + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; +} + +static int uea_cmv_e4(struct uea_softc *sc, + u16 function, u16 group, u16 address, u16 offset, u32 data) +{ + struct cmv_e4 cmv; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + memset(&cmv, 0, sizeof(cmv)); + + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, " + "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n", + E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function), + group, address, offset, data); + + /* we send a request, but we expect a reply */ + sc->cmv_dsc.e4.function = function | (0x1 << 4); + sc->cmv_dsc.e4.offset = offset; + sc->cmv_dsc.e4.address = address; + sc->cmv_dsc.e4.group = group; + + cmv.wFunction = cpu_to_be16(function); + cmv.wGroup = cpu_to_be16(group); + cmv.wAddress = cpu_to_be16(address); + cmv.wOffset = cpu_to_be16(offset); + cmv.dwData[0] = cpu_to_be32(data); + + ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) return ret; ret = wait_cmv_ack(sc); @@ -826,10 +1198,10 @@ static int uea_cmv(struct uea_softc *sc, return ret; } -static inline int uea_read_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 *data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD), address, offset, 0); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc, return ret; } -static inline int uea_write_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 *data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size), + group, address, offset, 0); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "reading cmv failed with error %d\n", ret); + else { + *data = sc->data; + /* size is in 16-bit word quantities */ + if (size > 2) + *(data + 1) = sc->data1; + } + return ret; +} + +static inline int uea_write_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE), address, offset, data); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc, return ret; } +static inline int uea_write_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size), + group, address, offset, data); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "writing cmv failed with error %d\n", ret); + + return ret; +} + +static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) +{ + int ret; + u16 timeout; + + /* in bulk mode the modem have problem with high rate + * changing internal timing could improve things, but the + * value is misterious. + * ADI930 don't support it (-EPIPE error). + */ + + if (UEA_CHIP_VERSION(sc) == ADI930 || + altsetting[sc->modem_index] > 0 || + sc->stats.phy.dsrate == dsrate) + return; + + /* Original timming (1Mbit/s) from ADI (used in windows driver) */ + timeout = (dsrate <= 1024*1024) ? 0 : 1; + ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", + timeout, ret < 0 ? " failed" : ""); + +} + /* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed) */ -static int uea_stat(struct uea_softc *sc) +static int uea_stat_e1(struct uea_softc *sc) { u32 data; int ret; @@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); data = sc->stats.phy.state; - ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state); + ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state); if (ret < 0) return ret; @@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc) case 3: /* fail ... */ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" - " (may be try other cmv/dsp)\n"); + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc) /* wake up processes waiting for synchronization */ wake_up(&sc->sync_q); - ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags); if (ret < 0) return ret; sc->stats.phy.mflags |= sc->stats.phy.flags; @@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc) return 0; } - ret = uea_read_cmv(sc, SA_RATE, 0, &data); + ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); if (ret < 0) return ret; - /* in bulk mode the modem have problem with high rate - * changing internal timing could improve things, but the - * value is misterious. - * ADI930 don't support it (-EPIPE error). - */ - if (UEA_CHIP_VERSION(sc) != ADI930 - && !use_iso[sc->modem_index] - && sc->stats.phy.dsrate != (data >> 16) * 32) { - /* Original timming from ADI(used in windows driver) - * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits - */ - u16 timeout = (data <= 0x20ffff) ? 0 : 1; - ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); - uea_info(INS_TO_USBDEV(sc), - "setting new timeout %d%s\n", timeout, - ret < 0?" failed":""); - } + uea_set_bulk_timeout(sc, (data >> 16) * 32); sc->stats.phy.dsrate = (data >> 16) * 32; sc->stats.phy.usrate = (data & 0xffff) * 32; UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - ret = uea_read_cmv(sc, SA_DIAG, 23, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data); if (ret < 0) return ret; sc->stats.phy.dsattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 47, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data); if (ret < 0) return ret; sc->stats.phy.usattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe); if (ret < 0) return ret; return 0; } -static int request_cmvs(struct uea_softc *sc, - struct uea_cmvs **cmvs, const struct firmware **fw) +static int uea_stat_e4(struct uea_softc *sc) { - int ret, size; - u8 *data; + u32 data; + u32 tmp_arr[2]; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + data = sc->stats.phy.state; + + /* XXX only need to be done before operationnal... */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state); + if (ret < 0) + return ret; + + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n"); + return 0; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); + return 0; + case 0x2: /* fail ... */ + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); + return -EAGAIN; + case 0x7: /* operational */ + break; + default: + uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state); + return 0; + } + + if (data != 7) { + uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "modem operational\n"); + + /* release the dsp firmware as it is not needed until + * the next failure + */ + if (sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + } + + /* always update it as atm layer could not be init when we switch to + * operational state + */ + UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND); + + /* wake up processes waiting for synchronization */ + wake_up(&sc->sync_q); + + /* TODO improve this state machine : + * we need some CMV info : what they do and their unit + * we should find the equivalent of eagle3- CMV + */ + /* check flags */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags); + if (ret < 0) + return ret; + sc->stats.phy.mflags |= sc->stats.phy.flags; + + /* in case of a flags ( for example delineation LOSS (& 0x10)), + * we check the status again in order to detect the failure earlier + */ + if (sc->stats.phy.flags) { + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", + sc->stats.phy.flags); + if (sc->stats.phy.flags & 1) //delineation LOSS + return -EAGAIN; + if (sc->stats.phy.flags & 0x4000) //Reset Flag + return -EAGAIN; + return 0; + } + + /* rate data may be in upper or lower half of 64 bit word, strange */ + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + sc->stats.phy.usrate = data / 1000; + + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + uea_set_bulk_timeout(sc, data / 1000); + sc->stats.phy.dsrate = data / 1000; + UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.usattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsmargin = data / 2; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.usmargin = data / 10; + + return 0; +} + +static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) +{ + char file_arr[] = "CMVxy.bin"; char *file; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + /* set proper name corresponding modem version and line type */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; + file_arr[3] = '9'; + else if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + file_arr[3] = '4'; else - file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; + file_arr[3] = 'e'; + + file_arr[4] = IS_ISDN(sc) ? 'i' : 'p'; + file = file_arr; } else file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, sizeof(cmv_name)); + strlcat(cmv_name, file, FIRMWARE_NAME_MAX); + if (ver == 2) + strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX); +} + +static int request_cmvs_old(struct uea_softc *sc, + void **cmvs, const struct firmware **fw) +{ + int ret, size; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + cmvs_file_name(sc, cmv_name, 1); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), @@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc, } data = (u8 *) (*fw)->data; - size = *data * sizeof(struct uea_cmvs) + 1; - if (size != (*fw)->size) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - cmv_name); - release_firmware(*fw); - return -EILSEQ; + size = (*fw)->size; + if (size < 1) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v1) + 1) + goto err_fw_corrupted; + + *cmvs = (void *)(data + 1); + return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int request_cmvs(struct uea_softc *sc, + void **cmvs, const struct firmware **fw, int *ver) +{ + int ret, size; + u32 crc; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + + cmvs_file_name(sc, cmv_name, 2); + ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); + if (ret < 0) { + /* if caller can handle old version, try to provide it */ + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, " + "try to get older cmvs\n", cmv_name); + return request_cmvs_old(sc, cmvs, fw); + } + uea_err(INS_TO_USBDEV(sc), + "requesting firmware %s failed with error %d\n", + cmv_name, ret); + return ret; + } + + size = (*fw)->size; + data = (u8 *) (*fw)->data; + if (size < 4 || strncmp(data, "cmv2", 4) != 0) { + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, " + "try to get older cmvs\n", cmv_name); + release_firmware(*fw); + return request_cmvs_old(sc, cmvs, fw); + } + goto err_fw_corrupted; } - *cmvs = (struct uea_cmvs *)(data + 1); + *ver = 2; + + data += 4; + size -= 4; + if (size < 5) + goto err_fw_corrupted; + + crc = FW_GET_LONG(data); + data += 4; + size -= 4; + if (crc32_be(0, data, size) != crc) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v2) + 1) + goto err_fw_corrupted; + + *cmvs = (void *) (data + 1); return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int uea_send_cmvs_e1(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 1; // we can handle v1 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 1) { + struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr; + + uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, " + "please update your firmware\n"); + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), + FW_GET_WORD(&cmvs_v1[i].offset), + FW_GET_LONG(&cmvs_v1[i].data)); + if (ret < 0) + goto out; + } + } else if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), + (u16) FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; +} + +static int uea_send_cmvs_e4(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 2; // we can only handle v2 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + /* XXX don't read the 3th byte as it is always 6 */ + ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e4(sc, 1, + FW_GET_LONG(&cmvs_v2[i].group), + FW_GET_LONG(&cmvs_v2[i].address), + FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; } /* Start boot post firmware modem: @@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc, static int uea_start_reset(struct uea_softc *sc) { u16 zero = 0; /* ;-) */ - int i, len, ret; - struct uea_cmvs *cmvs; - const struct firmware *cmvs_fw; + int ret; uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); @@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); /* original driver use 200ms, but windows driver use 100ms */ - msleep(100); + ret = uea_wait(sc, 0, msecs_to_jiffies(100)); + if (ret < 0) + return ret; /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); - /* clear tx and rx mailboxes */ - uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { + /* clear tx and rx mailboxes */ + uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + } + + ret = uea_wait(sc, 0, msecs_to_jiffies(1000)); + if (ret < 0) + return ret; + + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); + else + sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY); - msleep(1000); - sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); /* demask interrupt */ sc->booting = 0; /* start loading DSP */ sc->pageno = 0; sc->ovl = 0; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); /* wait for modem ready CMV */ ret = wait_cmv_ack(sc); @@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc) uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 1); - if (ret < 0) - return ret; - - /* Dump firmware version */ - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); + ret = sc->send_cmvs(sc); if (ret < 0) return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - /* get options */ - ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); - if (ret < 0) - return ret; - - /* send options */ - for (i = 0; i < len; i++) { - ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address), - FW_GET_WORD(&cmvs[i].offset), - FW_GET_LONG(&cmvs[i].data)); - if (ret < 0) - goto out; - } - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "Modem started, " - "waiting synchronization\n"); -out: - release_firmware(cmvs_fw); sc->reset = 0; uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1174,12 +1879,10 @@ static int uea_kthread(void *data) if (ret < 0 || sc->reset) ret = uea_start_reset(sc); if (!ret) - ret = uea_stat(sc); + ret = sc->stat(sc); if (ret != -EAGAIN) - msleep_interruptible(1000); - if (try_to_freeze()) - uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " - "please unplug/replug your modem\n"); + uea_wait(sc, 0, msecs_to_jiffies(1000)); + try_to_freeze(); } uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc) if (ret < 0) uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret); - err1: release_firmware(fw_entry); err0: @@ -1243,40 +1945,41 @@ err0: } /* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) +static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) { + struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1; + struct cmv_e1 *cmv = &intr->u.e1.s2.cmv; + uea_enters(INS_TO_USBDEV(sc)); - if (le16_to_cpu(cmv->wPreamble) != PREAMBLE) + if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE) goto bad1; - if (cmv->bDirection != MODEMTOHOST) + if (cmv->bDirection != E1_MODEMTOHOST) goto bad1; /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to * the first MEMACESS cmv. Ignore it... */ - if (cmv->bFunction != sc->cmv_function) { + if (cmv->bFunction != dsc->function) { if (UEA_CHIP_VERSION(sc) == ADI930 - && cmv->bFunction == MAKEFUNCTION(2, 2)) { - cmv->wIndex = cpu_to_le16(sc->cmv_idx); - put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress); - cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset); - } - else + && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { + cmv->wIndex = cpu_to_le16(dsc->idx); + put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + cmv->wOffsetAddress = cpu_to_le16(dsc->offset); + } else goto bad2; } - if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { + if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) { wake_up_cmv_ack(sc); uea_leaves(INS_TO_USBDEV(sc)); return; } /* in case of MEMACCESS */ - if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != - sc->cmv_address - || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset) + if (le16_to_cpu(cmv->wIndex) != dsc->idx || + le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); @@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) bad2: uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," "Function : %d, Subfunction : %d\n", - FUNCTION_TYPE(cmv->bFunction), - FUNCTION_SUBTYPE(cmv->bFunction)); + E1_FUNCTION_TYPE(cmv->bFunction), + E1_FUNCTION_SUBTYPE(cmv->bFunction)); uea_leaves(INS_TO_USBDEV(sc)); return; @@ -1301,6 +2004,61 @@ bad1: uea_leaves(INS_TO_USBDEV(sc)); } +/* The modem send us an ack. First with check if it right */ +static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4; + struct cmv_e4 *cmv = &intr->u.e4.s2.cmv; + + uea_enters(INS_TO_USBDEV(sc)); + uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n", + be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction), + be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress), + be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1])); + + if (be16_to_cpu(cmv->wFunction) != dsc->function) + goto bad2; + + if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) { + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + } + + /* in case of MEMACCESS */ + if (be16_to_cpu(cmv->wOffset) != dsc->offset || + be16_to_cpu(cmv->wGroup) != dsc->group || + be16_to_cpu(cmv->wAddress) != dsc->address) + goto bad2; + + sc->data = be32_to_cpu(cmv->dwData[0]); + sc->data1 = be32_to_cpu(cmv->dwData[1]); + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + +bad2: + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + "Function : %d, Subfunction : %d\n", + E4_FUNCTION_TYPE(cmv->wFunction), + E4_FUNCTION_SUBTYPE(cmv->wFunction)); + uea_leaves(INS_TO_USBDEV(sc)); + return; +} + +static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e1_bSwapPageNo; + sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; + queue_work(sc->work_q, &sc->task); +} + +static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e4_bSwapPageNo; + queue_work(sc->work_q, &sc->task); +} + /* * interrupt handler */ @@ -1326,13 +2084,11 @@ static void uea_intr(struct urb *urb) switch (le16_to_cpu(intr->wInterrupt)) { case INT_LOADSWAPPAGE: - sc->pageno = intr->bSwapPageNo; - sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4; - schedule_work(&sc->task); + sc->schedule_load_page(sc, intr); break; case INT_INCOMINGCMV: - uea_dispatch_cmv(sc, &intr->u.s2.cmv); + sc->dispatch_cmv(sc, intr); break; default: @@ -1349,35 +2105,55 @@ resubmit: */ static int uea_boot(struct uea_softc *sc) { - int ret; + int ret, size; struct intr_pkt *intr; uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + size = E4_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e4; + sc->schedule_load_page = uea_schedule_load_page_e4; + sc->stat = uea_stat_e4; + sc->send_cmvs = uea_send_cmvs_e4; + INIT_WORK(&sc->task, uea_load_page_e4); + } else { + size = E1_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e1; + sc->schedule_load_page = uea_schedule_load_page_e1; + sc->stat = uea_stat_e1; + sc->send_cmvs = uea_send_cmvs_e1; + INIT_WORK(&sc->task, uea_load_page_e1); + } + init_waitqueue_head(&sc->sync_q); - init_waitqueue_head(&sc->cmv_ack_wait); + + sc->work_q = create_workqueue("ueagle-dsp"); + if (!sc->work_q) { + uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n"); + uea_leaves(INS_TO_USBDEV(sc)); + return -ENOMEM; + } if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); - intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL); + intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); - uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; + goto err0; } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); - goto err; + goto err1; } usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), - intr, INTR_PKT_SIZE, uea_intr, sc, + intr, size, uea_intr, sc, sc->usb_dev->actconfig->interface[0]->altsetting[0]. endpoint[0].desc.bInterval); @@ -1385,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err; + goto err1; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -1399,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err: +err1: usb_free_urb(sc->urb_int); sc->urb_int = NULL; kfree(intr); +err0: + destroy_workqueue(sc->work_q); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -1417,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc) ret = kthread_stop(sc->kthread); uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); - /* stop any pending boot process */ - flush_scheduled_work(); - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); usb_kill_urb(sc->urb_int); kfree(sc->urb_int->transfer_buffer); usb_free_urb(sc->urb_int); + /* stop any pending boot process, when no one can schedule work */ + destroy_workqueue(sc->work_q); + if (sc->dsp_firm) release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); @@ -1487,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at char *buf) { int ret = -ENODEV; + int modem_state; struct uea_softc *sc; mutex_lock(&uea_mutex); @@ -1494,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at if (!sc) goto out; - switch (GET_STATUS(sc->stats.phy.state)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + modem_state = 0; + break; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + modem_state = 1; + break; + case 0x7: /* operational */ + modem_state = 2; + break; + case 0x2: /* fail ... */ + modem_state = 3; + break; + default: /* unknown */ + modem_state = 4; + break; + } + } else + modem_state = GET_STATUS(sc->stats.phy.state); + + switch (modem_state) { case 0: ret = sprintf(buf, "Modem is booting\n"); break; @@ -1504,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at case 2: ret = sprintf(buf, "Modem is operational\n"); break; - default: + case 3: ret = sprintf(buf, "Modem synchronization failed\n"); break; + default: + ret = sprintf(buf, "Modem state is unknown\n"); + break; } out: mutex_unlock(&uea_mutex); @@ -1520,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr, { int ret = -ENODEV; struct uea_softc *sc; + char *delin = "GOOD"; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; - if (sc->stats.phy.flags & 0x0C00) - ret = sprintf(buf, "ERROR\n"); - else if (sc->stats.phy.flags & 0x0030) - ret = sprintf(buf, "LOSS\n"); - else - ret = sprintf(buf, "GOOD\n"); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (sc->stats.phy.flags & 0x4000) + delin = "RESET"; + else if (sc->stats.phy.flags & 0x0001) + delin = "LOSS"; + } else { + if (sc->stats.phy.flags & 0x0C00) + delin = "ERROR"; + else if (sc->stats.phy.flags & 0x0030) + delin = "LOSS"; + } + + ret = sprintf(buf, "%s\n", delin); out: mutex_unlock(&uea_mutex); return ret; @@ -1662,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, struct usb_device *usb = interface_to_usbdev(intf); struct uea_softc *sc; int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; + unsigned int alt; uea_enters(usb); @@ -1696,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; sc->driver_info = id->driver_info; - /* ADI930 don't support iso */ - if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { - int i; - - /* try set fastest alternate for inbound traffic interface */ - for (i = FASTEST_ISO_INTF; i > 0; i--) - if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0) - break; + /* first try to use module parameter */ + if (annex[sc->modem_index] == 1) + sc->annex = ANNEXA; + else if (annex[sc->modem_index] == 2) + sc->annex = ANNEXB; + /* try to autodetect annex */ + else if (sc->driver_info & AUTO_ANNEX_A) + sc->annex = ANNEXA; + else if (sc->driver_info & AUTO_ANNEX_B) + sc->annex = ANNEXB; + else + sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; - if (i > 0) { - uea_dbg(usb, "set alternate %d for 2 interface\n", i); + alt = altsetting[sc->modem_index]; + /* ADI930 don't support iso */ + if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { + if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { + uea_dbg(usb, "set alternate %u for 2 interface\n", alt); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { - uea_err(usb, "setting any alternate failed for " - "2 interface, using bulk mode\n"); + uea_err(usb, "setting alternate %u failed for " + "2 interface, using bulk mode\n", alt); } } @@ -1757,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", - le16_to_cpu(usb->descriptor.idVendor), - le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", + le16_to_cpu(usb->descriptor.idVendor), + le16_to_cpu(usb->descriptor.idProduct), + le16_to_cpu(usb->descriptor.bcdDevice), + chip_name[UEA_CHIP_VERSION(id)]); usb_reset_device(usb); @@ -1793,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf) * List of supported VID/PID */ static const struct usb_device_id uea_ids[] = { + {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {} }; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 5192cd9356d..ad632f2d6f9 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -28,6 +28,7 @@ * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) * v0.13 - alloc space for statusbuf (<status> not on stack); * use usb_buffer_alloc() for read buf & write buf; + * none - Maintained in Linux kernel after v0.13 */ /* @@ -69,7 +70,6 @@ #define USBLP_DEVICE_ID_SIZE 1024 /* ioctls: */ -#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 @@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ +#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */ #define USBLP_FIRST_PROTOCOL 1 #define USBLP_LAST_PROTOCOL 3 @@ -159,10 +159,12 @@ struct usblp { int wstatus; /* bytes written or error */ int rstatus; /* bytes ready or error */ unsigned int quirks; /* quirks flags */ + unsigned int flags; /* mode flags */ unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ unsigned char sleeping; /* interface is suspended */ + unsigned char no_paper; /* Paper Out happened */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); + request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; @@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb) usblp->wstatus = status; else usblp->wstatus = urb->actual_length; + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock(&usblp->lock); - /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */ - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */ usb_free_urb(urb); } @@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err) unsigned char status, newerr = 0; int error; - error = usblp_read_status (usblp, usblp->statusbuf); - if (error < 0) { + mutex_lock(&usblp->mut); + if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + mutex_unlock(&usblp->mut); if (printk_ratelimit()) printk(KERN_ERR "usblp%d: error %d reading printer status\n", usblp->minor, error); return 0; } - status = *usblp->statusbuf; + mutex_unlock(&usblp->mut); if (~status & LP_PERRORP) newerr = 3; @@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file) goto out; /* - * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? - * This is #if 0-ed because we *don't* want to fail an open - * just because the printer is off-line. + * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: + * - We do not want persistent state which close(2) does not clear + * - It is not used anyway, according to CUPS people */ -#if 0 - if ((retval = usblp_check_status(usblp, 0))) { - retval = retval > 1 ? -EIO : -ENOSPC; - goto out; - } -#else - retval = 0; -#endif retval = usb_autopm_get_interface(intf); if (retval < 0) @@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + usblp->flags &= ~LP_ABORT; + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { @@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->rwait, wait); poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); - ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); + ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | + ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; + case LPABORT: + if (arg) + usblp->flags |= LP_ABORT; + else + usblp->flags &= ~LP_ABORT; + break; + default: retval = -ENOTTY; } @@ -684,10 +686,30 @@ done: return retval; } +static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) +{ + struct urb *urb; + char *writebuf; + + if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) + return NULL; + if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + kfree(writebuf); + return NULL; + } + + usb_fill_bulk_urb(urb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), + writebuf, transfer_length, usblp_bulk_write, usblp); + urb->transfer_flags |= URB_FREE_BUFFER; + + return urb; +} + static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - char *writebuf; struct urb *writeurb; int rv; int transfer_length; @@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; - if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL) - goto raise_buf; - if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) + if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) goto raise_urb; - usb_fill_bulk_urb(writeurb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); usb_anchor_urb(writeurb, &usblp->urbs); - if (copy_from_user(writebuf, + if (copy_from_user(writeurb->transfer_buffer, buffer + writecount, transfer_length)) { rv = -EFAULT; goto raise_badaddr; @@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock_irq(&usblp->lock); @@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t /* Presume that it's going to complete well. */ writecount += transfer_length; } + if (rv == -ENOSPC) { + spin_lock_irq(&usblp->lock); + usblp->no_paper = 1; /* Mark for poll(2) */ + spin_unlock_irq(&usblp->lock); + writecount += transfer_length; + } /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } if (usblp->wstatus < 0) { - usblp_check_status(usblp, 0); rv = -EIO; goto collect_error; } @@ -771,8 +793,6 @@ raise_badaddr: usb_unanchor_urb(writeurb); usb_free_urb(writeurb); raise_urb: - kfree(writebuf); -raise_buf: raise_wait: collect_error: /* Out of raise sequence */ mutex_unlock(&usblp->wmut); @@ -838,32 +858,36 @@ done: * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use * select(2) or poll(2) to wait for the buffer to drain before closing. * Alternatively, set blocking mode with fcntl and issue a zero-size write. - * - * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot - * to check the return code for timeout expiration, so it had no effect. - * Apparently, it was intended to check for error conditons, such as out - * of paper. It is going to return when we settle things with CUPS. XXX */ static int usblp_wwait(struct usblp *usblp, int nonblock) { DECLARE_WAITQUEUE(waita, current); int rc; + int err = 0; add_wait_queue(&usblp->wwait, &waita); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_wtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } + rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); - if (rc == 0) + if (rc <= 0) break; - schedule(); + + if (usblp->flags & LP_ABORT) { + if (schedule_timeout(msecs_to_jiffies(5000)) == 0) { + err = usblp_check_status(usblp, err); + if (err == 1) { /* Paper out */ + rc = -ENOSPC; + break; + } + } + } else { + schedule(); + } } set_current_state(TASK_RUNNING); remove_wait_queue(&usblp->wwait, &waita); diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cb69aa1e02e..1a8edcee7f3 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev) } -// hub-only!! ... and only in reset path, or usb_new_device() -// (used by real hubs and virtual root hubs) +/* + * Get the USB config descriptors, cache and parse'em + * + * hub-only!! ... and only in reset path, or usb_new_device() + * (used by real hubs and virtual root hubs) + * + * NOTE: if this is a WUSB device and is not authorized, we skip the + * whole thing. A non-authorized USB device has no + * configurations. + */ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; + int result = 0; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + cfgno = 0; + if (dev->authorized == 0) /* Not really an error */ + goto out_not_authorized; + result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev) goto err2; desc = (struct usb_config_descriptor *)buffer; - for (cfgno = 0; cfgno < ncfg; cfgno++) { + result = 0; + for (; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE); if (result < 0) { dev_err(ddev, "unable to read config index %d " - "descriptor/%s\n", cfgno, "start"); + "descriptor/%s: %d\n", cfgno, "start", result); dev_err(ddev, "chopping to %d config(s)\n", cfgno); dev->descriptor.bNumConfigurations = cfgno; break; @@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(buffer); +out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a..f013b4012c9 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -71,6 +71,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + int status; u32 secid; }; @@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb) if (!usbfs_snoop) return; - if (urb->pipe & USB_DIR_IN) - dev_info(&urb->dev->dev, "direction=IN\n"); - else - dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "direction=%s\n", + usb_urb_dir_in(urb) ? "IN" : "OUT"); dev_info(&urb->dev->dev, "userurb=%p\n", userurb); dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", urb->transfer_buffer_length); @@ -312,9 +311,10 @@ static void async_completed(struct urb *urb) spin_lock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); spin_unlock(&ps->lock); + as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; - sinfo.si_errno = as->urb->status; + sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, @@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; + int is_in; if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) @@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if ((ret = checkintf(ps, ifnum))) return ret; } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) - ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - else - ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { + is_in = 1; + ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } else { + is_in = 0; + ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } if (!ep) return -ENOENT; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_CONTROL) + if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) @@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return ret; } - uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { + if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { + is_in = 1; + uurb->endpoint |= USB_DIR_IN; + } else { + is_in = 0; + uurb->endpoint &= ~USB_DIR_IN; + } + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) { kfree(dr); return -EFAULT; } snoop(&ps->dev->dev, "control urb: bRequest=%02x " "bRrequestType=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - dr->bRequest, dr->bRequestType, dr->wValue, - dr->wIndex, dr->wLength); + dr->bRequest, dr->bRequestType, + __le16_to_cpup(&dr->wValue), + __le16_to_cpup(&dr->wIndex), + __le16_to_cpup(&dr->wLength)); break; case USBDEVFS_URB_TYPE_BULK: - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: return -EINVAL; @@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->number_of_packets = 0; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "bulk urb\n"); break; @@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, /* arbitrary limit */ if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) return -EINVAL; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_ISOC) + if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) @@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_INTERRUPT: uurb->number_of_packets = 0; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; @@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -ENOMEM; } as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags; + as->urb->pipe = (uurb->type << 30) | + __create_pipe(ps->dev, uurb->endpoint & 0xf) | + (uurb->endpoint & USB_DIR_IN); + as->urb->transfer_flags = uurb->flags | + (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char*)dr; as->urb->start_frame = uurb->start_frame; @@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); - if (!(uurb->endpoint & USB_DIR_IN)) { - if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { + if (!is_in) { + if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, + as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } } - snoop(&as->urb->dev->dev, "submit urb\n"); snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { @@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1576,6 +1591,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai } const struct file_operations usbdev_file_operations = { + .owner = THIS_MODULE, .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1625,10 +1641,7 @@ static struct notifier_block usbdev_nb = { }; #endif -static struct cdev usb_device_cdev = { - .kobj = {.name = "usb_device", }, - .owner = THIS_MODULE, -}; +static struct cdev usb_device_cdev; int __init usb_devio_init(void) { diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a913..8586817698a 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } + id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); @@ -576,12 +581,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int usb_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -610,51 +612,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, * all the device descriptors we don't tell them about. Or * act as usermode drivers. */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif /* per-device configurations are common */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; /* class-based driver binding models */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "BUSNUM=%03d", + if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVNUM=%03d", + if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } @@ -945,11 +935,11 @@ done: #ifdef CONFIG_USB_SUSPEND /* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev) +static int autosuspend_check(struct usb_device *udev, int reschedule) { int i; struct usb_interface *intf; - unsigned long suspend_time; + unsigned long suspend_time, j; /* For autosuspend, fail fast if anything is in use or autosuspend * is disabled. Also fail if any interfaces require remote wakeup @@ -991,20 +981,20 @@ static int autosuspend_check(struct usb_device *udev) } /* If everything is okay but the device hasn't been idle for long - * enough, queue a delayed autosuspend request. + * enough, queue a delayed autosuspend request. If the device + * _has_ been idle for long enough and the reschedule flag is set, + * likewise queue a delayed (1 second) autosuspend request. */ - if (time_after(suspend_time, jiffies)) { + j = jiffies; + if (time_before(j, suspend_time)) + reschedule = 1; + else + suspend_time = j + HZ; + if (reschedule) { if (!timer_pending(&udev->autosuspend.timer)) { - - /* The value of jiffies may change between the - * time_after() comparison above and the subtraction - * below. That's okay; the system behaves sanely - * when a timer is registered for the present moment - * or for the past. - */ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - round_jiffies_relative(suspend_time - jiffies)); - } + round_jiffies_relative(suspend_time - j)); + } return -EAGAIN; } return 0; @@ -1012,7 +1002,7 @@ static int autosuspend_check(struct usb_device *udev) #else -static inline int autosuspend_check(struct usb_device *udev) +static inline int autosuspend_check(struct usb_device *udev, int reschedule) { return 0; } @@ -1069,7 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->auto_pm) { - status = autosuspend_check(udev); + status = autosuspend_check(udev, 0); if (status < 0) goto done; } @@ -1083,15 +1073,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) break; } } - if (status == 0) { - - /* Non-root devices don't need to do anything for FREEZE - * or PRETHAW. */ - if (udev->parent && (msg.event == PM_EVENT_FREEZE || - msg.event == PM_EVENT_PRETHAW)) - goto done; + if (status == 0) status = usb_suspend_device(udev, msg); - } /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { @@ -1102,12 +1085,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* Try another autosuspend when the interfaces aren't busy */ if (udev->auto_pm) - autosuspend_check(udev); + autosuspend_check(udev, status == -EBUSY); - /* If the suspend succeeded, propagate it up the tree */ + /* If the suspend succeeded then prevent any more URB submissions, + * flush any outstanding URBs, and propagate the suspend up the tree. + */ } else { cancel_delayed_work(&udev->autosuspend); - if (parent) + udev->can_submit = 0; + for (i = 0; i < 16; ++i) { + usb_hcd_flush_endpoint(udev, udev->ep_out[i]); + usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + } + + /* If this is just a FREEZE or a PRETHAW, udev might + * not really be suspended. Only true suspends get + * propagated up the device tree. + */ + if (parent && udev->state == USB_STATE_SUSPENDED) usb_autosuspend_device(parent); } @@ -1156,6 +1151,7 @@ static int usb_resume_both(struct usb_device *udev) status = -ENODEV; goto done; } + udev->can_submit = 1; /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { @@ -1529,9 +1525,21 @@ int usb_external_resume_device(struct usb_device *udev) static int usb_suspend(struct device *dev, pm_message_t message) { + struct usb_device *udev; + if (!is_usb_device(dev)) /* Ignore PM for interfaces */ return 0; - return usb_external_suspend_device(to_usb_device(dev), message); + udev = to_usb_device(dev); + + /* If udev is already suspended, we can skip this suspend and + * we should also skip the upcoming system resume. */ + if (udev->state == USB_STATE_SUSPENDED) { + udev->skip_sys_resume = 1; + return 0; + } + + udev->skip_sys_resume = 0; + return usb_external_suspend_device(udev, message); } static int usb_resume(struct device *dev) @@ -1542,13 +1550,14 @@ static int usb_resume(struct device *dev) return 0; udev = to_usb_device(dev); - /* If autoresume is disabled then we also want to prevent resume - * during system wakeup. However, a "persistent-device" reset-resume - * after power loss counts as a wakeup event. So allow a - * reset-resume to occur if remote wakeup is enabled. */ - if (udev->autoresume_disabled) { + /* If udev->skip_sys_resume is set then udev was already suspended + * when the system suspend started, so we don't want to resume + * udev during this system wakeup. However a reset-resume counts + * as a wakeup event, so allow a reset-resume to occur if remote + * wakeup is enabled. */ + if (udev->skip_sys_resume) { if (!(udev->reset_resume && udev->do_remote_wakeup)) - return -EPERM; + return -EHOSTUNREACH; } return usb_external_resume_device(udev); } diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index e0ec7045e86..7dc123d6b2d 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); endpoint_free_minor(ep_dev); kfree(ep_dev); } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b2fc2b11525..c1cb94e9f24 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -static int choose_configuration(struct usb_device *udev) +int usb_choose_configuration(struct usb_device *udev) { int i; int num_configs; @@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", + if (udev->authorized == 0) + dev_err(&udev->dev, "Device is not authorized for usage\n"); + else { + c = usb_choose_configuration(udev); + if (c >= 0) { + err = usb_set_configuration(udev, c); + if (err) { + dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ + /* This need not be fatal. The user can try to + * set other configurations. */ + } } } - /* USB device state == configured ... usable */ usb_notify_add_device(udev); @@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) */ if (!udev->parent) rc = hcd_bus_suspend(udev); + + /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ + else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + rc = 0; else rc = usb_port_suspend(udev); + return rc; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 42ef1d5f6c8..3dd997df850 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - unsigned long flags; - int status = 0; + int status; int n; + might_sleep(); + + spin_lock_irq(&hcd_root_hub_lock); + status = usb_hcd_link_urb_to_ep(hcd, urb); + spin_unlock_irq(&hcd_root_hub_lock); + if (status) + return status; + urb->hcpriv = hcd; /* Indicate it's queued */ + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -523,13 +531,18 @@ error: } /* any errors get returned through the urb completion */ - local_irq_save (flags); - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - spin_unlock (&urb->lock); - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + spin_lock_irq(&hcd_root_hub_lock); + usb_hcd_unlink_urb_from_ep(hcd, urb); + + /* This peculiar use of spinlocks echoes what real HC drivers do. + * Avoiding calls to local_irq_disable/enable makes the code + * RT-friendly. + */ + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb, status); + spin_lock(&hcd_root_hub_lock); + + spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (length > 0) { /* try to complete the status urb */ - local_irq_save (flags); - spin_lock(&hcd_root_hub_lock); + spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { - hcd->poll_pending = 0; - hcd->status_urb = NULL; - urb->status = 0; - urb->hcpriv = NULL; - urb->actual_length = length; - memcpy(urb->transfer_buffer, buffer, length); - } else /* urb has been unlinked */ - length = 0; - spin_unlock(&urb->lock); - } else - length = 0; - spin_unlock(&hcd_root_hub_lock); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb); - else + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb, 0); + spin_lock(&hcd_root_hub_lock); + } else { + length = 0; hcd->poll_pending = 1; - local_irq_restore (flags); + } + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't @@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) int len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (urb->status != -EINPROGRESS) /* already unlinked */ - retval = urb->status; - else if (hcd->status_urb || urb->transfer_buffer_length < len) { + if (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; - } else { - hcd->status_urb = urb; - urb->hcpriv = hcd; /* indicate it's queued */ + goto done; + } - if (!hcd->uses_new_polling) - mod_timer (&hcd->rh_timer, - (jiffies/(HZ/4) + 1) * (HZ/4)); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) + goto done; - /* If a status change has already occurred, report it ASAP */ - else if (hcd->poll_pending) - mod_timer (&hcd->rh_timer, jiffies); - retval = 0; - } + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ + if (!hcd->uses_new_polling) + mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); + + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer(&hcd->rh_timer, jiffies); + retval = 0; + done: spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval; } static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) + if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); - if (usb_pipecontrol (urb->pipe)) + if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; } @@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) /* Unlinks of root-hub control URBs are legal, but they don't do anything * since these URBs always execute synchronously. */ -static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; + int rc; + + spin_lock_irqsave(&hcd_root_hub_lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; - if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); - local_irq_save (flags); - spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; - urb->hcpriv = NULL; - } else - urb = NULL; /* wasn't fully queued */ - spin_unlock (&hcd_root_hub_lock); - if (urb) - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + usb_hcd_unlink_urb_from_ep(hcd, urb); + + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb, status); + spin_lock(&hcd_root_hub_lock); + } } + done: + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); + return rc; +} - return 0; + + +/* + * Show & store the current value of authorized_default + */ +static ssize_t usb_host_authorized_default_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); +} + +static ssize_t usb_host_authorized_default_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + unsigned val; + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + result = sscanf(buf, "%u\n", &val); + if (result == 1) { + usb_hcd->authorized_default = val? 1 : 0; + result = size; + } + else + result = -EINVAL; + return result; } +static DEVICE_ATTR(authorized_default, 0644, + usb_host_authorized_default_show, + usb_host_authorized_default_store); + + +/* Group all the USB bus attributes */ +static struct attribute *usb_bus_attrs[] = { + &dev_attr_authorized_default.attr, + NULL, +}; + +static struct attribute_group usb_bus_attr_group = { + .name = NULL, /* we want them in the same directory */ + .attrs = usb_bus_attrs, +}; + + + /*-------------------------------------------------------------------------*/ static struct class *usb_host_class; @@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus) */ static int usb_register_bus(struct usb_bus *bus) { + int result = -E2BIG; int busnum; mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - } else { + if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - mutex_unlock(&usb_bus_list_lock); - return -E2BIG; + goto error_find_busnum; } - + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", busnum); - if (IS_ERR(bus->class_dev)) { - clear_bit(busnum, busmap.busmap); - mutex_unlock(&usb_bus_list_lock); - return PTR_ERR(bus->class_dev); - } - + bus->controller, "usb_host%d", + busnum); + result = PTR_ERR(bus->class_dev); + if (IS_ERR(bus->class_dev)) + goto error_create_class_dev; class_set_devdata(bus->class_dev, bus); /* Add it to the local list of buses */ @@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus) usb_notify_add_bus(bus); - dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); + dev_info (bus->controller, "new USB bus registered, assigned bus " + "number %d\n", bus->busnum); return 0; + +error_create_class_dev: + clear_bit(busnum, busmap.busmap); +error_find_busnum: + mutex_unlock(&usb_bus_list_lock); + return result; } /** @@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being submitted + * + * Host controller drivers should call this routine in their enqueue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for URB + * submission, as well as for endpoint shutdown and for usb_kill_urb. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the enqueue() method must fail). If no error occurs but enqueue() fails + * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing + * the private spinlock and returning. + */ +int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; + int rc = 0; - /* clear all state linking urb to this dev (and hcd) */ - spin_lock_irqsave(&hcd_urb_list_lock, flags); - list_del_init (&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_pipecontrol (urb->pipe) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - dma_unmap_single (hcd->self.controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - dma_unmap_single (hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + /* Check that the URB isn't being killed */ + if (unlikely(urb->reject)) { + rc = -EPERM; + goto done; } -} - -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) -{ - int status; - struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - struct usb_host_endpoint *ep; - unsigned long flags; - if (!hcd) - return -ENODEV; + if (unlikely(!urb->ep->enabled)) { + rc = -ENOENT; + goto done; + } - usbmon_urb_submit(&hcd->self, urb); + if (unlikely(!urb->dev->can_submit)) { + rc = -EHOSTUNREACH; + goto done; + } /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. + * Check the host controller's state and add the URB to the + * endpoint's queue. */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave(&hcd_urb_list_lock, flags); - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (unlikely (!ep)) - status = -ENOENT; - else if (unlikely (urb->reject)) - status = -EPERM; - else switch (hcd->state) { + switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &ep->urb_list); - status = 0; + urb->unlinked = 0; + list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: - status = -ESHUTDOWN; - break; + rc = -ESHUTDOWN; + goto done; } - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (status) { - INIT_LIST_HEAD (&urb->urb_list); - usbmon_urb_submit_error(&hcd->self, urb, status); - return status; + done: + spin_unlock(&hcd_urb_list_lock); + return rc; +} +EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); + +/** + * usb_hcd_check_unlink_urb - check whether an URB may be unlinked + * @hcd: host controller to which @urb was submitted + * @urb: URB being checked for unlinkability + * @status: error code to store in @urb if the unlink succeeds + * + * Host controller drivers should call this routine in their dequeue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for making + * sure than an unlink is valid. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the dequeue() method must fail). The possible error codes are: + * + * -EIDRM: @urb was not submitted or has already completed. + * The completion function may not have been called yet. + * + * -EBUSY: @urb has already been unlinked. + */ +int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + struct list_head *tmp; + + /* insist the urb is still queued */ + list_for_each(tmp, &urb->ep->urb_list) { + if (tmp == &urb->urb_list) + break; } + if (tmp != &urb->urb_list) + return -EIDRM; - /* increment urb's reference count as part of giving it to the HCD - * (which now controls it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. + /* Any status except -EINPROGRESS means something already started to + * unlink this URB from the hardware. So there's no more work to do. */ - urb = usb_get_urb (urb); - atomic_inc (&urb->use_count); - - if (is_root_hub(urb->dev)) { - /* NOTE: requirement on hub callers (usbfs and the hub - * driver, for now) that URBs' urb->transfer_buffer be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. - */ - status = rh_urb_enqueue (hcd, urb); - goto done; + if (urb->unlinked) + return -EBUSY; + urb->unlinked = status; + + /* IRQ setup can easily be broken so that USB controllers + * never get completion IRQs ... maybe even the ones we need to + * finish unlinking the initial failed usb_set_address() + * or device descriptor fetch. + */ + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && + !is_root_hub(urb->dev)) { + dev_warn(hcd->self.controller, "Unlink after no-IRQ? " + "Controller is probably using the wrong IRQ.\n"); + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } - /* lower level hcd code should use *_dma exclusively, + return 0; +} +EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); + +/** + * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being unlinked + * + * Host controller drivers should call this routine before calling + * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and + * interrupts must be disabled. The actions carried out here are required + * for URB completion. + */ +void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +{ + /* clear all state linking urb to this dev (and hcd) */ + spin_lock(&hcd_urb_list_lock); + list_del_init(&urb->urb_list); + spin_unlock(&hcd_urb_list_lock); +} +EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); + +static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + /* Map the URB's buffers for DMA access. + * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma) { - if (usb_pipecontrol (urb->pipe) + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->self.controller, @@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +} - status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); -done: - if (unlikely (status)) { - urb_unlink(hcd, urb); - atomic_dec (&urb->use_count); - if (urb->reject) - wake_up (&usb_kill_urb_queue); +static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + dma_unmap_single(hcd->self.controller, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + dma_unmap_single(hcd->self.controller, + urb->transfer_dma, + urb->transfer_buffer_length, + usb_urb_dir_in(urb) + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); + } +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount + * caller surrenders "ownership" of urb + * expects usb_submit_urb() to have sanity checked and conditioned all + * inputs in the urb + */ +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +{ + int status; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + + /* increment urb's reference count as part of giving it to the HCD + * (which will control it). HCD guarantees that it either returns + * an error or calls giveback(), but not both. + */ + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + usbmon_urb_submit(&hcd->self, urb); + + /* NOTE requirements on root-hub callers (usbfs and the hub + * driver, for now): URBs' urb->transfer_buffer must be + * valid and usb_buffer_{sync,unmap}() not be needed, since + * they could clobber root hub response data. Also, control + * URBs must be submitted in process context with interrupts + * enabled. + */ + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); + + if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); - usb_put_urb (urb); + unmap_urb_for_dma(hcd, urb); + urb->hcpriv = NULL; + INIT_LIST_HEAD(&urb->urb_list); + atomic_dec(&urb->use_count); + atomic_dec(&urb->dev->urbnum); + if (urb->reject) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); } return status; } @@ -1042,24 +1213,19 @@ done: * soon as practical. we've already set up the urb's return status, * but we can't know if the callback completed already. */ -static int -unlink1 (struct usb_hcd *hcd, struct urb *urb) +static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) { int value; if (is_root_hub(urb->dev)) - value = usb_rh_urb_dequeue (hcd, urb); + value = usb_rh_urb_dequeue(hcd, urb, status); else { /* The only reason an HCD might fail this call is if * it has not yet fully queued the urb to begin with. * Such failures should be harmless. */ - value = hcd->driver->urb_dequeue (hcd, urb); + value = hcd->driver->urb_dequeue(hcd, urb, status); } - - if (value != 0) - dev_dbg (hcd->self.controller, "dequeue %p --> %d\n", - urb, value); return value; } @@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_host_endpoint *ep; - struct usb_hcd *hcd = NULL; - struct device *sys = NULL; - unsigned long flags; - struct list_head *tmp; - int retval; - - if (!urb) - return -EINVAL; - if (!urb->dev || !urb->dev->bus) - return -ENODEV; - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) - return -ENODEV; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); + struct usb_hcd *hcd; + int retval; - sys = &urb->dev->dev; hcd = bus_to_hcd(urb->dev->bus); - if (hcd == NULL) { - retval = -ENODEV; - goto done; - } + retval = unlink1(hcd, urb, status); - /* insist the urb is still queued */ - list_for_each(tmp, &ep->urb_list) { - if (tmp == &urb->urb_list) - break; - } - if (tmp != &urb->urb_list) { - retval = -EIDRM; - goto done; - } - - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - */ - if (urb->status != -EINPROGRESS) { - retval = -EBUSY; - goto done; - } - - /* IRQ setup can easily be broken so that USB controllers - * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address() - * or device descriptor fetch. - */ - if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && - !is_root_hub(urb->dev)) { - dev_warn (hcd->self.controller, "Unlink after no-IRQ? " - "Controller is probably using the wrong IRQ.\n"); - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - } - - urb->status = status; - - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - retval = unlink1 (hcd, urb); if (retval == 0) retval = -EINPROGRESS; - return retval; - -done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - if (retval != -EIDRM && sys && sys->driver) - dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); + else if (retval != -EIDRM && retval != -EBUSY) + dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", + urb, retval); return retval; } @@ -1162,6 +1257,7 @@ done: * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * @status: completion status code for the URB. * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its @@ -1169,14 +1265,27 @@ done: * (and is done using urb->hcpriv). It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. + * + * If @urb was unlinked, the value of @status will be overridden by + * @urb->unlinked. Erroneous short transfers are detected in case + * the HCD hasn't checked for them. */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - urb_unlink(hcd, urb); - usbmon_urb_complete (&hcd->self, urb); + urb->hcpriv = NULL; + if (unlikely(urb->unlinked)) + status = urb->unlinked; + else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !status)) + status = -EREMOTEIO; + + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb, status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ + urb->status = status; urb->complete (urb); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) @@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ -/* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware, and then - * waits until the endpoint's queue is completely drained. use for - * set_configuration, set_interface, driver removal, physical disconnect. - * - * example: a qh stored in ep->hcpriv, holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. +/* Cancel all URBs pending on this endpoint and wait for the endpoint's + * queue to drain completely. The caller must first insure that no more + * URBs can be submitted for this endpoint. */ -void usb_hcd_endpoint_disable (struct usb_device *udev, +void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; + if (!ep) + return; + might_sleep(); hcd = bus_to_hcd(udev->bus); - local_irq_disable (); - /* ep is already gone from udev->ep_{in,out}[]; no more submits */ + /* No more submits can occur */ rescan: - spin_lock(&hcd_urb_list_lock); + spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { - int tmp; + int is_in; - /* the urb may already have been unlinked */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) continue; usb_get_urb (urb); + is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); - spin_lock (&urb->lock); - tmp = urb->status; - if (tmp == -EINPROGRESS) - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); - - /* kick hcd unless it's already returning this */ - if (tmp == -EINPROGRESS) { - tmp = urb->pipe; - unlink1 (hcd, urb); - dev_dbg (hcd->self.controller, - "shutdown urb %p pipe %08x ep%d%s%s\n", - urb, tmp, usb_pipeendpoint (tmp), - (tmp & USB_DIR_IN) ? "in" : "out", - ({ char *s; \ - switch (usb_pipetype (tmp)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-intr"; break; \ - default: s = "-iso"; break; \ - }; s;})); - } + /* kick hcd */ + unlink1(hcd, urb, -ESHUTDOWN); + dev_dbg (hcd->self.controller, + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); usb_put_urb (urb); /* list contents may have changed */ goto rescan; } - spin_unlock(&hcd_urb_list_lock); - local_irq_enable (); - - /* synchronize with the hardware, so old configuration state - * clears out immediately (and will be freed). - */ - might_sleep (); - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, ep); + spin_unlock_irq(&hcd_urb_list_lock); - /* Wait until the endpoint queue is completely empty. Most HCDs - * will have done this already in their endpoint_disable method, - * but some might not. And there could be root-hub control URBs - * still pending since they aren't affected by the HCDs' - * endpoint_disable methods. - */ + /* Wait until the endpoint queue is completely empty */ while (!list_empty (&ep->urb_list)) { spin_lock_irq(&hcd_urb_list_lock); @@ -1278,6 +1370,25 @@ rescan: } } +/* Disables the endpoint: synchronizes with the hcd to make sure all + * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must + * have been called previously. Use for set_configuration, set_interface, + * driver removal, physical disconnect. + * + * example: a qh stored in ep->hcpriv, holding state related to endpoint + * type, maxpacket size, toggle, halt status, and scheduling. + */ +void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd; + + might_sleep(); + hcd = bus_to_hcd(udev->bus); + if (hcd->driver->endpoint_disable) + hcd->driver->endpoint_disable(hcd, ep); +} + /*-------------------------------------------------------------------------*/ /* called in any context */ @@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; - return hcd; } EXPORT_SYMBOL (usb_create_hcd); @@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + hcd->authorized_default = hcd->wireless? 0 : 1; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* HC is in reset state, but accessible. Now do the one-time init, @@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; + retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); + if (retval < 0) { + printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", + retval); + goto error_create_attr_group; + } if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; +error_create_attr_group: + mutex_lock(&usb_bus_list_lock); + usb_disconnect(&hcd->self.root_hub); + mutex_unlock(&usb_bus_list_lock); err_register_root_hub: hcd->driver->stop(hcd); err_hcd_driver_start: @@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) cancel_work_sync(&hcd->wakeup_work); #endif + sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index b5ebb73c233..98e24194a4a 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -19,6 +19,8 @@ #ifdef __KERNEL__ +#include <linux/rwsem.h> + /* This file contains declarations of usbcore internals that are mostly * used or exposed by Host Controller Drivers. */ @@ -51,6 +53,12 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. + * + * @authorized_default: Specifies if new devices are authorized to + * connect by default or they require explicit + * user space authorization; this bit is settable + * through /sys/class/usb_host/X/authorized_default. + * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -90,6 +98,7 @@ struct usb_hcd { unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ @@ -182,11 +191,10 @@ struct hc_driver { int (*get_frame_number) (struct usb_hcd *hcd); /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, - gfp_t mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + int (*urb_enqueue)(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags); + int (*urb_dequeue)(struct usb_hcd *hcd, + struct urb *urb, int status); /* hw synch, freeing endpoint resources that urb_dequeue can't */ void (*endpoint_disable)(struct usb_hcd *hcd, @@ -204,10 +212,18 @@ struct hc_driver { /* Needed only if port-change IRQs are level-triggered */ }; +extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); +extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); + extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); -extern void usb_hcd_endpoint_disable (struct usb_device *udev, +extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_flush_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); +extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); @@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { } struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); - void (*urb_complete)(struct usb_bus *bus, struct urb *urb); + void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ }; @@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, (*mon_ops->urb_submit_error)(bus, urb, error); } -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) { if (bus->monitored) - (*mon_ops->urb_complete)(bus, urb); + (*mon_ops->urb_complete)(bus, urb, status); } int usb_mon_register(struct usb_mon_operations *ops); @@ -435,7 +452,8 @@ void usb_mon_deregister(void); static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) {} #endif /* CONFIG_USB_MON */ @@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} : (in_interrupt () ? "in_interrupt" : "can sleep")) -#endif /* __KERNEL__ */ +/* This rwsem is for use only by the hub driver and ehci-hcd. + * Nobody else should touch it. + */ +extern struct rw_semaphore ehci_cf_port_reset_rwsem; +#endif /* __KERNEL__ */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f7b337feb3e..d20cb545a6e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " "first one fails"); +/* Mutual exclusion for EHCI CF initialization. This interferes with + * port reset on some companion controllers. + */ +DECLARE_RWSEM(ehci_cf_port_reset_rwsem); +EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + static inline char *portspeed(int portstatus) { @@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev) static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; - int status; + int status = urb->status; int i; unsigned long bits; - switch (urb->status) { + switch (status) { case -ENOENT: /* synchronous unlink */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware going away */ @@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status); + dev_dbg (hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; - hub->error = urb->status; + hub->error = status; /* FALL THROUGH */ /* let khubd handle things */ @@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #endif /** - * usb_new_device - perform initial device setup (usbcore-internal) + * usb_configure_device_otg - FIXME (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. + * Do configuration for On-The-Go devices */ -int usb_new_device(struct usb_device *udev) +static int usb_configure_device_otg(struct usb_device *udev) { - int err; - - /* Determine quirks */ - usb_detect_quirks(udev); - - err = usb_get_configuration(udev); - if (err < 0) { - dev_err(&udev->dev, "can't read configurations, error %d\n", - err); - goto fail; - } - - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - - /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + int err = 0; #ifdef CONFIG_USB_OTG /* @@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev) err = -ENOTSUPP; goto fail; } +fail: #endif + return err; +} + + +/** + * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is only called by usb_new_device() and usb_authorize_device() + * and FIXME -- all comments that apply to them apply here wrt to + * environment. + * + * If the device is WUSB and not authorized, we don't attempt to read + * the string descriptors, as they will be errored out by the device + * until it has been authorized. + */ +static int usb_configure_device(struct usb_device *udev) +{ + int err; + if (udev->config == NULL) { + err = usb_get_configuration(udev); + if (err < 0) { + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); + goto fail; + } + } + if (udev->wusb == 1 && udev->authorized == 0) { + udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + } + else { + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + } + err = usb_configure_device_otg(udev); +fail: + return err; +} + + +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) +{ + int err; + + usb_detect_quirks(udev); /* Determine quirks */ + err = usb_configure_device(udev); /* detect & probe dev/intfs */ + if (err < 0) + goto fail; /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); @@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev) err = device_add(&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); - if (udev->parent) - usb_autosuspend_device(udev->parent); goto fail; } -exit: + /* Tell the world! */ + dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); - goto exit; + return err; } + +/** + * Similar to usb_disconnect() + * + * We share a lock (that we have) with device_del(), so we need to + * defer its call. + */ +int usb_deauthorize_device(struct usb_device *usb_dev) +{ + unsigned cnt; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 0) + goto out_unauthorized; + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + kfree(usb_dev->config); + usb_dev->config = NULL; + for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) + kfree(usb_dev->rawdescriptors[cnt]); + usb_dev->descriptor.bNumConfigurations = 0; + kfree(usb_dev->rawdescriptors); +out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +} + + +int usb_authorize_device(struct usb_device *usb_dev) +{ + int result = 0, c; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 1) + goto out_authorized; + kfree(usb_dev->product); + usb_dev->product = NULL; + kfree(usb_dev->manufacturer); + usb_dev->manufacturer = NULL; + kfree(usb_dev->serial); + usb_dev->serial = NULL; + result = usb_autoresume_device(usb_dev); + if (result < 0) { + dev_err(&usb_dev->dev, + "can't autoresume for authorization: %d\n", result); + goto error_autoresume; + } + result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); + if (result < 0) { + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } + usb_dev->authorized = 1; + result = usb_configure_device(usb_dev); + if (result < 0) + goto error_configure; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ + c = usb_choose_configuration(usb_dev); + if (c >= 0) { + result = usb_set_configuration(usb_dev, c); + if (result) { + dev_err(&usb_dev->dev, + "can't set config #%d, error %d\n", c, result); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + dev_info(&usb_dev->dev, "authorized to connect\n"); +error_configure: +error_device_descriptor: +error_autoresume: +out_authorized: + usb_unlock_device(usb_dev); // complements locktree + return result; +} + + static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { @@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ + down_read(&ehci_cf_port_reset_rwsem); + /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { status = set_port_feature(hub->hdev, @@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, case 0: /* TRSTRCY = 10 ms; plus some extra */ msleep(10 + 40); + udev->devnum = 0; /* Device now at address 0 */ /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: @@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - return status; + goto done; } dev_dbg (hub->intfdev, @@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "Cannot enable port %i. Maybe the USB cable is bad?\n", port1); + done: + up_read(&ehci_cf_port_reset_rwsem); return status; } @@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && msg.event == PM_EVENT_SUSPEND && -#ifdef CONFIG_USB_SUSPEND - udev->state != USB_STATE_SUSPENDED -#else - udev->dev.power.power_state.event - == PM_EVENT_ON -#endif - ) { + if (udev && udev->can_submit) { if (!hdev->auto_pm) dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); @@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - udev->ep_in[0] = udev->ep_out[0] = &udev->ep0; + usb_enable_endpoint(udev, &udev->ep0); } #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) #define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) -static int hub_set_address(struct usb_device *udev) +static int hub_set_address(struct usb_device *udev, int devnum) { int retval; - if (udev->devnum == 0) + if (devnum <= 1) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; retval = usb_control_msg(udev, usb_sndaddr0pipe(), - USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, + USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { + udev->devnum = devnum; /* Device now using proper address */ usb_set_device_state(udev, USB_STATE_ADDRESS); ep0_reinit(udev); } @@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; + int devnum = udev->devnum; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } oldspeed = udev->speed; - + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. * For Wireless USB devices, ep0 max packet is always 512 (tho @@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, dev_info (&udev->dev, "%s %s speed %sUSB device using %s and address %d\n", (udev->config) ? "reset" : "new", speed, type, - udev->bus->controller->driver->name, udev->devnum); + udev->bus->controller->driver->name, devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, } for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev); + retval = hub_set_address(udev, devnum); if (retval >= 0) break; msleep(200); @@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval < 0) { dev_err(&udev->dev, "device not accepting address %d, error %d\n", - udev->devnum, retval); + devnum, retval); goto fail; } @@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = 0; fail: - if (retval) + if (retval) { hub_port_disable(hub, port1, 0); + udev->devnum = devnum; /* for disconnect processing */ + } mutex_unlock(&usb_address0_mutex); return retval; } @@ -2699,9 +2831,9 @@ static void hub_events(void) clear_hub_feature(hdev, C_HUB_LOCAL_POWER); if (hubstatus & HUB_STATUS_LOCAL_POWER) /* FIXME: Is this always true? */ - hub->limited_power = 0; - else hub->limited_power = 1; + else + hub->limited_power = 0; } if (hubchange & HUB_CHANGE_OVERCURRENT) { dev_dbg (hub_dev, "overcurrent change\n"); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f..c021af39037 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) dev_dbg(&urb->dev->dev, "%s timed out on ep%d%s len=%d/%d\n", current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", urb->actual_length, urb->transfer_buffer_length); } else @@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io) io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); + usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } @@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb) dev_err (io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", status, io->status); // BUG (); } @@ -379,7 +380,8 @@ int usb_sg_init ( */ dma = (dev->dev.dma_mask != NULL); if (dma) - io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); + io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), + sg, nents); else io->entries = nents; @@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus) - usb_hcd_endpoint_disable(dev, ep); + if (ep) { + ep->enabled = 0; + usb_hcd_flush_endpoint(dev, ep); + usb_hcd_disable_endpoint(dev, ep); + } } /** @@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ -static void -usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) +void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) { - unsigned int epaddr = ep->desc.bEndpointAddress; - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - int is_control; + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); - is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_CONTROL); - if (usb_endpoint_out(epaddr) || is_control) { + if (is_out || is_control) { usb_settoggle(dev, epnum, 1, 0); dev->ep_out[epnum] = ep; } - if (!usb_endpoint_out(epaddr) || is_control) { + if (!is_out || is_control) { usb_settoggle(dev, epnum, 0, 0); dev->ep_in[epnum] = ep; } + ep->enabled = 1; } /* @@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + int changed; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ - if (device_is_registered(&iface->dev)) + changed = (iface->cur_altsetting != alt); + if (changed && device_is_registered(&iface->dev)) usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); @@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); - if (device_is_registered(&iface->dev)) + if (changed && device_is_registered(&iface->dev)) usb_create_sysfs_intf_files(iface); return 0; @@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -void usb_release_interface(struct device *dev) +static void usb_release_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_interface_cache *intfc = @@ -1339,14 +1344,11 @@ void usb_release_interface(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; struct usb_interface *intf; struct usb_host_interface *alt; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -1359,39 +1361,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt = intf->cur_altsetting; #ifdef CONFIG_USB_DEVICEFS - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", + if (add_uevent_var(env, "INTERFACE=%d/%d/%d", alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, alt->desc.bInterfaceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, + if (add_uevent_var(env, "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), @@ -1404,14 +1397,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt->desc.bInterfaceProtocol)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_if_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } @@ -1481,6 +1472,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, * channels are available independently; and choosing between open * standard device protocols (like CDC) or proprietary ones. * + * Note that a non-authorized device (dev->authorized == 0) will only + * be put in unconfigured mode. + * * Note that USB has an additional level of device configurability, * associated with interfaces. That configurability is accessed using * usb_set_interface(). @@ -1502,7 +1496,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - if (configuration == -1) + if (dev->authorized == 0 || configuration == -1) configuration = 0; else { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ebf3dc20110..d42c561c75f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, - /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */ - { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* SGS Thomson Microelectronics 4in1 card reader */ - { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */ - { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Benq S2W 3300U */ - { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N1240U/LiDE30 */ - { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N650U/N656U */ - { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan 1220U */ - { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */ - { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* old Cannon scanner */ - { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 1200 */ - { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 660 */ - { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Epson Perfection 1260 Photo */ - { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp - Perfection 1670 */ - { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* EPSON Perfection 2480 */ - { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp.*/ - { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2010 printer */ - { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2510 Series printer */ - { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Elsa MicroLink 56k (V.250) */ - { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Ultima Electronics Corp.*/ - { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Genesys USB-to-IDE */ - { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* USB Graphical LCD - EEH Datalink GmbH */ - { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = { /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Agfa Snapscan1212u */ - { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seagate RSS LLC */ - { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Umax [hex] Astra 3400U */ - { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Alcor multi-card reader */ - { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Canon EOS 5D in PC Connection mode */ - { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* RIM Blackberry */ - { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Apple iPhone */ - { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, { } /* terminating entry must be last */ }; -static void usb_autosuspend_quirk(struct usb_device *udev) -{ -#ifdef CONFIG_USB_SUSPEND - /* disable autosuspend, but allow the user to re-enable it via sysfs */ - udev->autosuspend_disabled = 1; -#endif -} - static const struct usb_device_id *find_id(struct usb_device *udev) { const struct usb_device_id *id = usb_quirk_list; @@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); - /* do any special quirk handling here if needed */ - if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND) - usb_autosuspend_quirk(udev); - /* By default, disable autosuspend for all non-hubs */ #ifdef CONFIG_USB_SUSPEND if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) - udev->autosuspend_delay = -1; + udev->autosuspend_disabled = 1; #endif } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 2ab222be8fd..b04afd06e50 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +static ssize_t +show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); +} +static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); + #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) static const char power_group[] = "power"; @@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n") usb_descriptor_attr(bNumConfigurations, "%d\n") usb_descriptor_attr(bMaxPacketSize0, "%d\n") + + +/* show if the device is authorized (1) or not (0) */ +static ssize_t usb_dev_authorized_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); +} + + +/* + * Authorize a device to be used in the system + * + * Writing a 0 deauthorizes the device, writing a 1 authorizes it. + */ +static ssize_t usb_dev_authorized_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + struct usb_device *usb_dev = to_usb_device(dev); + unsigned val; + result = sscanf(buf, "%u\n", &val); + if (result != 1) + result = -EINVAL; + else if (val == 0) + result = usb_deauthorize_device(usb_dev); + else + result = usb_authorize_device(usb_dev); + return result < 0? result : size; +} + +static DEVICE_ATTR(authorized, 0644, + usb_dev_authorized_show, usb_dev_authorized_store); + + static struct attribute *dev_attrs[] = { /* current configuration's attributes */ &dev_attr_configuration.attr, @@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, &dev_attr_bMaxPower.attr, + &dev_attr_urbnum.attr, /* device attributes */ &dev_attr_idVendor.attr, &dev_attr_idProduct.attr, @@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, + &dev_attr_authorized.attr, NULL, }; static struct attribute_group dev_attr_grp = { diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index be630228461..c20c03aaf01 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -3,6 +3,7 @@ #include <linux/bitops.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/log2.h> #include <linux/usb.h> #include <linux/wait.h> #include "hcd.h" @@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); - spin_lock_init(&urb->lock); INIT_LIST_HEAD(&urb->anchor_list); } } @@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - int pipe, temp, max; - struct usb_device *dev; - int is_out; + int xfertype, max; + struct usb_device *dev; + struct usb_host_endpoint *ep; + int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || - (dev->state < USB_STATE_DEFAULT) || - (!dev->bus) || (dev->devnum <= 0)) + if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; - if (dev->bus->controller->power.power_state.event != PM_EVENT_ON - || dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; + /* For now, get the endpoint from the pipe. Eventually drivers + * will be required to set urb->ep directly and we will eliminate + * urb->pipe. + */ + ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENOENT; + + urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 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); + xfertype = usb_endpoint_type(&ep->desc); + if (xfertype == USB_ENDPOINT_XFER_CONTROL) { + struct usb_ctrlrequest *setup = + (struct usb_ctrlrequest *) urb->setup_packet; + + if (!setup) + return -ENOEXEC; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } - if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) - return -ENODEV; + /* Cache the direction for later use */ + urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | + (is_out ? URB_DIR_OUT : URB_DIR_IN); - /* 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.) - */ + if (xfertype != USB_ENDPOINT_XFER_CONTROL && + dev->state < USB_STATE_CONFIGURED) + return -ENODEV; - max = usb_maxpacket(dev, pipe, is_out); + max = le16_to_cpu(ep->desc.wMaxPacketSize); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint(pipe), is_out ? "out" : "in", + usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ - if (temp == PIPE_ISOCHRONOUS) { + if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */ @@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | - URB_NO_INTERRUPT); - switch (temp) { - case PIPE_BULK: + URB_NO_INTERRUPT | URB_DIR_MASK); + switch (xfertype) { + case USB_ENDPOINT_XFER_BULK: if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ - case PIPE_CONTROL: + case USB_ENDPOINT_XFER_CONTROL: allowed |= URB_NO_FSBR; /* only affects UHCI */ /* FALLTHROUGH */ default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; break; - case PIPE_ISOCHRONOUS: + case USB_ENDPOINT_XFER_ISOC: allowed |= URB_ISO_ASAP; break; } @@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * supports different values... this uses EHCI/UHCI defaults (and * EHCI can use smaller non-default values). */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: + switch (xfertype) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: /* too small? */ if (urb->interval <= 0) return -EINVAL; @@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) // NOTE usb handles 2^15 if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; - temp = 1024 * 8; + max = 1024 * 8; break; case USB_SPEED_FULL: /* units are frames/msec */ case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { + if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; // NOTE ohci only handles up to 32 - temp = 128; + max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; // NOTE usb and ohci handle up to 2^15 - temp = 1024; + max = 1024; } break; default: return -EINVAL; } - /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; + /* Round down to a power of 2, no more than max */ + urb->interval = min(max, 1 << ilog2(urb->interval)); } return usb_hcd_submit_urb(urb, mem_flags); @@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus)) + if (!urb->dev) return -ENODEV; + if (!urb->ep) + return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } @@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb) */ void usb_kill_urb(struct urb *urb) { + static DEFINE_MUTEX(reject_mutex); + might_sleep(); - if (!(urb && urb->dev && urb->dev->bus)) + if (!(urb && urb->dev && urb->ep)) return; - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); ++urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); --urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); } /** diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0fee5c66fd6..c99938d5f78 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void) #endif /* CONFIG_PM */ + +/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ +static unsigned usb_bus_is_wusb(struct usb_bus *bus) +{ + struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self); + return hcd->wireless; +} + + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -239,6 +248,8 @@ struct usb_device * usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; + struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); + unsigned root_hub = 0; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; + atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - dev->ep_in[0] = dev->ep_out[0] = &dev->ep0; + usb_enable_endpoint(dev, &dev->ep0); + dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The @@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.parent = bus->controller; sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); + root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') @@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; #endif + if (root_hub) /* Root hub always ok [and always wired] */ + dev->authorized = 1; + else { + dev->authorized = usb_hcd->authorized_default; + dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + } return dev; } @@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb) /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * @@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; if (!dev - || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) @@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, // FIXME generic api broken like pci, can't report errors return dma_map_sg(controller, sg, nents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to synchronize * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, return; dma_sync_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to unmap * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, return; dma_unmap_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index ad5fa0338f4..c52626c51f7 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint * struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); +extern void usb_enable_endpoint(struct usb_device *dev, + struct usb_host_endpoint *ep); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device (struct usb_device *); +extern int usb_authorize_device (struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int usb_choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 767aed5b4be..f81d08d6538 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_DEBUG_FS + boolean "Debugging information files in debugfs" + depends on USB_GADGET && DEBUG_FS + help + Some of the drivers in the "gadget" framework can expose + debugging information in files under /sys/kernel/debug/. + The information in these files may help when you're + troubleshooting or bringing up a driver on a new board. + Enable these files by choosing "Y" here. If in doubt, or + to conserve kernel memory, say "N". + config USB_GADGET_SELECTED boolean @@ -103,6 +114,20 @@ config USB_AMD5536UDC default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED + depends on AVR32 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x processors from Atmel. + +config USB_ATMEL_USBA + tristate + depends on USB_GADGET_ATMEL_USBA + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -228,7 +253,6 @@ config USB_LH7A40X default USB_GADGET select USB_GADGET_SELECTED - config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 1bc0f03550c..904e57bf611 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o +obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 714156ca8fe..1c804060252 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -69,7 +69,7 @@ /* gadget stack */ #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /* udc specific */ #include "amd5536udc.h" @@ -3244,7 +3244,6 @@ static int udc_pci_probe( retval = -ENOMEM; goto finished; } - memset(dev, 0, sizeof(struct udc)); /* pci setup */ if (pci_enable_device(pdev) < 0) { @@ -3286,14 +3285,12 @@ static int udc_pci_probe( pci_set_drvdata(pdev, dev); - /* chip revision */ - dev->chiprev = 0; + /* chip revision for Hs AMD5536 */ + dev->chiprev = pdev->revision; pci_set_master(pdev); pci_set_mwi(pdev); - /* chip rev for Hs AMD5536 */ - pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev); /* init dma pools */ if (use_dma) { retval = init_dma_pools(dev); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 63d7d656869..a6adf7e0f6f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -38,7 +38,7 @@ #include <linux/proc_fs.h> #include <linux/clk.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/hardware.h> diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c new file mode 100644 index 00000000000..4fb5ff46957 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -0,0 +1,2077 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/list.h> +#include <linux/platform_device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/delay.h> + +#include <asm/gpio.h> +#include <asm/arch/board.h> + +#include "atmel_usba_udc.h" + + +static struct usba_udc the_udc; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS +#include <linux/debugfs.h> +#include <linux/uaccess.h> + +static int queue_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_ep *ep = inode->i_private; + struct usba_request *req, *req_copy; + struct list_head *queue_data; + + queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL); + if (!queue_data) + return -ENOMEM; + INIT_LIST_HEAD(queue_data); + + spin_lock_irq(&ep->udc->lock); + list_for_each_entry(req, &ep->queue, queue) { + req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC); + if (!req_copy) + goto fail; + memcpy(req_copy, req, sizeof(*req_copy)); + list_add_tail(&req_copy->queue, queue_data); + } + spin_unlock_irq(&ep->udc->lock); + + file->private_data = queue_data; + return 0; + +fail: + spin_unlock_irq(&ep->udc->lock); + list_for_each_entry_safe(req, req_copy, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return -ENOMEM; +} + +/* + * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0 + * + * b: buffer address + * l: buffer length + * I/i: interrupt/no interrupt + * Z/z: zero/no zero + * S/s: short ok/short not ok + * s: status + * n: nr_packets + * F/f: submitted/not submitted to FIFO + * D/d: using/not using DMA + * L/l: last transaction/not last transaction + */ +static ssize_t queue_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct list_head *queue = file->private_data; + struct usba_request *req, *tmp_req; + size_t len, remaining, actual = 0; + char tmpbuf[38]; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EFAULT; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + list_for_each_entry_safe(req, tmp_req, queue, queue) { + len = snprintf(tmpbuf, sizeof(tmpbuf), + "%8p %08x %c%c%c %5d %c%c%c\n", + req->req.buf, req->req.length, + req->req.no_interrupt ? 'i' : 'I', + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 's' : 'S', + req->req.status, + req->submitted ? 'F' : 'f', + req->using_dma ? 'D' : 'd', + req->last_transaction ? 'L' : 'l'); + len = min(len, sizeof(tmpbuf)); + if (len > nbytes) + break; + + list_del(&req->queue); + kfree(req); + + remaining = __copy_to_user(buf, tmpbuf, len); + actual += len - remaining; + if (remaining) + break; + + nbytes -= len; + buf += len; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + + return actual; +} + +static int queue_dbg_release(struct inode *inode, struct file *file) +{ + struct list_head *queue_data = file->private_data; + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return 0; +} + +static int regs_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_udc *udc; + unsigned int i; + u32 *data; + int ret = -ENOMEM; + + mutex_lock(&inode->i_mutex); + udc = inode->i_private; + data = kmalloc(inode->i_size, GFP_KERNEL); + if (!data) + goto out; + + spin_lock_irq(&udc->lock); + for (i = 0; i < inode->i_size / 4; i++) + data[i] = __raw_readl(udc->regs + i * 4); + spin_unlock_irq(&udc->lock); + + file->private_data = data; + ret = 0; + +out: + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static ssize_t regs_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + mutex_lock(&inode->i_mutex); + ret = simple_read_from_buffer(buf, nbytes, ppos, + file->private_data, + file->f_dentry->d_inode->i_size); + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static int regs_dbg_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +const struct file_operations queue_dbg_fops = { + .owner = THIS_MODULE, + .open = queue_dbg_open, + .llseek = no_llseek, + .read = queue_dbg_read, + .release = queue_dbg_release, +}; + +const struct file_operations regs_dbg_fops = { + .owner = THIS_MODULE, + .open = regs_dbg_open, + .llseek = generic_file_llseek, + .read = regs_dbg_read, + .release = regs_dbg_release, +}; + +static void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + struct dentry *ep_root; + + ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root); + if (!ep_root) + goto err_root; + ep->debugfs_dir = ep_root; + + ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root, + ep, &queue_dbg_fops); + if (!ep->debugfs_queue) + goto err_queue; + + if (ep->can_dma) { + ep->debugfs_dma_status + = debugfs_create_u32("dma_status", 0400, ep_root, + &ep->last_dma_status); + if (!ep->debugfs_dma_status) + goto err_dma_status; + } + if (ep_is_control(ep)) { + ep->debugfs_state + = debugfs_create_u32("state", 0400, ep_root, + &ep->state); + if (!ep->debugfs_state) + goto err_state; + } + + return; + +err_state: + if (ep->can_dma) + debugfs_remove(ep->debugfs_dma_status); +err_dma_status: + debugfs_remove(ep->debugfs_queue); +err_queue: + debugfs_remove(ep_root); +err_root: + dev_err(&ep->udc->pdev->dev, + "failed to create debugfs directory for %s\n", ep->ep.name); +} + +static void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + debugfs_remove(ep->debugfs_queue); + debugfs_remove(ep->debugfs_dma_status); + debugfs_remove(ep->debugfs_state); + debugfs_remove(ep->debugfs_dir); + ep->debugfs_dma_status = NULL; + ep->debugfs_dir = NULL; +} + +static void usba_init_debugfs(struct usba_udc *udc) +{ + struct dentry *root, *regs; + struct resource *regs_resource; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + udc->debugfs_root = root; + + regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops); + if (!regs) + goto err_regs; + + regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, + CTRL_IOMEM_ID); + regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; + udc->debugfs_regs = regs; + + usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); + + return; + +err_regs: + debugfs_remove(root); +err_root: + udc->debugfs_root = NULL; + dev_err(&udc->pdev->dev, "debugfs is not available\n"); +} + +static void usba_cleanup_debugfs(struct usba_udc *udc) +{ + usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0)); + debugfs_remove(udc->debugfs_regs); + debugfs_remove(udc->debugfs_root); + udc->debugfs_regs = NULL; + udc->debugfs_root = NULL; +} +#else +static inline void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + +} + +static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + +} + +static inline void usba_init_debugfs(struct usba_udc *udc) +{ + +} + +static inline void usba_cleanup_debugfs(struct usba_udc *udc) +{ + +} +#endif + +static int vbus_is_present(struct usba_udc *udc) +{ + if (udc->vbus_pin != -1) + return gpio_get_value(udc->vbus_pin); + + /* No Vbus detection: Assume always present */ + return 1; +} + +static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) +{ + unsigned long tmp; + + DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); + for (; len > 0; len -= 4, buf += 4, fifo += 4) { + tmp = *(unsigned long *)buf; + if (len >= 4) { + DBG(DBG_FIFO, " -> %08lx\n", tmp); + __raw_writel(tmp, fifo); + } else { + do { + DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); + __raw_writeb(tmp >> 24, fifo); + fifo++; + tmp <<= 8; + } while (--len); + break; + } + } +} + +static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +{ + union { + unsigned long *w; + unsigned char *b; + } p; + unsigned long tmp; + + DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); + for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { + if (len >= 4) { + tmp = __raw_readl(fifo); + *p.w = tmp; + DBG(DBG_FIFO, " -> %08lx\n", tmp); + } else { + do { + tmp = __raw_readb(fifo); + *p.b = tmp; + DBG(DBG_FIFO, " -> %02lx\n", tmp); + fifo++, p.b++; + } while (--len); + } + } +} + +static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) +{ + unsigned int transaction_len; + + transaction_len = req->req.length - req->req.actual; + req->last_transaction = 1; + if (transaction_len > ep->ep.maxpacket) { + transaction_len = ep->ep.maxpacket; + req->last_transaction = 0; + } else if (transaction_len == ep->ep.maxpacket && req->req.zero) + req->last_transaction = 0; + + DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", + ep->ep.name, req, transaction_len, + req->last_transaction ? ", done" : ""); + + copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + req->req.actual += transaction_len; +} + +static void submit_request(struct usba_ep *ep, struct usba_request *req) +{ + DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", + ep->ep.name, req, req->req.length); + + req->req.actual = 0; + req->submitted = 1; + + if (req->using_dma) { + if (req->req.length == 0) { + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + return; + } + + if (req->req.zero) + usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET); + else + usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET); + + usba_dma_writel(ep, ADDRESS, req->req.dma); + usba_dma_writel(ep, CONTROL, req->ctrl); + } else { + next_fifo_transaction(ep, req); + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } else { + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + } + } +} + +static void submit_next_request(struct usba_ep *ep) +{ + struct usba_request *req; + + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + if (!req->submitted) + submit_request(ep, req); +} + +static void send_status(struct usba_udc *udc, struct usba_ep *ep) +{ + ep->state = STATUS_STAGE_IN; + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); +} + +static void receive_data(struct usba_ep *ep) +{ + struct usba_udc *udc = ep->udc; + struct usba_request *req; + unsigned long status; + unsigned int bytecount, nr_busy; + int is_complete = 0; + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); + + while (nr_busy > 0) { + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + break; + } + req = list_entry(ep->queue.next, + struct usba_request, queue); + + bytecount = USBA_BFEXT(BYTE_COUNT, status); + + if (status & (1 << 31)) + is_complete = 1; + if (req->req.actual + bytecount >= req->req.length) { + is_complete = 1; + bytecount = req->req.length - req->req.actual; + } + + copy_from_fifo(req->req.buf + req->req.actual, + ep->fifo, bytecount); + req->req.actual += bytecount; + + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + + if (is_complete) { + DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); + req->req.status = 0; + list_del_init(&req->queue); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); + } + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + if (is_complete && ep_is_control(ep)) { + send_status(udc, ep); + break; + } + } +} + +static void +request_complete(struct usba_ep *ep, struct usba_request *req, int status) +{ + struct usba_udc *udc = ep->udc; + + WARN_ON(!list_empty(&req->queue)); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + if (req->mapped) { + dma_unmap_single( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + DBG(DBG_GADGET | DBG_REQ, + "%s: req %p complete: status %d, actual %u\n", + ep->ep.name, req, req->req.status, req->req.actual); + + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +static void +request_complete_list(struct usba_ep *ep, struct list_head *list, int status) +{ + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, list, queue) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } +} + +static int +usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags, ept_cfg, maxpacket; + unsigned int nr_trans; + + DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); + + maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + + if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) + || ep->index == 0 + || desc->bDescriptorType != USB_DT_ENDPOINT + || maxpacket == 0 + || maxpacket > ep->fifo_size) { + DBG(DBG_ERR, "ep_enable: Invalid argument"); + return -EINVAL; + } + + ep->is_isoc = 0; + ep->is_in = 0; + + if (maxpacket <= 8) + ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); + + DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + ep->ep.name, ept_cfg, maxpacket); + + if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + ep->is_in = 1; + ept_cfg |= USBA_EPT_DIR_IN; + } + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + break; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->can_isoc) { + DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", + ep->ep.name); + return -EINVAL; + } + + /* + * Bits 11:12 specify number of _additional_ + * transactions per microframe. + */ + nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; + if (nr_trans > 3) + return -EINVAL; + + ep->is_isoc = 1; + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + + /* + * Do triple-buffering on high-bandwidth iso endpoints. + */ + if (nr_trans > 1 && ep->nr_banks == 3) + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); + else + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ept_cfg |= USBA_BF(NB_TRANS, nr_trans); + break; + case USB_ENDPOINT_XFER_BULK: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + case USB_ENDPOINT_XFER_INT: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + + if (ep->desc) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + DBG(DBG_ERR, "ep%d already enabled\n", ep->index); + return -EBUSY; + } + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + + if (ep->can_dma) { + u32 ctrl; + + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index) + | USBA_BF(DMA_INT, 1 << ep->index))); + ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; + usba_ep_writel(ep, CTL_ENB, ctrl); + } else { + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index))); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, + (unsigned long)usba_ep_readl(ep, CFG)); + DBG(DBG_HW, "INT_ENB after init: %#08lx\n", + (unsigned long)usba_readl(udc, INT_ENB)); + + return 0; +} + +static int usba_ep_disable(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + LIST_HEAD(req_list); + unsigned long flags; + + DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); + + spin_lock_irqsave(&udc->lock, flags); + + if (!ep->desc) { + spin_unlock_irqrestore(&udc->lock, flags); + DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); + return -EINVAL; + } + ep->desc = NULL; + + list_splice_init(&ep->queue, &req_list); + if (ep->can_dma) { + usba_dma_writel(ep, CONTROL, 0); + usba_dma_writel(ep, ADDRESS, 0); + usba_dma_readl(ep, STATUS); + } + usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); + usba_writel(udc, INT_ENB, + usba_readl(udc, INT_ENB) + & ~USBA_BF(EPT_INT, 1 << ep->index)); + + request_complete_list(ep, &req_list, -ESHUTDOWN); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request * +usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct usba_request *req; + + DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + req->req.dma = DMA_ADDR_INVALID; + + return &req->req; +} + +static void +usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_request *req = to_usba_req(_req); + + DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); + + kfree(req); +} + +static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, + struct usba_request *req, gfp_t gfp_flags) +{ + unsigned long flags; + int ret; + + DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n", + ep->ep.name, req->req.length, req->req.dma, + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 'S' : 's', + req->req.no_interrupt ? 'I' : 'i'); + + if (req->req.length > 0x10000) { + /* Lengths from 0 to 65536 (inclusive) are supported */ + DBG(DBG_ERR, "invalid request length %u\n", req->req.length); + return -EINVAL; + } + + req->using_dma = 1; + + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + &udc->pdev->dev, req->req.buf, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) + | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE + | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; + + if (ep->is_in) + req->ctrl |= USBA_DMA_END_BUF_EN; + + /* + * Add this request to the queue and submit for DMA if + * possible. Check if we're still alive first -- we may have + * received a reset since last time we checked. + */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + if (list_empty(&ep->queue)) + submit_request(ep, req); + + list_add_tail(&req->queue, &ep->queue); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct usba_request *req = to_usba_req(_req); + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret; + + DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", + ep->ep.name, req, _req->length); + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) + return -ESHUTDOWN; + + req->submitted = 0; + req->using_dma = 0; + req->last_transaction = 0; + + _req->status = -EINPROGRESS; + _req->actual = 0; + + if (ep->can_dma) + return queue_dma(udc, ep, req, gfp_flags); + + /* May have received a reset since last time we checked */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->is_in || (ep_is_control(ep) + && (ep->state == DATA_STAGE_IN + || ep->state == STATUS_STAGE_IN))) + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + else + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static void +usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status) +{ + req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status); +} + +static int stop_dma(struct usba_ep *ep, u32 *pstatus) +{ + unsigned int timeout; + u32 status; + + /* + * Stop the DMA controller. When writing both CH_EN + * and LINK to 0, the other bits are not affected. + */ + usba_dma_writel(ep, CONTROL, 0); + + /* Wait for the FIFO to empty */ + for (timeout = 40; timeout; --timeout) { + status = usba_dma_readl(ep, STATUS); + if (!(status & USBA_DMA_CH_EN)) + break; + udelay(1); + } + + if (pstatus) + *pstatus = status; + + if (timeout == 0) { + dev_err(&ep->udc->pdev->dev, + "%s: timed out waiting for DMA FIFO to empty\n", + ep->ep.name); + return -ETIMEDOUT; + } + + return 0; +} + +static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + struct usba_request *req = to_usba_req(_req); + unsigned long flags; + u32 status; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", + ep->ep.name, req); + + spin_lock_irqsave(&udc->lock, flags); + + if (req->using_dma) { + /* + * If this request is currently being transferred, + * stop the DMA controller and reset the FIFO. + */ + if (ep->queue.next == &req->queue) { + status = usba_dma_readl(ep, STATUS); + if (status & USBA_DMA_CH_EN) + stop_dma(ep, &status); + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + + usba_writel(udc, EPT_RST, 1 << ep->index); + + usba_update_req(ep, req, status); + } + } + + /* + * Errors should stop the queue from advancing until the + * completion function returns. + */ + list_del_init(&req->queue); + + request_complete(ep, req, -ECONNRESET); + + /* Process the next request if any */ + submit_next_request(ep); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int usba_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret = 0; + + DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, + value ? "set" : "clear"); + + if (!ep->desc) { + DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", + ep->ep.name); + return -ENODEV; + } + if (ep->is_isoc) { + DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", + ep->ep.name); + return -ENOTTY; + } + + spin_lock_irqsave(&udc->lock, flags); + + /* + * We can't halt IN endpoints while there are still data to be + * transferred + */ + if (!list_empty(&ep->queue) + || ((value && ep->is_in && (usba_ep_readl(ep, STA) + & USBA_BF(BUSY_BANKS, -1L))))) { + ret = -EAGAIN; + } else { + if (value) + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + else + usba_ep_writel(ep, CLR_STA, + USBA_FORCE_STALL | USBA_TOGGLE_CLR); + usba_ep_readl(ep, STA); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int usba_ep_fifo_status(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + + return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); +} + +static void usba_ep_fifo_flush(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + + usba_writel(udc, EPT_RST, 1 << ep->index); +} + +static const struct usb_ep_ops usba_ep_ops = { + .enable = usba_ep_enable, + .disable = usba_ep_disable, + .alloc_request = usba_ep_alloc_request, + .free_request = usba_ep_free_request, + .queue = usba_ep_queue, + .dequeue = usba_ep_dequeue, + .set_halt = usba_ep_set_halt, + .fifo_status = usba_ep_fifo_status, + .fifo_flush = usba_ep_fifo_flush, +}; + +static int usba_udc_get_frame(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + + return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); +} + +static int usba_udc_wakeup(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + u32 ctrl; + int ret = -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + ctrl = usba_readl(udc, CTRL); + usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + if (is_selfpowered) + udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static const struct usb_gadget_ops usba_udc_ops = { + .get_frame = usba_udc_get_frame, + .wakeup = usba_udc_wakeup, + .set_selfpowered = usba_udc_set_selfpowered, +}; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ +{ \ + .ep = { \ + .ops = &usba_ep_ops, \ + .name = nam, \ + .maxpacket = maxpkt, \ + }, \ + .udc = &the_udc, \ + .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .index = idx, \ + .can_dma = dma, \ + .can_isoc = isoc, \ +} + +static struct usba_ep usba_ep[] = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1in-bulk", 1, 512, 2, 1, 1), + EP("ep2out-bulk", 2, 512, 2, 1, 1), + EP("ep3in-int", 3, 64, 3, 1, 0), + EP("ep4out-int", 4, 64, 3, 1, 0), + EP("ep5in-iso", 5, 1024, 3, 1, 1), + EP("ep6out-iso", 6, 1024, 3, 1, 1), +}; +#undef EP + +static struct usb_endpoint_descriptor usba_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = __constant_cpu_to_le16(64), + /* FIXME: I have no idea what to put here */ + .bInterval = 1, +}; + +static void nop_release(struct device *dev) +{ + +} + +static struct usba_udc the_udc = { + .gadget = { + .ops = &usba_udc_ops, + .ep0 = &usba_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "atmel_usba_udc", + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + .lock = SPIN_LOCK_UNLOCKED, +}; + +/* + * Called with interrupts disabled and udc->lock held. + */ +static void reset_all_endpoints(struct usba_udc *udc) +{ + struct usba_ep *ep; + struct usba_request *req, *tmp_req; + + usba_writel(udc, EPT_RST, ~0UL); + + ep = to_usba_ep(udc->gadget.ep0); + list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { + list_del_init(&req->queue); + request_complete(ep, req, -ECONNRESET); + } + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) { + spin_unlock(&udc->lock); + usba_ep_disable(&ep->ep); + spin_lock(&udc->lock); + } + } +} + +static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) +{ + struct usba_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return to_usba_ep(udc->gadget.ep0); + + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) + == (wIndex & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + return NULL; +} + +/* Called with interrupts disabled and udc->lock held */ +static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) +{ + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + ep->state = WAIT_FOR_SETUP; +} + +static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) +{ + if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) + return 1; + return 0; +} + +static inline void set_address(struct usba_udc *udc, unsigned int addr) +{ + u32 regval; + + DBG(DBG_BUS, "setting address %u...\n", addr); + regval = usba_readl(udc, CTRL); + regval = USBA_BFINS(DEV_ADDR, addr, regval); + usba_writel(udc, CTRL, regval); +} + +static int do_test_mode(struct usba_udc *udc) +{ + static const char test_packet_buffer[] = { + /* JKJKJKJK * 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* JJKKJJKK * 8 */ + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + /* JJKKJJKK * 8 */ + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + /* JJJJJJJKKKKKKK * 8 */ + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* JJJJJJJK * 8 */ + 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, + /* {JKKKKKKK * 10}, JK */ + 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E + }; + struct usba_ep *ep; + struct device *dev = &udc->pdev->dev; + int test_mode; + + test_mode = udc->test_mode; + + /* Start from a clean slate */ + reset_all_endpoints(udc); + + switch (test_mode) { + case 0x0100: + /* Test_J */ + usba_writel(udc, TST, USBA_TST_J_MODE); + dev_info(dev, "Entering Test_J mode...\n"); + break; + case 0x0200: + /* Test_K */ + usba_writel(udc, TST, USBA_TST_K_MODE); + dev_info(dev, "Entering Test_K mode...\n"); + break; + case 0x0300: + /* + * Test_SE0_NAK: Force high-speed mode and set up ep0 + * for Bulk IN transfers + */ + ep = &usba_ep[0]; + usba_writel(udc, TST, + USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + dev_info(dev, "Entering Test_SE0_NAK mode...\n"); + } + break; + case 0x0400: + /* Test_Packet */ + ep = &usba_ep[0]; + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_Packet: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + usba_writel(udc, TST, USBA_TST_PKT_MODE); + copy_to_fifo(ep->fifo, test_packet_buffer, + sizeof(test_packet_buffer)); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + dev_info(dev, "Entering Test_Packet mode...\n"); + } + break; + default: + dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode); + return -EINVAL; + } + + return 0; +} + +/* Avoid overly long expressions */ +static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) + return true; + return false; +} + +static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE)) + return true; + return false; +} + +static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT)) + return true; + return false; +} + +static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, + struct usb_ctrlrequest *crq) +{ + int retval = 0;; + + switch (crq->bRequest) { + case USB_REQ_GET_STATUS: { + u16 status; + + if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { + status = cpu_to_le16(udc->devstatus); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_INTERFACE)) { + status = __constant_cpu_to_le16(0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { + struct usba_ep *target; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + status = 0; + if (is_stalled(udc, target)) + status |= __constant_cpu_to_le16(1); + } else + goto delegate; + + /* Write directly to the FIFO. No queueing is done. */ + if (crq->wLength != __constant_cpu_to_le16(sizeof(status))) + goto stall; + ep->state = DATA_STAGE_IN; + __raw_writew(status, ep->fifo); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + break; + } + + case USB_REQ_CLEAR_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_remote_wakeup(crq)) + udc->devstatus + &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else + /* Can't CLEAR_FEATURE TEST_MODE */ + goto stall; + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); + if (target->index != 0) + usba_ep_writel(target, CLR_STA, + USBA_TOGGLE_CLR); + } else { + goto delegate; + } + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_test_mode(crq)) { + send_status(udc, ep); + ep->state = STATUS_STAGE_TEST; + udc->test_mode = le16_to_cpu(crq->wIndex); + return 0; + } else if (feature_is_dev_remote_wakeup(crq)) { + udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; + } else { + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); + } else + goto delegate; + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_ADDRESS: + if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) + goto delegate; + + set_address(udc, le16_to_cpu(crq->wValue)); + send_status(udc, ep); + ep->state = STATUS_STAGE_ADDR; + break; + + default: +delegate: + spin_unlock(&udc->lock); + retval = udc->driver->setup(&udc->gadget, crq); + spin_lock(&udc->lock); + } + + return retval; + +stall: + printk(KERN_ERR + "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + "halting endpoint...\n", + ep->ep.name, crq->bRequestType, crq->bRequest, + le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), + le16_to_cpu(crq->wLength)); + set_protocol_stall(udc, ep); + return -1; +} + +static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + +restart: + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", + ep->ep.name, ep->state, epstatus, epctrl); + + req = NULL; + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct usba_request, queue); + + if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } + goto restart; + } + if ((epstatus & epctrl) & USBA_TX_COMPLETE) { + usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); + + switch (ep->state) { + case DATA_STAGE_IN: + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = STATUS_STAGE_OUT; + break; + case STATUS_STAGE_ADDR: + /* Activate our new address */ + usba_writel(udc, CTRL, (usba_readl(udc, CTRL) + | USBA_FADDR_EN)); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_IN: + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + submit_next_request(ep); + } + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_TEST: + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + if (do_test_mode(udc)) + set_protocol_stall(udc, ep); + break; + default: + printk(KERN_ERR + "udc: %s: TXCOMP: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + switch (ep->state) { + case STATUS_STAGE_OUT: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + + case DATA_STAGE_OUT: + receive_data(ep); + break; + + default: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + printk(KERN_ERR + "udc: %s: RXRDY: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if (epstatus & USBA_RX_SETUP) { + union { + struct usb_ctrlrequest crq; + unsigned long data[2]; + } crq; + unsigned int pkt_len; + int ret; + + if (ep->state != WAIT_FOR_SETUP) { + /* + * Didn't expect a SETUP packet at this + * point. Clean up any pending requests (which + * may be successful). + */ + int status = -EPROTO; + + /* + * RXRDY and TXCOMP are dropped when SETUP + * packets arrive. Just pretend we received + * the status packet. + */ + if (ep->state == STATUS_STAGE_OUT + || ep->state == STATUS_STAGE_IN) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + status = 0; + } + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } + } + + pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + printk(KERN_WARNING "udc: Invalid packet length %u " + "(expected %lu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; + } + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); + copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ + usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); + + /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", + ep->state, crq.crq.bRequestType, + crq.crq.bRequest); */ + + if (crq.crq.bRequestType & USB_DIR_IN) { + /* + * The USB 2.0 spec states that "if wLength is + * zero, there is no data transfer phase." + * However, testusb #14 seems to actually + * expect a data phase even if wLength = 0... + */ + ep->state = DATA_STAGE_IN; + } else { + if (crq.crq.wLength != __constant_cpu_to_le16(0)) + ep->state = DATA_STAGE_OUT; + else + ep->state = STATUS_STAGE_IN; + } + + ret = -1; + if (ep->index == 0) + ret = handle_ep0_setup(udc, ep, &crq.crq); + else { + spin_unlock(&udc->lock); + ret = udc->driver->setup(&udc->gadget, &crq.crq); + spin_lock(&udc->lock); + } + + DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", + crq.crq.bRequestType, crq.crq.bRequest, + le16_to_cpu(crq.crq.wLength), ep->state, ret); + + if (ret < 0) { + /* Let the host know that we failed */ + set_protocol_stall(udc, ep); + } + } +} + +static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); + + while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); + + if (list_empty(&ep->queue)) { + dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n"); + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + + if (req->using_dma) { + /* Send a zero-length packet */ + usba_ep_writel(ep, SET_STA, + USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_DIS, + USBA_TX_PK_RDY); + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } else { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } + } + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); + receive_data(ep); + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + } +} + +static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 status, control, pending; + + status = usba_dma_readl(ep, STATUS); + control = usba_dma_readl(ep, CONTROL); +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + pending = status & control; + DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control); + + if (status & USBA_DMA_CH_EN) { + dev_err(&udc->pdev->dev, + "DMA_CH_EN is set after transfer is finished!\n"); + dev_err(&udc->pdev->dev, + "status=%#08x, pending=%#08x, control=%#08x\n", + status, pending, control); + + /* + * try to pretend nothing happened. We might have to + * do something here... + */ + } + + if (list_empty(&ep->queue)) + /* Might happen if a reset comes along at the right moment */ + return; + + if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) { + req = list_entry(ep->queue.next, struct usba_request, queue); + usba_update_req(ep, req, status); + + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } +} + +static irqreturn_t usba_udc_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + u32 status; + u32 dma_status; + u32 ep_status; + + spin_lock(&udc->lock); + + status = usba_readl(udc, INT_STA); + DBG(DBG_INT, "irq, status=%#08x\n", status); + + if (status & USBA_DET_SUSPEND) { + usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); + DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (status & USBA_WAKE_UP) { + usba_writel(udc, INT_CLR, USBA_WAKE_UP); + DBG(DBG_BUS, "Wake Up CPU detected\n"); + } + + if (status & USBA_END_OF_RESUME) { + usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); + DBG(DBG_BUS, "Resume detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + + dma_status = USBA_BFEXT(DMA_INT, status); + if (dma_status) { + int i; + + for (i = 1; i < USBA_NR_ENDPOINTS; i++) + if (dma_status & (1 << i)) + usba_dma_irq(udc, &usba_ep[i]); + } + + ep_status = USBA_BFEXT(EPT_INT, status); + if (ep_status) { + int i; + + for (i = 0; i < USBA_NR_ENDPOINTS; i++) + if (ep_status & (1 << i)) { + if (ep_is_control(&usba_ep[i])) + usba_control_irq(udc, &usba_ep[i]); + else + usba_ep_irq(udc, &usba_ep[i]); + } + } + + if (status & USBA_END_OF_RESET) { + struct usba_ep *ep0; + + usba_writel(udc, INT_CLR, USBA_END_OF_RESET); + reset_all_endpoints(udc); + + if (status & USBA_HIGH_SPEED) { + DBG(DBG_BUS, "High-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_HIGH; + } else { + DBG(DBG_BUS, "Full-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_FULL; + } + + ep0 = &usba_ep[0]; + ep0->desc = &usba_ep0_desc; + ep0->state = WAIT_FOR_SETUP; + usba_ep_writel(ep0, CFG, + (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) + | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); + usba_ep_writel(ep0, CTL_ENB, + USBA_EPT_ENABLE | USBA_RX_SETUP); + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1) + | USBA_DET_SUSPEND + | USBA_END_OF_RESUME)); + + if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) + dev_warn(&udc->pdev->dev, + "WARNING: EP0 configuration is invalid!\n"); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t usba_vbus_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + int vbus; + + /* debounce */ + udelay(10); + + spin_lock(&udc->lock); + + /* May happen if Vbus pin toggles during probe() */ + if (!udc->driver) + goto out; + + vbus = gpio_get_value(udc->vbus_pin); + if (vbus != udc->vbus_prev) { + if (vbus) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } else { + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + usba_writel(udc, CTRL, 0); + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + udc->vbus_prev = vbus; + } + +out: + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + int ret; + + if (!udc->pdev) + return -ENODEV; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + clk_enable(udc->pclk); + clk_enable(udc->hclk); + + ret = driver->bind(&udc->gadget); + if (ret) { + DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", + driver->driver.name, ret); + goto err_driver_bind; + } + + DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); + + udc->vbus_prev = 0; + if (udc->vbus_pin != -1) + enable_irq(gpio_to_irq(udc->vbus_pin)); + + /* If Vbus is present, enable the controller and wait for reset */ + spin_lock_irqsave(&udc->lock, flags); + if (vbus_is_present(udc) && udc->vbus_prev == 0) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; + +err_driver_bind: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return ret; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + + if (!udc->pdev) + return -ENODEV; + if (driver != udc->driver) + return -EINVAL; + + if (udc->vbus_pin != -1) + disable_irq(gpio_to_irq(udc->vbus_pin)); + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + /* This will also disable the DP pullup */ + usba_writel(udc, CTRL, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + clk_disable(udc->hclk); + clk_disable(udc->pclk); + + DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int __init usba_udc_probe(struct platform_device *pdev) +{ + struct usba_platform_data *pdata = pdev->dev.platform_data; + struct resource *regs, *fifo; + struct clk *pclk, *hclk; + struct usba_udc *udc = &the_udc; + int irq, ret, i; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); + if (!regs || !fifo) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + hclk = clk_get(&pdev->dev, "hclk"); + if (IS_ERR(hclk)) { + ret = PTR_ERR(hclk); + goto err_get_hclk; + } + + udc->pdev = pdev; + udc->pclk = pclk; + udc->hclk = hclk; + udc->vbus_pin = -1; + + ret = -ENOMEM; + udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!udc->regs) { + dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); + goto err_map_regs; + } + dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", + (unsigned long)regs->start, udc->regs); + udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1); + if (!udc->fifo) { + dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); + goto err_map_fifo; + } + dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", + (unsigned long)fifo->start, udc->fifo); + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + + platform_set_drvdata(pdev, udc); + + /* Make sure we start from a clean slate */ + clk_enable(pclk); + usba_writel(udc, CTRL, 0); + clk_disable(pclk); + + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); + usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); + usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); + usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + struct usba_ep *ep = &usba_ep[i]; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); + ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } + + ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); + if (ret) { + dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n", + irq, ret); + goto err_request_irq; + } + udc->irq = irq; + + ret = device_add(&udc->gadget.dev); + if (ret) { + dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); + goto err_device_add; + } + + if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { + udc->vbus_pin = pdata->vbus_pin; + + ret = request_irq(gpio_to_irq(udc->vbus_pin), + usba_vbus_irq, 0, + "atmel_usba_udc", udc); + if (ret) { + gpio_free(udc->vbus_pin); + udc->vbus_pin = -1; + dev_warn(&udc->pdev->dev, + "failed to request vbus irq; " + "assuming always on\n"); + } else { + disable_irq(gpio_to_irq(udc->vbus_pin)); + } + } + } + + usba_init_debugfs(udc); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_init_debugfs(udc, &usba_ep[i]); + + return 0; + +err_device_add: + free_irq(irq, udc); +err_request_irq: + iounmap(udc->fifo); +err_map_fifo: + iounmap(udc->regs); +err_map_regs: + clk_put(hclk); +err_get_hclk: + clk_put(pclk); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __exit usba_udc_remove(struct platform_device *pdev) +{ + struct usba_udc *udc; + int i; + + udc = platform_get_drvdata(pdev); + + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_cleanup_debugfs(&usba_ep[i]); + usba_cleanup_debugfs(udc); + + if (udc->vbus_pin != -1) + gpio_free(udc->vbus_pin); + + free_irq(udc->irq, udc); + iounmap(udc->fifo); + iounmap(udc->regs); + clk_put(udc->hclk); + clk_put(udc->pclk); + + device_unregister(&udc->gadget.dev); + + return 0; +} + +static struct platform_driver udc_driver = { + .remove = __exit_p(usba_udc_remove), + .driver = { + .name = "atmel_usba_udc", + }, +}; + +static int __init udc_init(void) +{ + return platform_driver_probe(&udc_driver, usba_udc_probe); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION("Atmel USBA UDC driver"); +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h new file mode 100644 index 00000000000..a68304e31a6 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -0,0 +1,352 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_USB_GADGET_USBA_UDC_H__ +#define __LINUX_USB_GADGET_USBA_UDC_H__ + +/* USB register offsets */ +#define USBA_CTRL 0x0000 +#define USBA_FNUM 0x0004 +#define USBA_INT_ENB 0x0010 +#define USBA_INT_STA 0x0014 +#define USBA_INT_CLR 0x0018 +#define USBA_EPT_RST 0x001c +#define USBA_TST 0x00e0 + +/* USB endpoint register offsets */ +#define USBA_EPT_CFG 0x0000 +#define USBA_EPT_CTL_ENB 0x0004 +#define USBA_EPT_CTL_DIS 0x0008 +#define USBA_EPT_CTL 0x000c +#define USBA_EPT_SET_STA 0x0014 +#define USBA_EPT_CLR_STA 0x0018 +#define USBA_EPT_STA 0x001c + +/* USB DMA register offsets */ +#define USBA_DMA_NXT_DSC 0x0000 +#define USBA_DMA_ADDRESS 0x0004 +#define USBA_DMA_CONTROL 0x0008 +#define USBA_DMA_STATUS 0x000c + +/* Bitfields in CTRL */ +#define USBA_DEV_ADDR_OFFSET 0 +#define USBA_DEV_ADDR_SIZE 7 +#define USBA_FADDR_EN (1 << 7) +#define USBA_EN_USBA (1 << 8) +#define USBA_DETACH (1 << 9) +#define USBA_REMOTE_WAKE_UP (1 << 10) + +/* Bitfields in FNUM */ +#define USBA_MICRO_FRAME_NUM_OFFSET 0 +#define USBA_MICRO_FRAME_NUM_SIZE 3 +#define USBA_FRAME_NUMBER_OFFSET 3 +#define USBA_FRAME_NUMBER_SIZE 11 +#define USBA_FRAME_NUM_ERROR (1 << 31) + +/* Bitfields in INT_ENB/INT_STA/INT_CLR */ +#define USBA_HIGH_SPEED (1 << 0) +#define USBA_DET_SUSPEND (1 << 1) +#define USBA_MICRO_SOF (1 << 2) +#define USBA_SOF (1 << 3) +#define USBA_END_OF_RESET (1 << 4) +#define USBA_WAKE_UP (1 << 5) +#define USBA_END_OF_RESUME (1 << 6) +#define USBA_UPSTREAM_RESUME (1 << 7) +#define USBA_EPT_INT_OFFSET 8 +#define USBA_EPT_INT_SIZE 16 +#define USBA_DMA_INT_OFFSET 24 +#define USBA_DMA_INT_SIZE 8 + +/* Bitfields in EPT_RST */ +#define USBA_RST_OFFSET 0 +#define USBA_RST_SIZE 16 + +/* Bitfields in USBA_TST */ +#define USBA_SPEED_CFG_OFFSET 0 +#define USBA_SPEED_CFG_SIZE 2 +#define USBA_TST_J_MODE (1 << 2) +#define USBA_TST_K_MODE (1 << 3) +#define USBA_TST_PKT_MODE (1 << 4) +#define USBA_OPMODE2 (1 << 5) + +/* Bitfields in EPT_CFG */ +#define USBA_EPT_SIZE_OFFSET 0 +#define USBA_EPT_SIZE_SIZE 3 +#define USBA_EPT_DIR_IN (1 << 3) +#define USBA_EPT_TYPE_OFFSET 4 +#define USBA_EPT_TYPE_SIZE 2 +#define USBA_BK_NUMBER_OFFSET 6 +#define USBA_BK_NUMBER_SIZE 2 +#define USBA_NB_TRANS_OFFSET 8 +#define USBA_NB_TRANS_SIZE 2 +#define USBA_EPT_MAPPED (1 << 31) + +/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ +#define USBA_EPT_ENABLE (1 << 0) +#define USBA_AUTO_VALID (1 << 1) +#define USBA_INTDIS_DMA (1 << 3) +#define USBA_NYET_DIS (1 << 4) +#define USBA_DATAX_RX (1 << 6) +#define USBA_MDATA_RX (1 << 7) +/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ +#define USBA_BUSY_BANK_IE (1 << 18) + +/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ +#define USBA_FORCE_STALL (1 << 5) +#define USBA_TOGGLE_CLR (1 << 6) +#define USBA_TOGGLE_SEQ_OFFSET 6 +#define USBA_TOGGLE_SEQ_SIZE 2 +#define USBA_ERR_OVFLW (1 << 8) +#define USBA_RX_BK_RDY (1 << 9) +#define USBA_KILL_BANK (1 << 9) +#define USBA_TX_COMPLETE (1 << 10) +#define USBA_TX_PK_RDY (1 << 11) +#define USBA_ISO_ERR_TRANS (1 << 11) +#define USBA_RX_SETUP (1 << 12) +#define USBA_ISO_ERR_FLOW (1 << 12) +#define USBA_STALL_SENT (1 << 13) +#define USBA_ISO_ERR_CRC (1 << 13) +#define USBA_ISO_ERR_NBTRANS (1 << 13) +#define USBA_NAK_IN (1 << 14) +#define USBA_ISO_ERR_FLUSH (1 << 14) +#define USBA_NAK_OUT (1 << 15) +#define USBA_CURRENT_BANK_OFFSET 16 +#define USBA_CURRENT_BANK_SIZE 2 +#define USBA_BUSY_BANKS_OFFSET 18 +#define USBA_BUSY_BANKS_SIZE 2 +#define USBA_BYTE_COUNT_OFFSET 20 +#define USBA_BYTE_COUNT_SIZE 11 +#define USBA_SHORT_PACKET (1 << 31) + +/* Bitfields in DMA_CONTROL */ +#define USBA_DMA_CH_EN (1 << 0) +#define USBA_DMA_LINK (1 << 1) +#define USBA_DMA_END_TR_EN (1 << 2) +#define USBA_DMA_END_BUF_EN (1 << 3) +#define USBA_DMA_END_TR_IE (1 << 4) +#define USBA_DMA_END_BUF_IE (1 << 5) +#define USBA_DMA_DESC_LOAD_IE (1 << 6) +#define USBA_DMA_BURST_LOCK (1 << 7) +#define USBA_DMA_BUF_LEN_OFFSET 16 +#define USBA_DMA_BUF_LEN_SIZE 16 + +/* Bitfields in DMA_STATUS */ +#define USBA_DMA_CH_ACTIVE (1 << 1) +#define USBA_DMA_END_TR_ST (1 << 4) +#define USBA_DMA_END_BUF_ST (1 << 5) +#define USBA_DMA_DESC_LOAD_ST (1 << 6) + +/* Constants for SPEED_CFG */ +#define USBA_SPEED_CFG_NORMAL 0 +#define USBA_SPEED_CFG_FORCE_HIGH 2 +#define USBA_SPEED_CFG_FORCE_FULL 3 + +/* Constants for EPT_SIZE */ +#define USBA_EPT_SIZE_8 0 +#define USBA_EPT_SIZE_16 1 +#define USBA_EPT_SIZE_32 2 +#define USBA_EPT_SIZE_64 3 +#define USBA_EPT_SIZE_128 4 +#define USBA_EPT_SIZE_256 5 +#define USBA_EPT_SIZE_512 6 +#define USBA_EPT_SIZE_1024 7 + +/* Constants for EPT_TYPE */ +#define USBA_EPT_TYPE_CONTROL 0 +#define USBA_EPT_TYPE_ISO 1 +#define USBA_EPT_TYPE_BULK 2 +#define USBA_EPT_TYPE_INT 3 + +/* Constants for BK_NUMBER */ +#define USBA_BK_NUMBER_ZERO 0 +#define USBA_BK_NUMBER_ONE 1 +#define USBA_BK_NUMBER_DOUBLE 2 +#define USBA_BK_NUMBER_TRIPLE 3 + +/* Bit manipulation macros */ +#define USBA_BF(name, value) \ + (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ + << USBA_##name##_OFFSET) +#define USBA_BFEXT(name, value) \ + (((value) >> USBA_##name##_OFFSET) \ + & ((1 << USBA_##name##_SIZE) - 1)) +#define USBA_BFINS(name, value, old) \ + (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ + << USBA_##name##_OFFSET)) \ + | USBA_BF(name, value)) + +/* Register access macros */ +#define usba_readl(udc, reg) \ + __raw_readl((udc)->regs + USBA_##reg) +#define usba_writel(udc, reg, value) \ + __raw_writel((value), (udc)->regs + USBA_##reg) +#define usba_ep_readl(ep, reg) \ + __raw_readl((ep)->ep_regs + USBA_EPT_##reg) +#define usba_ep_writel(ep, reg, value) \ + __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) +#define usba_dma_readl(ep, reg) \ + __raw_readl((ep)->dma_regs + USBA_DMA_##reg) +#define usba_dma_writel(ep, reg, value) \ + __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) + +/* Calculate base address for a given endpoint or DMA controller */ +#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) +#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) +#define USBA_FIFO_BASE(x) ((x) << 16) + +/* Synth parameters */ +#define USBA_NR_ENDPOINTS 7 + +#define EP0_FIFO_SIZE 64 +#define EP0_EPT_SIZE USBA_EPT_SIZE_64 +#define EP0_NR_BANKS 1 + +/* + * REVISIT: Try to eliminate this value. Can we rely on req->mapped to + * provide this information? + */ +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + +#ifdef DEBUG +#define DBG_ERR 0x0001 /* report all error returns */ +#define DBG_HW 0x0002 /* debug hardware initialization */ +#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ +#define DBG_INT 0x0008 /* interrupts */ +#define DBG_BUS 0x0010 /* report changes in bus state */ +#define DBG_QUEUE 0x0020 /* debug request queue processing */ +#define DBG_FIFO 0x0040 /* debug FIFO contents */ +#define DBG_DMA 0x0080 /* debug DMA handling */ +#define DBG_REQ 0x0100 /* print out queued request length */ +#define DBG_ALL 0xffff +#define DBG_NONE 0x0000 + +#define DEBUG_LEVEL (DBG_ERR) +#define DBG(level, fmt, ...) \ + do { \ + if ((level) & DEBUG_LEVEL) \ + printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + } while (0) +#else +#define DBG(level, fmt...) +#endif + +enum usba_ctrl_state { + WAIT_FOR_SETUP, + DATA_STAGE_IN, + DATA_STAGE_OUT, + STATUS_STAGE_IN, + STATUS_STAGE_OUT, + STATUS_STAGE_ADDR, + STATUS_STAGE_TEST, +}; +/* + EP_STATE_IDLE, + EP_STATE_SETUP, + EP_STATE_IN_DATA, + EP_STATE_OUT_DATA, + EP_STATE_SET_ADDR_STATUS, + EP_STATE_RX_STATUS, + EP_STATE_TX_STATUS, + EP_STATE_HALT, +*/ + +struct usba_dma_desc { + dma_addr_t next; + dma_addr_t addr; + u32 ctrl; +}; + +struct usba_ep { + int state; + void __iomem *ep_regs; + void __iomem *dma_regs; + void __iomem *fifo; + struct usb_ep ep; + struct usba_udc *udc; + + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + + u16 fifo_size; + u8 nr_banks; + u8 index; + unsigned int can_dma:1; + unsigned int can_isoc:1; + unsigned int is_isoc:1; + unsigned int is_in:1; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + u32 last_dma_status; + struct dentry *debugfs_dir; + struct dentry *debugfs_queue; + struct dentry *debugfs_dma_status; + struct dentry *debugfs_state; +#endif +}; + +struct usba_request { + struct usb_request req; + struct list_head queue; + + u32 ctrl; + + unsigned int submitted:1; + unsigned int last_transaction:1; + unsigned int using_dma:1; + unsigned int mapped:1; +}; + +struct usba_udc { + /* Protect hw registers from concurrent modifications */ + spinlock_t lock; + + void __iomem *regs; + void __iomem *fifo; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + int irq; + int vbus_pin; + struct clk *pclk; + struct clk *hclk; + + u16 devstatus; + + u16 test_mode; + int vbus_prev; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *debugfs_regs; +#endif +}; + +static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) +{ + return container_of(ep, struct usba_ep, ep); +} + +static inline struct usba_request *to_usba_req(struct usb_request *req) +{ + return container_of(req, struct usba_request, req); +} + +static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct usba_udc, gadget); +} + +#define ep_is_control(ep) ((ep)->index == 0) +#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) + +#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index c6760aee1e5..a4e54b2743f 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -25,7 +25,7 @@ #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /** diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d008d1360a7..9db2482bdfa 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -46,7 +46,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/usb.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = { static int dummy_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; unsigned long flags; + int rc; if (!urb->transfer_buffer && urb->transfer_buffer_length) return -EINVAL; @@ -980,6 +980,11 @@ static int dummy_urb_enqueue ( dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + rc = usb_hcd_link_urb_to_ep(hcd, urb); + if (rc) { + kfree(urbp); + goto done; + } if (!dum->udev) { dum->udev = urb->dev; @@ -996,36 +1001,35 @@ static int dummy_urb_enqueue ( if (!timer_pending (&dum->timer)) mod_timer (&dum->timer, jiffies + 1); - spin_unlock_irqrestore (&dum->lock, flags); - return 0; + done: + spin_unlock_irqrestore(&dum->lock, flags); + return rc; } -static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct dummy *dum; unsigned long flags; + int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!rc && dum->rh_state != DUMMY_RH_RUNNING && + !list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); - spin_unlock_irqrestore (&dum->lock, flags); - return 0; -} -static void maybe_set_status (struct urb *urb, int status) -{ - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - spin_unlock (&urb->lock); + spin_unlock_irqrestore (&dum->lock, flags); + return rc; } /* transfer up to a frame's worth; caller must own lock */ static int -transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, + int *status) { struct dummy_request *req; @@ -1088,24 +1092,20 @@ top: * * partially filling a buffer optionally blocks queue advances * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. so we only show part - * of the URB_SHORT_NOT_OK effect: completion status. + * need to emulate such data-in-flight. */ if (is_short) { if (host_len == dev_len) { req->req.status = 0; - maybe_set_status (urb, 0); + *status = 0; } else if (to_host) { req->req.status = 0; if (dev_len > host_len) - maybe_set_status (urb, -EOVERFLOW); + *status = -EOVERFLOW; else - maybe_set_status (urb, - (urb->transfer_flags - & URB_SHORT_NOT_OK) - ? -EREMOTEIO : 0); + *status = 0; } else if (!to_host) { - maybe_set_status (urb, 0); + *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; else @@ -1119,9 +1119,8 @@ top: req->req.status = 0; if (urb->transfer_buffer_length == urb->actual_length && !(urb->transfer_flags - & URB_ZERO_PACKET)) { - maybe_set_status (urb, 0); - } + & URB_ZERO_PACKET)) + *status = 0; } /* device side completion --> continuable */ @@ -1137,7 +1136,7 @@ top: } /* host side completion --> terminate */ - if (urb->status != -EINPROGRESS) + if (*status != -EINPROGRESS) break; /* rescan to continue with any other queued i/o */ @@ -1248,12 +1247,12 @@ restart: u8 address; struct dummy_ep *ep = NULL; int type; + int status = -EINPROGRESS; urb = urbp->urb; - if (urb->status != -EINPROGRESS) { - /* likely it was just unlinked */ + if (urb->unlinked) goto return_urb; - } else if (dum->rh_state != DUMMY_RH_RUNNING) + else if (dum->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); @@ -1274,7 +1273,7 @@ restart: dev_dbg (dummy_dev(dum), "no ep configured for urb %p\n", urb); - maybe_set_status (urb, -EPROTO); + status = -EPROTO; goto return_urb; } @@ -1289,7 +1288,7 @@ restart: /* NOTE: must not be iso! */ dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", ep->ep.name, urb); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; goto return_urb; } /* FIXME make sure both ends agree on maxpacket */ @@ -1307,7 +1306,7 @@ restart: w_value = le16_to_cpu(setup.wValue); if (le16_to_cpu(setup.wLength) != urb->transfer_buffer_length) { - maybe_set_status (urb, -EOVERFLOW); + status = -EOVERFLOW; goto return_urb; } @@ -1337,7 +1336,7 @@ restart: if (setup.bRequestType != Dev_Request) break; dum->address = w_value; - maybe_set_status (urb, 0); + status = 0; dev_dbg (udc_dev(dum), "set_address = %d\n", w_value); value = 0; @@ -1364,7 +1363,7 @@ restart: if (value == 0) { dum->devstatus |= (1 << w_value); - maybe_set_status (urb, 0); + status = 0; } } else if (setup.bRequestType == Ep_Request) { @@ -1376,7 +1375,7 @@ restart: } ep2->halted = 1; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_CLEAR_FEATURE: @@ -1386,7 +1385,7 @@ restart: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); value = 0; - maybe_set_status (urb, 0); + status = 0; break; default: value = -EOPNOTSUPP; @@ -1401,7 +1400,7 @@ restart: } ep2->halted = 0; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_GET_STATUS: @@ -1438,7 +1437,7 @@ restart: urb->actual_length = min (2, urb->transfer_buffer_length); value = 0; - maybe_set_status (urb, 0); + status = 0; } break; } @@ -1465,7 +1464,7 @@ restart: dev_dbg (udc_dev(dum), "setup --> %d\n", value); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; urb->actual_length = 0; } @@ -1482,7 +1481,7 @@ restart: * report random errors, to debug drivers. */ limit = max (limit, periodic_bytes (dum, ep)); - maybe_set_status (urb, -ENOSYS); + status = -ENOSYS; break; case PIPE_INTERRUPT: @@ -1496,23 +1495,23 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer (dum, urb, ep, limit); + total = transfer(dum, urb, ep, limit, &status); break; } /* incomplete transfer? */ - if (urb->status == -EINPROGRESS) + if (status == -EINPROGRESS) continue; return_urb: - urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) ep->already_seen = ep->setup_stage = 0; + usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); - usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); + usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); spin_lock (&dum->lock); goto restart; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 3aa46cfa66b..f9d07108bc3 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -28,7 +28,7 @@ #include <linux/string.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f70055473a0..9e732bff9df 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -19,40 +19,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* #define VERBOSE_DEBUG */ -// #define DEBUG 1 -// #define VERBOSE - -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> #include <linux/utsname.h> #include <linux/device.h> -#include <linux/moduleparam.h> #include <linux/ctype.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/usb/ch9.h> #include <linux/usb/cdc.h> -#include <linux/usb_gadget.h> - -#include <linux/random.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); #define qlen(gadget) \ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) -/* also defer IRQs on highspeed TX */ -#define TX_DELAY qmult - static inline int BITRATE(struct usb_gadget *g) { return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; } #else /* full speed (low speed doesn't do bulk) */ + +#define qmult 1 + #define DEVSPEED USB_SPEED_FULL #define qlen(gadget) DEFAULT_QLEN @@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g) do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DEBUG #else #define VDEBUG(dev,fmt,args...) \ @@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = { }; #endif -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else - -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) (((void)(g)), (fs)) - -static inline void __init hs_subset_descriptors(void) +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) { + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; } -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = { * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, - u8 *buf, u8 type, - unsigned index, int is_otg) +config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) { int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); + int hs = 0; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(g)) { + hs = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) -#else -#define which_fn(t) (fs_ ## t ## _function) -#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; @@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) if (number) eth_reset_config (dev); usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); + gadget_is_otg(dev->gadget) ? 8 : 100); } else { char *speed; unsigned power; @@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (value >= 0) value = min (wLength, (u16) value); break; @@ -1585,12 +1553,12 @@ done_set_intf: && rndis_control_intf.bInterfaceNumber == wIndex) { u8 *buf; + u32 n; /* return the result */ - buf = rndis_get_next_response (dev->rndis_config, - &value); + buf = rndis_get_next_response(dev->rndis_config, &n); if (buf) { - memcpy (req->buf, buf, value); + memcpy(req->buf, buf, n); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); } @@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } spin_lock_irqsave(&dev->req_lock, flags); + /* + * this freelist can be empty if an interrupt triggered disconnect() + * and reconfigured the gadget (shutting down this queue) after the + * network stack decided to xmit but before we got the spinlock. + */ + if (list_empty(&dev->tx_reqs)) { + spin_unlock_irqrestore(&dev->req_lock, flags); + return 1; + } + req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + + /* temporarily stop TX queue when the freelist empties */ if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); spin_unlock_irqrestore(&dev->req_lock, flags); @@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) req->length = length; -#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) - : 0; -#endif + if (gadget_is_dualspeed(dev->gadget)) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) + : 0; retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { @@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net) } if (rndis_active(dev)) { - rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } @@ -2443,26 +2421,28 @@ autoconf_fail: if (rndis) device_desc.bNumConfigurations = 2; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + if (gadget_is_dualspeed(gadget)) { + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; + if (status_ep) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif -#endif /* DUALSPEED */ + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; @@ -2598,12 +2578,11 @@ fail0: if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; - if (rndis_set_param_vendor (dev->rndis_config, vendorID, - manufacturer)) + if (rndis_set_param_vendor(dev->rndis_config, vendorID, + manufacturer)) goto fail0; - if (rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, - 0)) + if (rndis_set_param_medium(dev->rndis_config, + NDIS_MEDIUM_802_3, 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 965ad7bec7b..73726c570a6 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003-2005 Alan Stern + * Copyright (C) 2003-2007 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -217,17 +217,11 @@ */ -#undef DEBUG -#undef VERBOSE -#undef DUMP_MSGS - +/* #define VERBOSE_DEBUG */ +/* #define DUMP_MSGS */ -#include <asm/system.h> -#include <asm/uaccess.h> -#include <linux/bitops.h> #include <linux/blkdev.h> -#include <linux/compiler.h> #include <linux/completion.h> #include <linux/dcache.h> #include <linux/delay.h> @@ -235,18 +229,10 @@ #include <linux/fcntl.h> #include <linux/file.h> #include <linux/fs.h> -#include <linux/init.h> -#include <linux/kernel.h> #include <linux/kref.h> #include <linux/kthread.h> #include <linux/limits.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pagemap.h> #include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/signal.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -254,7 +240,7 @@ #include <linux/utsname.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -263,7 +249,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 November 2005" +#define DRIVER_VERSION "7 August 2007" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define xprintk(f,level,fmt,args...) \ - dev_printk(level , &(f)->gadget->dev , fmt , ## args) -#define yprintk(l,level,fmt,args...) \ - dev_printk(level , &(l)->dev , fmt , ## args) - #ifdef DEBUG -#define DBG(fsg,fmt,args...) \ - xprintk(fsg , KERN_DEBUG , fmt , ## args) #define LDBG(lun,fmt,args...) \ - yprintk(lun , KERN_DEBUG , fmt , ## args) + dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else -#define DBG(fsg,fmt,args...) \ - do { } while (0) #define LDBG(lun,fmt,args...) \ do { } while (0) #define MDBG(fmt,args...) \ do { } while (0) -#undef VERBOSE +#undef VERBOSE_DEBUG #undef DUMP_MSGS #endif /* DEBUG */ -#ifdef VERBOSE -#define VDBG DBG +#ifdef VERBOSE_DEBUG #define VLDBG LDBG #else -#define VDBG(fsg,fmt,args...) \ - do { } while (0) #define VLDBG(lun,fmt,args...) \ do { } while (0) -#endif /* VERBOSE */ +#endif /* VERBOSE_DEBUG */ -#define ERROR(fsg,fmt,args...) \ - xprintk(fsg , KERN_ERR , fmt , ## args) #define LERROR(lun,fmt,args...) \ - yprintk(lun , KERN_ERR , fmt , ## args) - -#define WARN(fsg,fmt,args...) \ - xprintk(fsg , KERN_WARNING , fmt , ## args) + dev_err(&(lun)->dev , fmt , ## args) #define LWARN(lun,fmt,args...) \ - yprintk(lun , KERN_WARNING , fmt , ## args) - -#define INFO(fsg,fmt,args...) \ - xprintk(fsg , KERN_INFO , fmt , ## args) + dev_warn(&(lun)->dev , fmt , ## args) #define LINFO(lun,fmt,args...) \ - yprintk(lun , KERN_INFO , fmt , ## args) + dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) + /*-------------------------------------------------------------------------*/ @@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - int num_filenames; - int num_ros; + unsigned int num_filenames; + unsigned int num_ros; unsigned int nluns; int removable; @@ -578,7 +555,7 @@ struct lun { #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static inline struct lun *dev_to_lun(struct device *dev) +static struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -711,13 +688,13 @@ struct fsg_dev { typedef void (*fsg_routine_t)(struct fsg_dev *); -static int inline exception_in_progress(struct fsg_dev *fsg) +static int exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void inline set_bulk_out_req_length(struct fsg_dev *fsg, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -743,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg); static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) { - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG(fsg, "%s, length %u:\n", label, length); - - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; + if (length < 512) { + DBG(fsg, "%s, length %u:\n", label, length); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, buf, length, 0); } } -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) {} #else -static void inline dump_msg(struct fsg_dev *fsg, const char *label, +static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -static void inline dump_cdb(struct fsg_dev *fsg) -{ - int i; - char cmdbuf[3*MAX_COMMAND_SIZE + 1]; +#ifdef VERBOSE_DEBUG - for (i = 0; i < fsg->cmnd_size; ++i) - sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); - VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +static void dump_cdb(struct fsg_dev *fsg) +{ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, + 16, 1, fsg->cmnd, fsg->cmnd_size, 0); } +#else + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#endif /* VERBOSE_DEBUG */ #endif /* DUMP_MSGS */ @@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 inline get_be16(u8 *buf) +static u16 get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 inline get_be32(u8 *buf) +static u32 get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void inline put_be16(u8 *buf, u16 val) +static void put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void inline put_be32(u8 *buf, u32 val) +static void put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = { #define FS_FUNCTION_PRE_EP_ENTRIES 2 -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) - -#else - -/* If there's no high speed support, always use the full-speed descriptor. */ -#define ep_desc(g,fs,hs) fs - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1053,26 +1014,22 @@ static struct usb_gadget_strings stringtab = { static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { -#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; -#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) function = hs_function; else -#endif function = fs_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); @@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg, value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); @@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; goto get_config; -#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef CONFIG_USB_GADGET_DUALSPEED - get_config: -#endif +get_config: value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg) } /* Wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg) /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg) } /* Otherwise wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } return 0; @@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } fsg->phase_error = 0; fsg->short_packet_received = 0; @@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW meaningful? */ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); @@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); @@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } smp_rmb(); rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; @@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Is the previous status interrupt request still busy? * The host is allowed to skip reading the status, @@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, - buf, PAGE_SIZE - 1); + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char } -static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const return rc; } -static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) - i = max(mod_data.num_filenames, 1); + i = max(mod_data.num_filenames, 1u); if (i > MAX_LUNS) { ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; @@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget) intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + if (gadget_is_dualspeed(gadget)) { + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume that all endpoint addresses are the same for both speeds */ - hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; - hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; -#endif + /* Assume endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = + fs_intr_in_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) otg_desc.bmAttributes |= USB_OTG_HNP; - } rc = -ENOMEM; diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index d57bcfbc08a..9bb7f64a85c 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -35,7 +35,7 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <linux/usb/otg.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> @@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) */ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) { -#ifdef CONFIG_USB_OTG struct fsl_udc *udc; udc = container_of(gadget, struct fsl_udc, gadget); - if (udc->transceiver) return otg_set_power(udc->transceiver, mA); -#endif return -ENOTSUPP; } @@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } -/* defined in usb_gadget.h */ +/* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, @@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc, | USB_TYPE_STANDARD)) { /* Note: The driver has not include OTG support yet. * This will be set when OTG support is added */ - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) break; else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) udc->gadget.b_hnp_enable = 1; @@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc, else if (setup->bRequest == USB_DEVICE_A_ALT_HNP_SUPPORT) udc->gadget.a_alt_hnp_support = 1; + else + break; rc = 0; } else break; @@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; -#ifdef CONFIG_USB_OTG if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); -#endif /* stop DR, disable intr */ dr_controller_stop(udc_controller); diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 1c5aa49d743..0689189550b 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -18,17 +18,11 @@ * http://www.usb.org/developers/devclass_docs/midi10.pdf */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/init.h> #include <linux/utsname.h> #include <linux/device.h> -#include <linux/moduleparam.h> #include <sound/driver.h> #include <sound/core.h> @@ -36,7 +30,7 @@ #include <sound/rawmidi.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <linux/usb/audio.h> #include <linux/usb/midi.h> @@ -139,30 +133,16 @@ struct gmidi_device { static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) static unsigned buflen = 256; @@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget, return len; } -static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; @@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = { * Receives a chunk of MIDI data. */ static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t* data, int length) + uint8_t *data, int length) { struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ @@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) { int err = 0; struct usb_request *req; - struct usb_ep* ep; + struct usb_ep *ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); @@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); @@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget) static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) { struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card* card; + struct snd_card *card; DBG(dev, "unbind\n"); @@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device) return 0; } -static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, +static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3) { unsigned length = req->length; + u8 *buf = (u8 *)req->buf + length; - uint8_t* buf = (uint8_t*)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, /* * Converts MIDI commands to USB MIDI packets. */ -static void gmidi_transmit_byte(struct usb_request* req, - struct gmidi_in_port* port, uint8_t b) +static void gmidi_transmit_byte(struct usb_request *req, + struct gmidi_in_port *port, uint8_t b) { uint8_t p0 = port->cable; @@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req, } } -static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) +static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) { - struct usb_ep* ep = dev->in_ep; - struct gmidi_in_port* port = &dev->in_port; + struct usb_ep *ep = dev->in_ep; + struct gmidi_in_port *port = &dev->in_port; if (!ep) { return; @@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) static void gmidi_in_tasklet(unsigned long data) { - struct gmidi_device* dev = (struct gmidi_device*)data; + struct gmidi_device *dev = (struct gmidi_device *)data; gmidi_transmit(dev, NULL); } static int gmidi_in_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; @@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream) static int gmidi_in_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_in_close\n"); return 0; } static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; @@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) static int gmidi_out_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; @@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream) static int gmidi_out_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_out_close\n"); return 0; } static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 349b8166f34..2ec9d196a8c 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -37,7 +37,7 @@ #include <linux/proc_fs.h> #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 173004f60fe..47ef8bd58a0 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,8 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ -// #define VERBOSE /* extra debug messages (success too) */ +/* #define VERBOSE_DEBUG */ #include <linux/init.h> #include <linux/module.h> @@ -38,7 +37,7 @@ #include <linux/moduleparam.h> #include <linux/usb/gadgetfs.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /* @@ -253,7 +252,7 @@ static const char *CHIP; do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DBG #else #define VDEBUG(dev,fmt,args...) \ @@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (dev->gadget->speed == USB_SPEED_HIGH) + + if (gadget_is_dualspeed(dev->gadget) + && (dev->gadget->speed + == USB_SPEED_HIGH)) power = dev->hs_config->bMaxPower; else -#endif power = dev->config->bMaxPower; usb_gadget_vbus_draw(dev->gadget, 2 * power); } @@ -1355,24 +1355,21 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs; -#endif + int hs = 0; /* only one configuration */ if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(dev->gadget)) { + hs = (dev->gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) { dev->req->buf = dev->hs_config; len = le16_to_cpu(dev->hs_config->wTotalLength); - } else -#endif - { + } else { dev->req->buf = dev->config; len = le16_to_cpu(dev->config->wTotalLength); } @@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) { + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH + && dev->hs_config == NULL) { spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* CONFIG_USB_GADGET_DUALSPEED */ dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) { + + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; - } else -#endif - { + } else { config = dev->config->bConfigurationValue; power = dev->config->bMaxPower; } diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index b3fe197e1ee..1ecfd6366b9 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -50,7 +50,7 @@ #include <asm/hardware.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /* * Memory map diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 4b27d12f049..ebc5536aa27 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -27,7 +27,7 @@ #include <linux/platform_device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "m66592-udc.h" diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c3d364ecd4f..d5d473f8144 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -62,7 +62,7 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 9b0f0925ddd..87c4f50dfb6 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include <linux/moduleparam.h> #include <linux/platform_device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <linux/usb/otg.h> #include <linux/dma-mapping.h> #include <linux/clk.h> @@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc) udc->gadget.dev.parent->power.power_state = PMSG_ON; udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG |= OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; } static void pullup_disable(struct omap_udc *udc) { -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG &= ~OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } @@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc) { u16 devstat; - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) return; if (OTG_CTRL_REG & OTG_ID) diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1407ad1c812..3e715082de3 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -54,7 +54,7 @@ #include <asm/hardware.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/mach/udc_pxa2xx.h> diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 0be80c635c4..e3e90f8a75e 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -42,7 +42,7 @@ #include <linux/seq_file.h> #include <linux/usb.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ce4d2e09633..f5738eb8e76 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -17,34 +17,15 @@ * */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> #include <linux/utsname.h> -#include <linux/wait.h> -#include <linux/proc_fs.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/mutex.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/unaligned.h> -#include <asm/uaccess.h> #include <linux/usb/ch9.h> #include <linux/usb/cdc.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -89,30 +70,29 @@ #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS -/* select highspeed/fullspeed, hiding highspeed if not configured */ -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs)) -#else -#define GS_SPEED_SELECT(is_hs,hs,fs) (fs) -#endif /* CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +static inline struct usb_endpoint_descriptor * +choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + /* debug settings */ -#ifdef GS_DEBUG +#ifdef DEBUG static int debug = 1; +#else +#define debug 0 +#endif #define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) #define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) -#else - -#define gs_debug(format, arg...) \ - do { } while(0) -#define gs_debug_level(level, format, arg...) \ - do { } while(0) - -#endif /* GS_DEBUG */ /* Thanks to NetChip Technologies for donating this product ID. * @@ -147,10 +127,10 @@ struct gs_req_entry { /* the port structure holds info for each port, one for each minor number */ struct gs_port { - struct gs_dev *port_dev; /* pointer to device struct */ + struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; - int port_num; + int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ @@ -188,7 +168,7 @@ static void __exit gs_module_exit(void); /* tty driver */ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); -static int gs_write(struct tty_struct *tty, +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); static void gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); @@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req); static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, @@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = { }; static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { - .bLength = sizeof(gs_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - .bDataInterface = 1, /* index of data interface */ + .bLength = sizeof(gs_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 1, /* index of data interface */ }; static struct usb_cdc_acm_descriptor gs_acm_descriptor = { - .bLength = sizeof(gs_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bLength = sizeof(gs_acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = { .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; - + static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { NULL, }; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - /* Module */ MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); -#ifdef GS_DEBUG +#ifdef DEBUG module_param(debug, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); #endif @@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) return; } - gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2)); + gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", + port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); @@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev) len = gs_send_packet(dev, req->buf, ep->maxpacket); if (len > 0) { -gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2)); + gs_debug_level(3, "gs_send: len=%d, 0x%2.2x " + "0x%2.2x 0x%2.2x ...\n", len, + *((unsigned char *)req->buf), + *((unsigned char *)req->buf+1), + *((unsigned char *)req->buf+2)); list_del(&req_entry->re_entry); req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); @@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) switch(req->status) { case 0: - /* normal completion */ + /* normal completion */ gs_recv_packet(dev, req->buf, req->actual); requeue: req->length = ep->maxpacket; @@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget) ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - gs_qualifier_desc.bDeviceClass = use_acm - ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; - /* assume ep0 uses the same packet size for both speeds */ - gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; - /* assume endpoints are dual-speed */ - gs_highspeed_notify_desc.bEndpointAddress = - gs_fullspeed_notify_desc.bEndpointAddress; - gs_highspeed_in_desc.bEndpointAddress = - gs_fullspeed_in_desc.bEndpointAddress; - gs_highspeed_out_desc.bEndpointAddress = - gs_fullspeed_out_desc.bEndpointAddress; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ + if (gadget_is_dualspeed(gadget)) { + gs_qualifier_desc.bDeviceClass = use_acm + ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = + gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_notify_desc.bEndpointAddress = + gs_fullspeed_notify_desc.bEndpointAddress; + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; + } usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) dev->dev_ctrl_req = NULL; } gs_free_ports(dev); + if (dev->dev_notify_ep) + usb_ep_disable(dev->dev_notify_ep); + if (dev->dev_in_ep) + usb_ep_disable(dev->dev_in_ep); + if (dev->dev_out_ep) + usb_ep_disable(dev->dev_out_ep); kfree(dev); set_gadget_data(gadget, NULL); } @@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget, memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); @@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget, break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* fall through */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - ret = gs_build_config_buf(req->buf, gadget->speed, + ret = gs_build_config_buf(req->buf, gadget, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (ret >= 0) ret = min(wLength, (u16)ret); break; @@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_IN_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, - &gs_highspeed_in_desc, + ep_desc = choose_ep_desc(gadget, + &gs_highspeed_in_desc, &gs_fullspeed_in_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { @@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_out_desc, &gs_fullspeed_out_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev) * Builds the config descriptors in the given buffer and returns the * length, or a negative error number. */ -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg) { int len; - int high_speed; + int high_speed = 0; const struct usb_config_descriptor *config_desc; const struct usb_descriptor_header **function; @@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, return -EINVAL; /* other speed switches high and full speed */ - high_speed = (speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - high_speed = !high_speed; + if (gadget_is_dualspeed(g)) { + high_speed = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + high_speed = !high_speed; + } if (use_acm) { config_desc = &gs_acm_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_acm_highspeed_function, - gs_acm_fullspeed_function); + function = high_speed + ? gs_acm_highspeed_function + : gs_acm_fullspeed_function; } else { config_desc = &gs_bulk_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_bulk_highspeed_function, - gs_bulk_fullspeed_function); + function = high_speed + ? gs_bulk_highspeed_function + : gs_bulk_fullspeed_function; } /* for now, don't advertise srp-only devices */ diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 3459ea6c6c0..878e428a0ec 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -15,7 +15,7 @@ #include <linux/init.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/unaligned.h> diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcfe869acb9..fcde5d9c87d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1,38 +1,22 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003-2007 David Brownell * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * 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. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that 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. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -57,40 +41,28 @@ * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this * driver does). + * + * Why is *this* driver using two configurations, rather than setting up + * two interfaces with different functions? To help verify that multiple + * configuration infrastucture is working correctly; also, so that it can + * work with low capability USB controllers without four bulk endpoints. */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> #include <linux/utsname.h> #include <linux/device.h> -#include <linux/moduleparam.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/unaligned.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "St Patrick's Day 2004" +#define DRIVER_VERSION "Lughnasadh, 2007" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -131,30 +103,16 @@ struct zero_dev { struct timer_list resume; }; -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { }; /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +static char manufacturer[50]; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +/* default serial number takes at least two packets */ +static char serial[] = "0123456789.0123456789.0123456789"; -static char manufacturer [50]; -static char serial [40]; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget, int is_source_sink; int len; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (gadget->speed == USB_SPEED_HIGH); -#endif + int hs = 0; /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; is_source_sink = loopdefault ? (index == 1) : (index == 0); -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(gadget)) { + hs = (gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else -#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf (is_source_sink @@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /*-------------------------------------------------------------------------*/ +/* + * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals, + * this just sinks bulk packets OUT to the peripheral and sources them IN + * to the host, optionally with specific data patterns. + * + * In terms of control messaging, this supports all the standard requests + * plus two that support control-OUT tests. + * + * Note that because this doesn't queue more than one request at a time, + * some other function must be used to test queueing logic. The network + * link (g_ether) is probably the best option for that. + */ + /* optionally require specific source/sink data patterns */ static int @@ -534,12 +505,7 @@ check_read_data ( return 0; } -static void -reinit_write_data ( - struct zero_dev *dev, - struct usb_ep *ep, - struct usb_request *req -) +static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) { unsigned i; u8 *buf = req->buf; @@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { check_read_data (dev, ep, req); memset (req->buf, 0x55, req->length); } else - reinit_write_data (dev, ep, req); + reinit_write_data(ep, req); break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } } -static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) +static struct usb_request *source_sink_start_ep(struct usb_ep *ep) { struct usb_request *req; int status; @@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) - reinit_write_data (ep->driver_data, ep, req); + reinit_write_data(ep, req); else memset (req->buf, 0x55, req->length); - status = usb_ep_queue (ep, req, gfp_flags); + status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { struct zero_dev *dev = ep->driver_data; @@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) return req; } -static int -set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_source_sink_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->in_ep = ep; continue; } @@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->out_ep = ep; continue; } @@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); @@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); @@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } } -static int -set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_loopback_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev) * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */ -static int -zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) +static int zero_set_config(struct zero_dev *dev, unsigned number) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO (dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: - result = set_source_sink_config (dev, gfp_flags); + result = set_source_sink_config(dev); break; case CONFIG_LOOPBACK: - result = set_loopback_config (dev, gfp_flags); + result = set_loopback_config(dev); break; default: result = -EINVAL; @@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, w_value >> 8, @@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) else VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config (dev, w_value, GFP_ATOMIC); + value = zero_set_config(dev, w_value); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: @@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * use this "reset the config" shortcut. */ zero_reset_config (dev); - zero_set_config (dev, config, GFP_ATOMIC); + zero_set_config(dev, config); value = 0; } spin_unlock (&dev->lock); @@ -1163,7 +1121,7 @@ autoconf_fail: } EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!ep) goto autoconf_fail; @@ -1207,16 +1165,18 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* assume ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + if (gadget_is_dualspeed(gadget)) { + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; -#endif + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = { .suspend = zero_suspend, .resume = zero_resume, - .driver = { + .driver = { .name = (char *) shortname, .owner = THIS_MODULE, }, }; -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("Dual BSD/GPL"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); static int __init init (void) { - /* a real value would likely come through some id prom - * or module option. this one takes at least two packets. - */ - strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial); - return usb_gadget_register_driver (&zero_driver); } module_init (init); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 565d6ef4c4c..c978d622fa8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. +config USB_OHCI_HCD_SSB + bool "OHCI support for Broadcom SSB OHCI core" + depends on USB_OHCI_HCD && SSB && EXPERIMENTAL + default n + ---help--- + Support for the Sonics Silicon Backplane (SSB) attached + Broadcom USB OHCI core. + + This device is present in some embedded devices with + Broadcom based SSB bus. + + If unsure, say N. + config USB_OHCI_BIG_ENDIAN_DESC bool depends on USB_OHCI_HCD diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index b1d19268cb2..766ef68a0b4 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35cdba10411..c1514442883 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd) * are explicitly handed to companion controller(s), so no TT is * involved with the root hub. (Except where one is integrated, * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. */ + down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + up_write(&ehci_cf_port_reset_rwsem); temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, @@ -719,7 +727,6 @@ dead: */ static int ehci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -734,12 +741,12 @@ static int ehci_urb_enqueue ( default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return submit_async (ehci, ep, urb, &qtd_list, mem_flags); + return submit_async(ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return intr_submit (ehci, ep, urb, &qtd_list, mem_flags); + return intr_submit(ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) @@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) * completions normally happen asynchronously */ -static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; + int rc; spin_lock_irqsave (&ehci->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: @@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) } done: spin_unlock_irqrestore (&ehci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a7816e392a8..ad0d4965f2f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); - ehci_port_power(ehci, 0); - return 0; } @@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; } - if (ehci_is_TDI(ehci)) - ehci_reset(ehci); + ehci_reset(ehci); /* at least the Genesys GL880S needs fixup here */ temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 4f99b0eb27b..452d4b1bc85 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 829fe649a98..03a6b2f4e6e 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd) if (result) return result; - ehci_port_power(ehci, 0); + ehci_reset(ehci); return result; } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 140bfa423e0..b10f39c047e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -static void qtd_copy_status ( +static int qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, size_t length, u32 token ) { + int status = -EINPROGRESS; + /* count IN/OUT bytes, not SETUP (even short packets) */ if (likely (QTD_PID (token) != 2)) urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ - if (unlikely (urb->status != -EINPROGRESS)) - return; + if (unlikely(urb->unlinked)) + return status; /* force cleanup after short read; not always an error */ if (unlikely (IS_SHORT_READ (token))) - urb->status = -EREMOTEIO; + status = -EREMOTEIO; /* serious "can't proceed" faults reported by the hardware */ if (token & QTD_STS_HALT) { if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ - urb->status = -EOVERFLOW; + status = -EOVERFLOW; } else if (token & QTD_STS_MMF) { /* fs/ls interrupt xfer missed the complete-split */ - urb->status = -EPROTO; + status = -EPROTO; } else if (token & QTD_STS_DBE) { - urb->status = (QTD_PID (token) == 1) /* IN ? */ + status = (QTD_PID (token) == 1) /* IN ? */ ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { /* timeout, bad crc, wrong PID, etc; retried */ if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else { ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", urb->dev->devpath, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out"); - urb->status = -EPROTO; + status = -EPROTO; } /* CERR nonzero + no errors + halt --> stall */ } else if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else /* unknown */ - urb->status = -EPROTO; + status = -EPROTO; ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", usb_pipedevice (urb->pipe), usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - token, urb->status); + token, status); /* if async CSPLIT failed, try cleaning out the TT buffer */ - if (urb->status != -EPIPE + if (status != -EPIPE && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) @@ -212,10 +214,12 @@ static void qtd_copy_status ( usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } + + return status; } static void -ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) __releases(ehci->lock) __acquires(ehci->lock) { @@ -231,25 +235,13 @@ __acquires(ehci->lock) qh_put (qh); } - spin_lock (&urb->lock); - urb->hcpriv = NULL; - switch (urb->status) { - case -EINPROGRESS: /* success */ - urb->status = 0; - default: /* fault */ - COUNT (ehci->stats.complete); - break; - case -EREMOTEIO: /* fault or normal */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - urb->status = 0; - COUNT (ehci->stats.complete); - break; - case -ECONNRESET: /* canceled */ - case -ENOENT: - COUNT (ehci->stats.unlink); - break; + if (unlikely(urb->unlinked)) { + COUNT(ehci->stats.unlink); + } else { + if (likely(status == -EINPROGRESS)) + status = 0; + COUNT(ehci->stats.complete); } - spin_unlock (&urb->lock); #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -257,13 +249,14 @@ __acquires(ehci->lock) __FUNCTION__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - urb->status, + status, urb->actual_length, urb->transfer_buffer_length); #endif /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); + usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); spin_lock (&ehci->lock); } @@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *last = NULL, *end = qh->dummy; struct list_head *entry, *tmp; + int last_status = -EINPROGRESS; int stopped; unsigned count = 0; int do_status = 0; @@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; + int qtd_status; qtd = list_entry (entry, struct ehci_qtd, qtd_list); urb = qtd->urb; @@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; } ehci_qtd_free (ehci, last); last = NULL; + last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ @@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) stopped = 1; if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) - urb->status = -ESHUTDOWN; + last_status = -ESHUTDOWN; /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely (urb->status == -EINPROGRESS)) + if (likely(last_status == -EINPROGRESS && + !urb->unlinked)) continue; /* issue status after short control reads */ @@ -392,11 +389,14 @@ halt: } /* remove it from the queue */ - spin_lock (&urb->lock); - qtd_copy_status (ehci, urb, qtd->length, token); - do_status = (urb->status == -EREMOTEIO) - && usb_pipecontrol (urb->pipe); - spin_unlock (&urb->lock); + qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); + if (unlikely(qtd_status == -EREMOTEIO)) { + do_status = (!urb->unlinked && + usb_pipecontrol(urb->pipe)); + qtd_status = 0; + } + if (likely(last_status == -EINPROGRESS)) + last_status = qtd_status; if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, @@ -409,7 +409,7 @@ halt: /* last urb's completion might still need calling */ if (likely (last != NULL)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; ehci_qtd_free (ehci, last); } @@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds ( static int submit_async ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -922,10 +921,10 @@ submit_async ( int epnum; unsigned long flags; struct ehci_qh *qh = NULL; - int rc = 0; + int rc; qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -933,7 +932,7 @@ submit_async ( __FUNCTION__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", urb->transfer_buffer_length, - qtd, ep->hcpriv); + qtd, urb->ep->hcpriv); #endif spin_lock_irqsave (&ehci->lock, flags); @@ -942,9 +941,13 @@ submit_async ( rc = -ESHUTDOWN; goto done; } + rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(rc)) + goto done; - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); rc = -ENOMEM; goto done; } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e682f2342ef..80d99bce2b3 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -797,7 +797,6 @@ done: static int intr_submit ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -805,23 +804,26 @@ static int intr_submit ( unsigned epnum; unsigned long flags; struct ehci_qh *qh; - int status = 0; + int status; struct list_head empty; /* get endpoint and transfer/schedule data */ - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - goto done; + goto done_not_linked; } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); - qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv); if (qh == NULL) { status = -ENOMEM; goto done; @@ -832,13 +834,16 @@ static int intr_submit ( } /* then queue the urb's tds to the qh */ - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); BUG_ON (qh == NULL); /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); if (status) qtd_list_free (ehci, urb, qtd_list); @@ -1622,7 +1627,7 @@ itd_complete ( /* give urb back to the driver ... can be out-of-order */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -1988,7 +2000,7 @@ sitd_complete ( /* give urb back to the driver */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5c851a36de7..c27417f5b9d 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x) processed urbs. */ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb) + struct urb *urb, int status) __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; - urb->hcpriv = NULL; ep->error_count = 0; if (usb_pipecontrol(urb->pipe)) @@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock) urb_dbg(urb, "Finish"); + usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); spin_lock(&isp116x->lock); /* take idle endpoints out of the schedule */ @@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) if (PTD_GET_ACTIVE(ptd) || (cc != TD_CC_NOERROR && cc < 0x0E)) break; - if ((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length) - status = -EREMOTEIO; - else - status = 0; + status = 0; ep->nextpid = 0; break; default: @@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) } done: - if (status != -EINPROGRESS) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - spin_unlock(&urb->lock); - } - if (urb->status != -EINPROGRESS) - finish_request(isp116x, ep, urb); + if (status != -EINPROGRESS || urb->unlinked) + finish_request(isp116x, ep, urb, status); } } @@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) /*-----------------------------------------------------------------*/ static int isp116x_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); @@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, int is_out = !usb_pipein(pipe); int type = usb_pipetype(pipe); int epnum = usb_pipeendpoint(pipe); + struct usb_host_endpoint *hep = urb->ep; struct isp116x_ep *ep = NULL; unsigned long flags; int i; @@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, if (!HC_IS_RUNNING(hcd->state)) { kfree(ep); ret = -ENODEV; - goto fail; + goto fail_not_linked; + } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) @@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } } - /* in case of unlink-during-submit */ - if (urb->status != -EINPROGRESS) { - finish_request(isp116x, ep, urb); - ret = 0; - goto fail; - } urb->hcpriv = hep; start_atl_transfers(isp116x); fail: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); + fail_not_linked: spin_unlock_irqrestore(&isp116x->lock, flags); return ret; } @@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, /* Dequeue URBs. */ -static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_host_endpoint *hep; struct isp116x_ep *ep, *ep_act; unsigned long flags; + int rc; spin_lock_irqsave(&isp116x->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + hep = urb->hcpriv; - /* URB already unlinked (or never linked)? */ - if (!hep) { - spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; - } ep = hep->hcpriv; WARN_ON(hep != ep->hep); @@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) } if (urb) - finish_request(isp116x, ep, urb); - + finish_request(isp116x, ep, urb, status); + done: spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; + return rc; } static void isp116x_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index f61c6cdd06f..ebab5ce8f5c 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -24,7 +24,7 @@ * small: 0) header + data packets 1) just header */ static void __maybe_unused -urb_print (struct urb * urb, char * str, int small) +urb_print(struct urb * urb, char * str, int small, int status) { unsigned int pipe= urb->pipe; @@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small) } #ifndef OHCI_VERBOSE_DEBUG - if (urb->status != 0) + if (status != 0) #endif dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", str, @@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_flags, urb->actual_length, urb->transfer_buffer_length, - urb->status); + status); #ifdef OHCI_VERBOSE_DEBUG if (!small) { @@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_buffer_length: urb->actual_length; for (i = 0; i < 16 && i < len; i++) printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", urb->status); + printk ("%s stat:%d\n", i < len? "...": "", status); } } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d..240c7f50754 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -81,7 +81,6 @@ 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_restart (struct ohci_hcd *ohci); -static void ohci_quirk_nec_worker (struct work_struct *work); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); */ static int ohci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -131,11 +129,11 @@ static int ohci_urb_enqueue ( int retval = 0; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); + urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) + if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ @@ -200,22 +198,17 @@ static int ohci_urb_enqueue ( retval = -ENODEV; goto fail; } - - /* in case of unlink-during-submit */ - spin_lock (&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock (&urb->lock); - urb->hcpriv = urb_priv; - finish_urb (ohci, urb); - retval = 0; + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) goto fail; - } /* schedule the ed if needed */ if (ed->state == ED_IDLE) { retval = ed_schedule (ohci, ed); - if (retval < 0) - goto fail0; + if (retval < 0) { + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = ohci_frame_no(ohci); @@ -239,8 +232,6 @@ static int ohci_urb_enqueue ( urb->hcpriv = urb_priv; td_submit_urb (ohci, urb); -fail0: - spin_unlock (&urb->lock); fail: if (retval) urb_free_priv (ohci, urb_priv); @@ -249,22 +240,26 @@ fail: } /* - * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked using urb->status. reporting is always done + * decouple the URB from the HC queues (TDs, urb_priv). + * reporting is always done * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ -static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; + int rc; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "UNLINK", 1); + urb_print(urb, "UNLINK", 1, status); #endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) { + ; /* Do nothing */ + } else if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) * any more ... just clean up every urb's memory. */ if (urb->hcpriv) - finish_urb (ohci, urb); + finish_urb(ohci, urb, status); } spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ @@ -314,6 +309,8 @@ rescan: if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; finish_unlinks (ohci, 0); } @@ -321,7 +318,12 @@ sanitize: case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ if (limit-- == 0) { - ohci_warn (ohci, "IRQ INTR_SF lossage\n"); + ohci_warn(ohci, "ED unlink timeout\n"); + if (quirk_zfmicro(ohci)) { + ohci_warn(ohci, "Attempting ZF TD recovery\n"); + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + } goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); @@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } +static int check_ed(struct ohci_hcd *ohci, struct ed *ed) +{ + return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 + && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) + == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) + && !list_empty(&ed->td_list); +} + +/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes + * an interrupt TD but neglects to add it to the donelist. On systems with + * this chipset, we need to periodically check the state of the queues to look + * for such "lost" TDs. + */ +static void unlink_watchdog_func(unsigned long _ohci) +{ + long flags; + unsigned max; + unsigned seen_count = 0; + unsigned i; + struct ed **seen = NULL; + struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; + + spin_lock_irqsave(&ohci->lock, flags); + max = ohci->eds_scheduled; + if (!max) + goto done; + + if (ohci->ed_to_check) + goto out; + + seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); + if (!seen) + goto out; + + for (i = 0; i < NUM_INTS; i++) { + struct ed *ed = ohci->periodic[i]; + + while (ed) { + unsigned temp; + + /* scan this branch of the periodic schedule tree */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp] == ed) { + /* we've checked it and what's after */ + ed = NULL; + break; + } + } + if (!ed) + break; + seen[seen_count++] = ed; + if (!check_ed(ohci, ed)) { + ed = ed->ed_next; + continue; + } + + /* HC's TD list is empty, but HCD sees at least one + * TD that's not been sent through the donelist. + */ + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + + /* The HC may wait until the next frame to report the + * TD as done through the donelist and INTR_WDH. (We + * just *assume* it's not a multi-TD interrupt URB; + * those could defer the IRQ more than one frame, using + * DI...) Check again after the next INTR_SF. + */ + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrstatus); + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrenable); + + /* flush those writes */ + (void) ohci_readl(ohci, &ohci->regs->control); + + goto out; + } + } +out: + kfree(seen); + if (ohci->eds_scheduled) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); +done: + spin_unlock_irqrestore(&ohci->lock, flags); +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -616,6 +705,15 @@ retry: mdelay ((temp >> 23) & 0x1fe); hcd->state = HC_STATE_RUNNING; + if (quirk_zfmicro(ohci)) { + /* Create timer to watch for bad queue state on ZF Micro */ + setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, + (unsigned long) ohci); + + ohci->eds_scheduled = 0; + ohci->ed_to_check = NULL; + } + ohci_dump (ohci, 1); return 0; @@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs __iomem *regs = ohci->regs; - int ints; + int ints; /* we can eliminate a (slow) ohci_readl() - if _only_ WDH caused this irq */ + * if _only_ WDH caused this irq + */ if ((ohci->hcca->done_head != 0) && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) & 0x01)) { @@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort - if (ohci->flags & OHCI_QUIRK_NEC) { + if (quirk_nec(ohci)) { /* Workaround for a silicon bug in some NEC chips used * in Apple's PowerBooks. Adapted from Darwin code. */ @@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } + if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { + spin_lock(&ohci->lock); + if (ohci->ed_to_check) { + struct ed *ed = ohci->ed_to_check; + + if (check_ed(ohci, ed)) { + /* HC thinks the TD list is empty; HCD knows + * at least one TD is outstanding + */ + if (--ohci->zf_delay == 0) { + struct td *td = list_entry( + ed->td_list.next, + struct td, td_list); + ohci_warn(ohci, + "Reclaiming orphan TD %p\n", + td); + takeback_td(ohci, td); + ohci->ed_to_check = NULL; + } + } else + ohci->ed_to_check = NULL; + } + spin_unlock(&ohci->lock); + } + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_lock (&ohci->lock); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list + if ((ints & OHCI_INTR_SF) != 0 + && !ohci->ed_rm_list + && !ohci->ed_to_check && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); @@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = -1; + if (quirk_zfmicro(ohci)) + del_timer(&ohci->unlink_watchdog); + remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { @@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci) ed, ed->state); } - spin_lock (&urb->lock); - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); + if (!urb->unlinked) + urb->unlinked = -ESHUTDOWN; } finish_unlinks (ohci, 0); spin_unlock_irq(&ohci->lock); @@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -/* NEC workaround */ -static void ohci_quirk_nec_worker(struct work_struct *work) -{ - struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); - int status; - - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_init, %d\n", status); - return; - } - - status = ohci_restart(ohci); - if (status != 0) - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_restart, %d\n", status); -} - -/*-------------------------------------------------------------------------*/ - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_AUTHOR (DRIVER_AUTHOR); @@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif +#ifdef CONFIG_USB_OHCI_HCD_SSB +#include "ohci-ssb.c" +#define SSB_OHCI_DRIVER ssb_ohci_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(SSB_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif +#ifdef SSB_OHCI_DRIVER + retval = ssb_driver_register(&SSB_OHCI_DRIVER); + if (retval) + goto error_ssb; +#endif + return retval; /* Error path */ +#ifdef SSB_OHCI_DRIVER + error_ssb: +#endif #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); error_pci: #endif #ifdef SA1111_DRIVER @@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SSB_OHCI_DRIVER + ssb_driver_unregister(&SSB_OHCI_DRIVER); +#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 450c7b460c5..2f20d3dc895 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); - INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a5e2eb85d07..d0360f65ebd 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n"); return 0; } @@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) /* Check for NEC chip and apply quirk for allegedly lost interrupts. */ + +static void ohci_quirk_nec_worker(struct work_struct *work) +{ + struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); + int status; + + status = ohci_init(ohci); + if (status != 0) { + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_init", status); + return; + } + + status = ohci_restart(ohci); + if (status != 0) + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_restart", status); +} + static int ohci_quirk_nec(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_NEC; + INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker); ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); return 0; diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index c43b66acd4d..0a742692015 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) } ohci = hcd_to_ohci(hcd); - if (is_bigendian) + if (is_bigendian) { ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_device_is_compatible(dn, "mpc5200-ohci")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + } ohci_hcd_init(ohci); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 1a2e1777ca6..f95be1896b0 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, ohci = hcd_to_ohci(hcd); ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + +#ifdef CONFIG_PPC_MPC52xx + /* MPC52xx doesn't need frame_no shift */ + ohci->flags |= OHCI_QUIRK_FRAME_NO; +#endif ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 830a3fe8615..51817322232 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb) +finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - /* report short control reads right even though the data TD always - * has TD_R set. (much simpler, but creates the 1-td limit.) - */ - if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) - && unlikely (usb_pipecontrol (urb->pipe)) - && urb->actual_length < urb->transfer_buffer_length - && usb_pipein (urb->pipe) - && urb->status == 0) { - urb->status = -EREMOTEIO; - } - spin_unlock (&urb->lock); + if (likely(status == -EINPROGRESS)) + status = 0; switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -70,12 +56,13 @@ __acquires(ohci->lock) } #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); + urb_print(urb, "RET", usb_pipeout (urb->pipe), status); #endif /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); + usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ @@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; + if (quirk_zfmicro(ohci) + && (ed->type == PIPE_INTERRUPT) + && !(ohci->eds_scheduled++)) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -708,19 +699,18 @@ static void td_submit_urb ( * Done List handling functions *-------------------------------------------------------------------------*/ -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +/* calculate transfer length/status and update the urb */ +static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; + int status = -EINPROGRESS; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + u16 tdPSW = ohci_hwPSW(ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that @@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ - return; + return status; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; @@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; - spin_unlock (&urb->lock); - } + if (cc != TD_CC_NOERROR && cc < 0x0E) + status = cc_to_error[cc]; /* count all non-empty packets except control SETUP packet */ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { @@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb->actual_length, urb->transfer_buffer_length); } + return status; } /*-------------------------------------------------------------------------*/ -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) wmb (); ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. + /* Get rid of all later tds from this urb. We don't have + * to be careful: no errors and nothing was transferred. + * Also patch the ed so it looks as if those tds completed normally. */ while (tmp != &ed->td_list) { struct td *next; - __hc32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) * then we need to leave the control STATUS packet queued * and clear ED_SKIP. */ - info = next->hwINFO; - info |= cpu_to_hc32 (ohci, TD_DONE); - info &= ~cpu_to_hc32 (ohci, TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; + list_del(&next->td_list); + urb_priv->td_cnt++; ed->hwHeadP = next->hwNextTD | toggle; } @@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) hc32_to_cpu (ohci, td->hwINFO), cc, cc_to_error [cc]); } - - return rev; } /* replies to the request have to be on a FIFO basis so @@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) */ if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - td_rev = ed_halted (ohci, td, cc, td_rev); + ed_halted(ohci, td, cc); td->next_dl_td = td_rev; td_rev = td; @@ -940,8 +919,12 @@ skip_ed: TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; + if (td->td_dma != head) { + if (ed == ohci->ed_to_check) + ohci->ed_to_check = NULL; + else + goto skip_ed; + } } } @@ -974,7 +957,7 @@ rescan_this: urb = td->urb; urb_priv = td->urb->hcpriv; - if (urb->status == -EINPROGRESS) { + if (!urb->unlinked) { prev = &td->hwNextTD; continue; } @@ -990,7 +973,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb); + finish_urb(ohci, urb, 0); } } if (completed && !list_empty (&ed->td_list)) @@ -998,6 +981,8 @@ rescan_this: /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb (); @@ -1021,7 +1006,7 @@ rescan_this: if (ohci->ed_controltail) { command |= OHCI_CLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_CLE)) { control |= OHCI_CTRL_CLE; @@ -1031,7 +1016,7 @@ rescan_this: } if (ohci->ed_bulktail) { command |= OHCI_BLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_BLE)) { control |= OHCI_CTRL_BLE; @@ -1043,13 +1028,13 @@ rescan_this: /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } if (command) { - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, command, &ohci->regs->cmdstatus); } @@ -1061,11 +1046,60 @@ rescan_this: /*-------------------------------------------------------------------------*/ /* + * Used to take back a TD from the host controller. This would normally be + * called from within dl_done_list, however it may be called directly if the + * HC no longer sees the TD and it has not appeared on the donelist (after + * two frames). This bug has been observed on ZF Micro systems. + */ +static void takeback_td(struct ohci_hcd *ohci, struct td *td) +{ + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + int status; + + /* update URB's length and status from TD */ + status = td_done(ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) + finish_urb(ohci, urb, status); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink(ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32(ohci, ED_SKIP)) { + td = list_entry(ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel(ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel(ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } +} + +/* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. + * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, + * instead of scanning the (re-reversed) donelist as this does. There's + * an abnormal path too, handling a quirk in some Compaq silicon: URBs + * with TDs that appear to be orphaned are directly reclaimed. */ static void dl_done_list (struct ohci_hcd *ohci) @@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci) while (td) { struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, - ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32 (ohci, ED_SKIP)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } - + takeback_td(ohci, td); td = td_next; } } diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c new file mode 100644 index 00000000000..bc3e785d8c0 --- /dev/null +++ b/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,247 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core OHCI driver + * + * Copyright 2007 Michael Buesch <mb@bu3sch.de> + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include <linux/ssb/ssb.h> + + +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_ohci_device { + struct ohci_hcd ohci; /* _must_ be at the beginning. */ + + u32 enable_flags; +}; + +static inline +struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) +{ + return (struct ssb_ohci_device *)(hcd->hcd_priv); +} + + +static int ssb_ohci_reset(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + ohci_hcd_init(ohci); + err = ohci_init(ohci); + + return err; +} + +static int ssb_ohci_start(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + err = ohci_run(ohci); + if (err < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + + return err; +} + +#ifdef CONFIG_PM +static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ + + /* 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); + + spin_unlock_irqrestore(&ohci->lock, flags); + return 0; +} + +static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) +{ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + usb_hcd_resume_root_hub(hcd); + return 0; +} +#endif /* CONFIG_PM */ + +static const struct hc_driver ssb_ohci_hc_driver = { + .description = "ssb-usb-ohci", + .product_desc = "SSB OHCI Controller", + .hcd_priv_size = sizeof(struct ssb_ohci_device), + + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + .reset = ssb_ohci_reset, + .start = ssb_ohci_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + +#ifdef CONFIG_PM + .suspend = ssb_ohci_hcd_suspend, + .resume = ssb_ohci_hcd_resume, +#endif + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .get_frame_number = ohci_get_frame, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, + + .start_port_reset = ohci_start_port_reset, +}; + +static void ssb_ohci_detach(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + usb_put_hcd(hcd); + ssb_device_disable(dev, 0); +} + +static int ssb_ohci_attach(struct ssb_device *dev) +{ + struct ssb_ohci_device *ohcidev; + struct usb_hcd *hcd; + int err = -ENOMEM; + u32 tmp, flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + flags |= SSB_OHCI_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); + if (!hcd) + goto err_dev_disable; + ohcidev = hcd_to_ssb_ohci(hcd); + ohcidev->enable_flags = flags; + + tmp = ssb_read32(dev, SSB_ADMATCH0); + hcd->rsrc_start = ssb_admatch_base(tmp); + hcd->rsrc_len = ssb_admatch_size(tmp); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) + goto err_put_hcd; + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); + if (err) + goto err_iounmap; + + ssb_set_drvdata(dev, hcd); + + return err; + +err_iounmap: + iounmap(hcd->regs); +err_put_hcd: + usb_put_hcd(hcd); +err_dev_disable: + ssb_device_disable(dev, flags); + return err; +} + +static int ssb_ohci_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err; + u16 chipid_top; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (usb_disabled()) + return -ENODEV; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + + err = ssb_ohci_attach(dev); + + return err; +} + +static void ssb_ohci_remove(struct ssb_device *dev) +{ + ssb_ohci_detach(dev); +} + +#ifdef CONFIG_PM + +static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_ohci_resume(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + + ssb_device_enable(dev, ohcidev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_ohci_suspend NULL +#define ssb_ohci_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_ohci_table[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); + +static struct ssb_driver ssb_ohci_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_ohci_table, + .probe = ssb_ohci_probe, + .remove = ssb_ohci_remove, + .suspend = ssb_ohci_suspend, + .resume = ssb_ohci_resume, +}; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 4ada43cf138..47c5c66a282 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -398,11 +398,38 @@ struct ohci_hcd { #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ +#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ + + /* Needed for ZF Micro quirk */ + struct timer_list unlink_watchdog; + unsigned eds_scheduled; + struct ed *ed_to_check; + unsigned zf_delay; }; +#ifdef CONFIG_PCI +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_NEC; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_ZFMICRO; +} +#else +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return 0; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return 0; +} +#endif + /* convert between an hcd pointer and the corresponding ohci_hcd */ static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd) { @@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. - * - * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over - * to arch/powerpc */ -#ifdef CONFIG_STB03xxx -#define OHCI_BE_FRAME_NO_SHIFT 16 +#ifdef CONFIG_PPC_MPC52xx +#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) #else -#define OHCI_BE_FRAME_NO_SHIFT 0 +#define big_endian_frame_no_quirk(ohci) 0 #endif static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) @@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) u32 tmp; if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - tmp >>= OHCI_BE_FRAME_NO_SHIFT; + if (!big_endian_frame_no_quirk(ohci)) + tmp >>= 16; } else tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 40a1de4c256..ae8ec4474eb 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) kfree(td); if (urb) { - urb->status = -ENODEV; - urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), + urb); + spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); + usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, + -ENODEV); spin_lock(&r8a66597->lock); } break; @@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, info.pipenum = get_empty_pipenum(r8a66597, ep); info.address = get_urb_to_r8a66597_addr(r8a66597, urb); info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = ep->wMaxPacketSize; + info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); info.type = get_r8a66597_type(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); @@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, p[i], setup_addr); + r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, pipe_start(r8a66597, td->pipe); } +static int is_set_address(unsigned char *setup_packet) +{ + if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && + setup_packet[1] == USB_REQ_SET_ADDRESS) + return 1; + else + return 0; +} + /* this function must be called with interrupt disabled */ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) { @@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) switch (td->type) { case USB_PID_SETUP: - if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) { + if (is_set_address(td->urb->setup_packet)) { td->set_address = 1; td->urb->setup_packet[2] = alloc_usb_address(r8a66597, td->urb); @@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) } /* this function must be called with interrupt disabled */ -static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) +static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, + u16 pipenum, struct urb *urb, int status) +__releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); @@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && urb->status != 0) + if (td->set_address && (status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, if (usb_pipeisoc(urb->pipe)) urb->start_frame = r8a66597_get_frame(hcd); - urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&r8a66597->lock); } @@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, } } -/* this function must be called with interrupt disabled */ -static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) -__releases(r8a66597->lock) __acquires(r8a66597->lock) -{ - done(r8a66597, td, pipenum, urb); -} - static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) { u16 tmp; @@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); struct urb *urb; int finish = 0; + int status = 0; if (unlikely(!td)) return; @@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("in fifo not ready (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, -EPIPE); return; } /* prepare parameters */ rcv_len = tmp & DTLN; - bufsize = td->maxpacket; if (usb_pipeisoc(urb->pipe)) { buf = (u16 *)(urb->transfer_buffer + urb->iso_frame_desc[td->iso_cnt].offset); @@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf = (void *)urb->transfer_buffer + urb->actual_length; urb_len = urb->transfer_buffer_length - urb->actual_length; } - if (rcv_len < bufsize) - size = min(rcv_len, urb_len); - else - size = min(bufsize, urb_len); + bufsize = min(urb_len, (int) td->maxpacket); + if (rcv_len <= bufsize) { + size = rcv_len; + } else { + size = bufsize; + status = -EOVERFLOW; + finish = 1; + } /* update parameters */ urb->actual_length += size; if (rcv_len == 0) td->zero_packet = 1; - if ((size % td->maxpacket) > 0) { + if (rcv_len < bufsize) { td->short_packet = 1; - if (urb->transfer_buffer_length != urb->actual_length && - urb->transfer_flags & URB_SHORT_NOT_OK) - td->urb->status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = 0; + urb->iso_frame_desc[td->iso_cnt].status = status; td->iso_cnt++; + finish = 0; } /* check transfer finish */ - if (check_transfer_finish(td, urb)) { + if (finish || check_transfer_finish(td, urb)) { pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); finish = 1; @@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf, size); } - if (finish && pipenum != 0) { - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, urb); - } + if (finish && pipenum != 0) + finish_request(r8a66597, td, pipenum, urb, status); } static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) @@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("out write fifo not ready. (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, urb, -EPIPE); return; } @@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) } -static void check_next_phase(struct r8a66597 *r8a66597) +static void check_next_phase(struct r8a66597 *r8a66597, int status) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0); struct urb *urb; @@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597) switch (td->type) { case USB_PID_IN: case USB_PID_OUT: - if (urb->status != -EINPROGRESS) { - finish = 1; - break; - } if (check_transfer_finish(td, urb)) td->type = USB_PID_ACK; break; case USB_PID_SETUP: - if (urb->status != -EINPROGRESS) - finish = 1; - else if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_buffer_length == urb->actual_length) td->type = USB_PID_ACK; - urb->status = 0; - } else if (usb_pipeout(urb->pipe)) + else if (usb_pipeout(urb->pipe)) td->type = USB_PID_OUT; else td->type = USB_PID_IN; break; case USB_PID_ACK: finish = 1; - if (urb->status == -EINPROGRESS) - urb->status = 0; break; } - if (finish) - finish_request(r8a66597, td, 0, urb); + if (finish || status != 0 || urb->unlinked) + finish_request(r8a66597, td, 0, urb, status); else start_transfer(r8a66597, td); } -static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum) +static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - if (td && td->urb) { + if (td) { u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID; if (pid == PID_NAK) - td->urb->status = -ECONNRESET; + return -ECONNRESET; else - td->urb->status = -EPIPE; + return -EPIPE; } + return 0; } static void irq_pipe_ready(struct r8a66597 *r8a66597) @@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597) packet_read(r8a66597, 0); else pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) td = r8a66597_get_td(r8a66597, 0); if (td && td->type != USB_PID_OUT) disable_irq_empty(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, + 0); } } } @@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) u16 check; u16 pipenum; u16 mask; + int status; mask = r8a66597_read(r8a66597, NRDYSTS) & r8a66597_read(r8a66597, NRDYENB); r8a66597_write(r8a66597, ~mask, NRDYSTS); if (mask & NRDY0) { cfifo_change(r8a66597, 0); - set_urb_error(r8a66597, 0); + status = get_urb_error(r8a66597, 0); pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, status); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) if (unlikely(!td)) continue; - set_urb_error(r8a66597, pipenum); + status = get_urb_error(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); pipe_stop(r8a66597, td->pipe); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, status); } } } @@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) u16 intsts0, intsts1, intsts2; u16 intenb0, intenb1, intenb2; u16 mask0, mask1, mask2; + int status; spin_lock(&r8a66597->lock); @@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) } if (mask1 & SIGN) { r8a66597_write(r8a66597, ~SIGN, INTSTS1); - set_urb_error(r8a66597, 0); - check_next_phase(r8a66597); + status = get_urb_error(r8a66597, 0); + check_next_phase(r8a66597, status); } if (mask1 & SACK) { r8a66597_write(r8a66597, ~SACK, INTSTS1); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } } if (mask0) { @@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, } static int r8a66597_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { + struct usb_host_endpoint *hep = urb->ep; struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td = NULL; - int ret = 0, request = 0; + int ret, request = 0; unsigned long flags; spin_lock_irqsave(&r8a66597->lock, flags); if (!get_urb_to_r8a66597_dev(r8a66597, urb)) { ret = -ENODEV; - goto error; + goto error_not_linked; } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto error_not_linked; + if (!hep->hcpriv) { hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), GFP_ATOMIC); @@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, if (list_empty(&r8a66597->pipe_queue[td->pipenum])) request = 1; list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]); - - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - ret = -EPIPE; - goto error; - } urb->hcpriv = td; - spin_unlock(&urb->lock); if (request) { ret = start_transfer(r8a66597, td); @@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, set_td_timer(r8a66597, td); error: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +error_not_linked: spin_unlock_irqrestore(&r8a66597->lock, flags); return ret; } -static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td; unsigned long flags; + int rc; spin_lock_irqsave(&r8a66597->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (urb->hcpriv) { td = urb->hcpriv; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - done(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb, status); } + done: spin_unlock_irqrestore(&r8a66597->lock, flags); - return 0; + return rc; } static void r8a66597_endpoint_disable(struct usb_hcd *hcd, @@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - done(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = rh->port; + *(u32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) @@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); del_timer_sync(&r8a66597->rh_timer); - iounmap((void *)r8a66597->reg); usb_remove_hcd(hcd); + iounmap((void *)r8a66597->reg); usb_put_hcd(hcd); return 0; } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 4cfa3ff2c99..94d859aa73f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -435,14 +435,9 @@ static void finish_request( if (usb_pipecontrol(urb->pipe)) ep->nextpid = USB_PID_SETUP; - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - urb->hcpriv = NULL; - spin_unlock(&urb->lock); - + usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); + usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status); spin_lock(&sl811->lock); /* leave active endpoints in the schedule */ @@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank + SL11H_XFERCNTREG); if (len > ep->length) { len = ep->length; - urb->status = -EOVERFLOW; + urbstat = -EOVERFLOW; } urb->actual_length += len; sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length) - urbstat = 0; - else if (len < ep->maxpacket) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) - urbstat = -EREMOTEIO; + if (urbstat == -EINPROGRESS && + (len < ep->maxpacket || + urb->actual_length == + urb->transfer_buffer_length)) { + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; else urbstat = 0; } - if (usb_pipecontrol(urb->pipe) - && (urbstat == -EREMOTEIO - || urbstat == 0)) { - - /* NOTE if the status stage STALLs (why?), - * this reports the wrong urb status. - */ - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = urbstat; - spin_unlock(&urb->lock); - - urb = NULL; - ep->nextpid = USB_PID_ACK; - } break; case USB_PID_SETUP: // PACKET("...ACK/setup_%02x qh%p\n", bank, ep); @@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) + if (urbstat != -EINPROGRESS || urb->unlinked) finish_request(sl811, ep, urb, urbstat); } @@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) static int sl811h_urb_enqueue( struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags ) { @@ -820,7 +800,8 @@ static int sl811h_urb_enqueue( struct sl811h_ep *ep = NULL; unsigned long flags; int i; - int retval = 0; + int retval; + struct usb_host_endpoint *hep = urb->ep; #ifdef DISABLE_ISO if (type == PIPE_ISOCHRONOUS) @@ -838,7 +819,12 @@ static int sl811h_urb_enqueue( || !HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; kfree(ep); - goto fail; + goto fail_not_linked; + } + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) { @@ -951,37 +937,31 @@ static int sl811h_urb_enqueue( sofirq_on(sl811); } - /* in case of unlink-during-submit */ - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - finish_request(sl811, ep, urb, 0); - retval = 0; - goto fail; - } urb->hcpriv = hep; - spin_unlock(&urb->lock); - start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: + if (retval) + usb_hcd_unlink_urb_from_ep(hcd, urb); +fail_not_linked: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } -static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_host_endpoint *hep; unsigned long flags; struct sl811h_ep *ep; - int retval = 0; + int retval; spin_lock_irqsave(&sl811->lock, flags); - hep = urb->hcpriv; - if (!hep) + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) goto fail; + hep = urb->hcpriv; ep = hep->hcpriv; if (ep) { /* finish right away if this urb can't be active ... @@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else -fail: retval = -EINVAL; + fail: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index b88eb3c62c0..ac283b09a63 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -51,7 +51,6 @@ #include <linux/usb.h> #include <linux/workqueue.h> #include <linux/platform_device.h> -#include <linux/pci_ids.h> #include <linux/mutex.h> #include <asm/io.h> #include <asm/irq.h> @@ -184,7 +183,7 @@ struct u132_ring { struct u132 { struct kref kref; struct list_head u132_list; - struct semaphore sw_lock; + struct mutex sw_lock; struct semaphore scheduler_lock; struct u132_platform_data *board; struct platform_device *platform_dev; @@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work) return; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&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); + mutex_unlock(&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); + mutex_unlock(&u132->sw_lock); return; } } @@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, 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); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, u132_ring_queue_work(u132, ring, 0); up(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, 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); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } usb_hcd_giveback_urb(hcd, urb); + } usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; urb->actual_length += len; endp->toggle_bits = toggle_bits; @@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; u8 *b = buf; @@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { if (usb_pipein(urb->pipe)) { int retval; struct u132_ring *ring = endp->ring; @@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; @@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, 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); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd) dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); } else { - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(100); u132_power(u132, 0); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); } } @@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) (pdev->dev.platform_data))->vendor; u16 device = ((struct u132_platform_data *) (pdev->dev.platform_data))->device; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { u132->flags = OHCI_QUIRK_AMD756; @@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) u132->going = 1; } msleep(100); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } else { dev_err(&u132->platform_dev->dev, "platform_device missing\n"); @@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd) return -ESHUTDOWN; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = u132_init(u132); if (retval) { u132_disable(u132); u132->going = 1; } - up(&u132->sw_lock); + mutex_unlock(&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 u132_udev *udev, 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); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132, 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; @@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132, return 0; } -static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, +static int queue_int_on_old_endpoint(struct u132 *u132, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, 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); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; endp->edset_flush = 0; @@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } 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; @@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_control(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + 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); + unsigned long irqs; + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; 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; @@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, 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; @@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, 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; @@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, 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; @@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, } static int queue_control_on_old_endpoint(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp) { @@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132, } } -static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, - struct urb *urb, gfp_t mem_flags) +static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { struct u132 *u132 = hcd_to_u132(hcd); if (irqs_disabled()) { @@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, , 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); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); return -ESHUTDOWN; } else { u8 usb_addr = usb_pipedevice(urb->pipe); @@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, 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; + struct u132_endp *endp = urb->ep->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); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_int_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else { /*(endp == NULL) */ return create_endpoint_and_queue_int(u132, udev, - hep, urb, usb_dev, usb_addr, usb_endp, - address, mem_flags); + 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" @@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, } 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; + struct u132_endp *endp = urb->ep->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); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_bulk_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_bulk(u132, - udev, hep, urb, usb_dev, usb_addr, + udev, urb, usb_dev, usb_addr, usb_endp, address, mem_flags); } else { - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; u16 urb_size = 8; u8 *b = urb->setup_packet; int i = 0; @@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, 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); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_control_on_old_endpoint( + u132, urb, usb_dev, + endp, usb_addr, + usb_endp); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_control(u132, - hep, urb, usb_dev, usb_addr, usb_endp, + urb, usb_dev, usb_addr, usb_endp, mem_flags); } } @@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - urb->hcpriv = NULL; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); return 0; } else continue; @@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132, } static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb) + struct urb *urb, int status) { unsigned long irqs; + int rc; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return rc; + } 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, @@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, 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); + u132_hcd_abandon_urb(u132, endp, urb, status); return 0; } } else { @@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } if (urb_slot) { struct usb_hcd *hcd = u132_to_hcd(u132); + + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_size -= 1; if (list_empty(&endp->urb_more)) { spin_unlock_irqrestore(&endp->queue_lock.slock, @@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - urb->hcpriv = NULL; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { dev_err(&u132->platform_dev->dev, "urb=%p not found in " @@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return -EINVAL; } else { - int retval = dequeue_from_overflow_chain(u132, endp, + int retval; + + usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); + retval = dequeue_from_overflow_chain(u132, endp, urb); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return retval; @@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } } -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { @@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) 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); + return u132_endp_urb_dequeue(u132, endp, urb, status); } 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); + return u132_endp_urb_dequeue(u132, endp, urb, status); } } } @@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, return -ESHUTDOWN; } else { int retval = 0; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); switch (typeReq) { case ClearHubFeature: switch (wValue) { @@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, stall:retval = -EPIPE; break; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev) dev_err(&u132->platform_dev->dev, "removing device u132" ".%d\n", u132->sequence_num); msleep(100); - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); u132_monitor_cancel_work(u132); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev) u132->going += 1; printk(KERN_INFO "removing device u132.%d\n", u132->sequence_num); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_remove_hcd(hcd); u132_u132_put_kref(u132); return 0; @@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; - init_MUTEX(&u132->sw_lock); + mutex_init(&u132->sw_lock); init_MUTEX(&u132->scheduler_lock); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->curr_endp = NULL; INIT_DELAYED_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler); - } down(&u132->sw_lock); + } mutex_lock(&u132->sw_lock); INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; @@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) while (endps-- > 0) { u132->endp[endps] = NULL; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 1497371583b..20cc58b9780 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); - if (urbp->urb->status != -EINPROGRESS) - out += sprintf(out, " Status=%d", urbp->urb->status); + if (urbp->urb->unlinked) + out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); out += sprintf(out, "\n"); i = nactive = ninactive = 0; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 1b3d23406ac..340d6ed3e6e 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -146,7 +146,6 @@ struct uhci_qh { short phase; /* Between 0 and period-1 */ short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ - int iso_status; /* Status for Isochronous URBs */ int state; /* QH_STATE_xxx; see above */ int type; /* Queue type (control, bulk, etc) */ @@ -457,21 +456,6 @@ struct urb_priv { }; -/* - * Locking in uhci.c - * - * Almost everything relating to the hardware schedule and processing - * of URBs is protected by uhci->lock. urb->status is protected by - * urb->lock; that's the one exception. - * - * To prevent deadlocks, never lock uhci->lock while holding urb->lock. - * The safe order of locking is: - * - * #1 uhci->lock - * #2 urb->lock - */ - - /* Some special IDs */ #define PCI_VENDOR_ID_GENESYS 0x17a0 diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 3bb908ca38e..e5d60d5b105 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, uhci_free_td(uhci, td); } - urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, if (list_empty(&qh->queue)) { qh->iso_packet_desc = &urb->iso_frame_desc[0]; qh->iso_frame = urb->start_frame; - qh->iso_status = 0; } qh->skel = SKEL_ISO; @@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) qh->iso_packet_desc->actual_length = actlength; qh->iso_packet_desc->status = status; } - - if (status) { + if (status) urb->error_count++; - qh->iso_status = status; - } uhci_remove_td_from_urbp(td); uhci_free_td(uhci, td); qh->iso_frame += qh->period; ++qh->iso_packet_desc; } - return qh->iso_status; + return 0; } static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; @@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, spin_lock_irqsave(&uhci->lock, flags); - ret = urb->status; - if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto done; + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto done_not_linked; ret = -ENOMEM; urbp = uhci_alloc_urb_priv(uhci, urb); if (!urbp) goto done; - if (hep->hcpriv) - qh = (struct uhci_qh *) hep->hcpriv; + if (urb->ep->hcpriv) + qh = urb->ep->hcpriv; else { - qh = uhci_alloc_qh(uhci, urb->dev, hep); + qh = uhci_alloc_qh(uhci, urb->dev, urb->ep); if (!qh) goto err_no_qh; } @@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, err_submit_failed: if (qh->state == QH_STATE_IDLE) uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ - err_no_qh: uhci_free_urb_priv(uhci, urbp); - done: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +done_not_linked: spin_unlock_irqrestore(&uhci->lock, flags); return ret; } -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp; struct uhci_qh *qh; + int rc; spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) goto done; - qh = urbp->qh; + + qh = ((struct urb_priv *) urb->hcpriv)->qh; /* Remove Isochronous TDs from the frame list ASAP */ if (qh->type == USB_ENDPOINT_XFER_ISOC) { @@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) done: spin_unlock_irqrestore(&uhci->lock, flags); - return 0; + return rc; } /* * Finish unlinking an URB and give it back */ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb) + struct urb *urb, int status) __releases(uhci->lock) __acquires(uhci->lock) { @@ -1497,13 +1493,6 @@ __acquires(uhci->lock) * unlinked first. Regardless, don't confuse people with a * negative length. */ urb->actual_length = max(urb->actual_length, 0); - - /* Report erroneous short transfers */ - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length && - urb->status == 0)) - urb->status = -EREMOTEIO; } /* When giving back the first URB in an Isochronous queue, @@ -1516,7 +1505,6 @@ __acquires(uhci->lock) qh->iso_packet_desc = &nurb->iso_frame_desc[0]; qh->iso_frame = nurb->start_frame; - qh->iso_status = 0; } /* Take the URB off the QH's queue. If the queue is now empty, @@ -1529,9 +1517,10 @@ __acquires(uhci->lock) } uhci_free_urb_priv(uhci, urbp); + usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status); spin_lock(&uhci->lock); /* If the queue is now empty, we can unlink the QH and give up its @@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) if (status == -EINPROGRESS) break; - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) /* Not dequeued */ - urb->status = status; - else - status = ECONNRESET; /* Not -ECONNRESET */ - spin_unlock(&urb->lock); - /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ - if (status == ECONNRESET) { + if (urb->unlinked) { if (QH_FINISHED_UNLINKING(qh)) qh->is_stopped = 1; else if (!qh->is_stopped) return; } - uhci_giveback_urb(uhci, qh, urb); - if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC) + uhci_giveback_urb(uhci, qh, urb, status); + if (status < 0) break; } @@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) restart: list_for_each_entry(urbp, &qh->queue, node) { urb = urbp->urb; - if (urb->status != -EINPROGRESS) { + if (urb->unlinked) { /* Fix up the TD links and save the toggles for * non-Isochronous queues. For Isochronous queues, @@ -1608,7 +1590,7 @@ restart: qh->is_stopped = 0; return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, 0); goto restart; } } diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index e9fdbc8997b..5131cbfb2f5 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb) spin_lock(&dev->buflock); if (status != 0) { - if ((status != -ENOENT) && (status != -ECONNRESET)) { + if ((status != -ENOENT) && (status != -ECONNRESET) && + (status != -ESHUTDOWN)) { dbg(1," %s : nonzero status received: %d", __FUNCTION__, status); } diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c index 92c1d2768df..24e2dc3148a 100644 --- a/drivers/usb/misc/berry_charge.c +++ b/drivers/usb/misc/berry_charge.c @@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 2) { dev_err(&udev->dev, "First magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Sending second magic command\n"); @@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 0) { dev_err(&udev->dev, "Second magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Calling set_configuration\n"); @@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); +exit: + kfree(dummy_buffer); return retval; } @@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + kfree(dummy_buffer); return retval; } diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 538b535e955..d3d8cd6ff10 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface, size_t buffer_size; int i; int retval = -ENOMEM; - struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (ftdi == NULL) { + struct usb_ftdi *ftdi; + + ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); + if (!ftdi) { printk(KERN_ERR "Out of memory\n"); return -ENOMEM; } - memset(ftdi, 0x00, sizeof(struct usb_ftdi)); + mutex_lock(&ftdi_module_lock); list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); ftdi->sequence_num = ++ftdi_instances; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b64ca91d9b0..9244d067cec 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, packet.address = 0x00000194; packet.data = addr; ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); packet.header = 0x001f; packet.address = 0x00000190; packet.data = (length & ~3); ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); if (sisusb->flagb0 != 0x16) { packet.header = 0x001f; packet.address = 0x00000180; @@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (ret) { msgcount++; if (msgcount < 500) - printk(KERN_ERR - "sisusbvga[%d]: Wrote %zd of " - "%d bytes, error %d\n", - sisusb->minor, *bytes_written, - length, ret); + dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n", + *bytes_written, length, ret); else if (msgcount == 500) - printk(KERN_ERR - "sisusbvga[%d]: Too many errors" - ", logging stopped\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n"); } addr += (*bytes_written); length -= (*bytes_written); } if (ret) - break; + break; } @@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, addr += 4; length -= 4; } -#if 0 /* That does not work, as EP 2 is an OUT EP! */ - default: - CLEARPACKET(&packet); - packet.header = 0x001f; - packet.address = 0x000001a0; - packet.data = 0x00000006; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b0; - packet.data = (length & ~3) | 0x40000000; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b4; - packet.data = addr; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001a4; - packet.data = 0x00000001; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (userbuffer) { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - NULL, userbuffer, - bytes_read, 0); - if (!ret) userbuffer += (*bytes_read); - } else { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - kernbuffer, NULL, - bytes_read, 0); - if (!ret) kernbuffer += (*bytes_read); - } - addr += (*bytes_read); - length -= (*bytes_read); -#endif } if (ret) - break; + break; } return ret; @@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); } -#if 0 - -int -sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) -{ - return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) -{ - return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -#endif /* 0 */ - int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, u32 dest, int length, size_t *bytes_written) @@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb) sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); for(i = 1; i <= 7; i++) { - printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i); + dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); for(j = 0; j < i; j++) { - printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]); + dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]); } } } @@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length) #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a) #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o) #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype) @@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines) SETIREG(SISSR, 0x26, 0x00); } - SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ + SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ return ret; } @@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb) if (ramtype <= 1) { ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab); if (iret) { - printk(KERN_ERR "sisusbvga[%d]: RAM size " - "detection failed, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* TODO */ } } else { - printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* *** TODO *** */ } @@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb) break; } - printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n", - sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1, + dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, ramtypetext2[ramtype], bw); } @@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file) struct usb_interface *interface; int subminor = iminor(inode); - if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", - subminor); + if (!(interface = usb_find_interface(&sisusb_driver, subminor))) return -ENODEV; - } if (!(sisusb = usb_get_intfdata(interface))) return -ENODEV; @@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file) if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to initialize " - "device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); return -EIO; } } else { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Device not attached to " - "USB 2.0 hub\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n"); return -EIO; } } @@ -2586,7 +2508,6 @@ static int sisusb_release(struct inode *inode, struct file *file) { struct sisusb_usb_data *sisusb; - int myminor; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) return -ENODEV; @@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file) sisusb_kill_all_busy(sisusb); } - myminor = sisusb->minor; - sisusb->isopen = 0; file->private_data = NULL; @@ -2942,7 +2861,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, unsigned long arg) { - int retval, port, length; + int retval, port, length; u32 address; /* All our commands require the device @@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, static int sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct sisusb_usb_data *sisusb; struct sisusb_info x; struct sisusb_command y; - int retval = 0; + int retval = 0; u32 __user *argp = (u32 __user *)arg; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) @@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SISUSB_GET_CONFIG: - x.sisusb_id = SISUSB_ID; + x.sisusb_id = SISUSB_ID; x.sisusb_version = SISUSB_VERSION; x.sisusb_revision = SISUSB_REVISION; x.sisusb_patchlevel = SISUSB_PATCHLEVEL; @@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = { .release = sisusb_release, .read = sisusb_read, .write = sisusb_write, - .llseek = sisusb_lseek, + .llseek = sisusb_lseek, #ifdef SISUSB_NEW_CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif @@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; - const char *memfail = - KERN_ERR - "sisusbvga[%d]: Failed to allocate memory for %s buffer\n"; - printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n", + dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); /* Allocate memory for our private */ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - printk(KERN_ERR - "sisusb: Failed to allocate memory for private data\n"); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); return -ENOMEM; } kref_init(&sisusb->kref); @@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Register device */ if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { - printk(KERN_ERR - "sisusb: Failed to get a minor for device %d\n", + dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n", dev->devnum); retval = -ENODEV; goto error_1; @@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->ibufsize = SISUSB_IBUF_SIZE; if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, GFP_KERNEL, &sisusb->transfer_dma_in))) { - printk(memfail, "input", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); retval = -ENOMEM; goto error_2; } @@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf, GFP_KERNEL, &sisusb->transfer_dma_out[i]))) { if (i == 0) { - printk(memfail, "output", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); retval = -ENOMEM; goto error_3; } @@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } @@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->urbstatus[i] = 0; } - printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", - sisusb->minor, sisusb->numobufs); + dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); #ifdef INCL_SISUSB_CON /* Allocate our SiS_Pr */ if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate SiS_Pr\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n"); } #endif @@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf, ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); if (ret) - printk(KERN_ERR - "sisusbvga[%d]: Error registering ioctl32 " - "translations\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); else sisusb->ioctl32registered = 1; } @@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf, initscreen = 0; #endif if (sisusb_init_gfxdevice(sisusb, initscreen)) - printk(KERN_ERR - "sisusbvga[%d]: Failed to early " - "initialize device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n"); } else - printk(KERN_INFO - "sisusbvga[%d]: Not attached to USB 2.0 hub, " - "deferring init\n", - sisusb->minor); + dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n"); sisusb->ready = 1; #ifdef SISUSBENDIANTEST - printk(KERN_DEBUG "sisusb: *** RWTEST ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n"); sisusb_testreadwrite(sisusb); - printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif #ifdef INCL_SISUSB_CON @@ -3354,7 +3252,6 @@ error_1: static void sisusb_disconnect(struct usb_interface *intf) { struct sisusb_usb_data *sisusb; - int minor; /* This should *not* happen */ if (!(sisusb = usb_get_intfdata(intf))) @@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf) sisusb_console_exit(sisusb); #endif - minor = sisusb->minor; - usb_deregister_dev(intf, &usb_sisusb_class); mutex_lock(&sisusb->lock); @@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf) ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); if (ret) { - printk(KERN_ERR - "sisusbvga[%d]: Error unregistering " - "ioctl32 translations\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); } } #endif @@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf) /* decrement our usage count */ kref_put(&sisusb->kref, sisusb_delete); - printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); + dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n"); } static struct usb_device_id sisusb_table [] = { @@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { - int retval; #ifdef INCL_SISUSB_CON sisusb_init_concode(); #endif - if (!(retval = usb_register(&sisusb_driver))) { - - printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", - SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); - printk(KERN_INFO - "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); - - } - - return retval; + return usb_register(&sisusb_driver); } static void __exit usb_sisusb_exit(void) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 8e1120a6480..d2d7872cd02 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -8,29 +8,29 @@ * * Otherwise, the following license terms apply: * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2) Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3) The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -44,16 +44,14 @@ #include <linux/mutex.h> /* For older kernels, support for text consoles is by default - * off. To ensable text console support, change the following: + * off. To enable text console support, change the following: */ -#if 0 -#define CONFIG_USB_SISUSBVGA_CON -#endif +/* #define CONFIG_USB_SISUSBVGA_CON */ /* Version Information */ #define SISUSB_VERSION 0 -#define SISUSB_REVISION 0 +#define SISUSB_REVISION 0 #define SISUSB_PATCHLEVEL 8 /* Include console and mode switching code? */ @@ -74,7 +72,7 @@ #define SISUSB_IBUF_SIZE 0x01000 #define SISUSB_OBUF_SIZE 0x10000 /* fixed */ -#define NUMOBUFS 8 /* max number of output buffers/output URBs */ +#define NUMOBUFS 8 /* max number of output buffers/output URBs */ /* About endianness: * @@ -93,7 +91,7 @@ */ #ifdef __BIG_ENDIAN -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ +#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ do { \ p->header = cpu_to_le16(p->header); \ p->address = cpu_to_le32(p->address); \ @@ -105,7 +103,7 @@ struct sisusb_usb_data; -struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ +struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ struct sisusb_usb_data *sisusb; int urbindex; int *actual_length; @@ -116,16 +114,16 @@ struct sisusb_usb_data { struct usb_interface *interface; struct kref kref; wait_queue_head_t wait_q; /* for syncind and timeouts */ - struct mutex lock; /* general race avoidance */ - unsigned int ifnum; /* interface number of the USB device */ - int minor; /* minor (for logging clarity) */ - int isopen; /* !=0 if open */ - int present; /* !=0 if device is present on the bus */ - int ready; /* !=0 if device is ready for userland */ + struct mutex lock; /* general race avoidance */ + unsigned int ifnum; /* interface number of the USB device */ + int minor; /* minor (for logging clarity) */ + int isopen; /* !=0 if open */ + int present; /* !=0 if device is present on the bus */ + int ready; /* !=0 if device is ready for userland */ #ifdef SISUSB_OLD_CONFIG_COMPAT int ioctl32registered; #endif - int numobufs; /* number of obufs = number of out urbs */ + int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; dma_addr_t transfer_dma_out[NUMOBUFS]; @@ -136,13 +134,13 @@ struct sisusb_usb_data { unsigned char completein; struct sisusb_urb_context urbout_context[NUMOBUFS]; unsigned long flagb0; - unsigned long vrambase; /* framebuffer base */ - unsigned int vramsize; /* framebuffer size (bytes) */ + unsigned long vrambase; /* framebuffer base */ + unsigned int vramsize; /* framebuffer size (bytes) */ unsigned long mmiobase; unsigned int mmiosize; unsigned long ioportbase; - unsigned char devinit; /* device initialized? */ - unsigned char gfxinit; /* graphics core initialized? */ + unsigned char devinit; /* device initialized? */ + unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; #ifdef INCL_SISUSB_CON @@ -152,7 +150,7 @@ struct sisusb_usb_data { int haveconsole, con_first, con_last; int havethisconsole[MAX_NR_CONSOLES]; int textmodedestroyed; - unsigned int sisusb_num_columns; /* real number, not vt's idea */ + unsigned int sisusb_num_columns; /* real number, not vt's idea */ int cur_start_addr, con_rolled_over; int sisusb_cursor_loc, bad_cursor_pos; int sisusb_cursor_size_from; @@ -197,7 +195,7 @@ struct sisusb_packet { unsigned short header; u32 address; u32 data; -} __attribute__((__packed__)); +} __attribute__ ((__packed__)); #define CLEARPACKET(packet) memset(packet, 0, 10) @@ -265,36 +263,36 @@ struct sisusb_packet { /* Structure argument for SISUSB_GET_INFO ioctl */ struct sisusb_info { - __u32 sisusb_id; /* for identifying sisusb */ -#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ - __u8 sisusb_version; - __u8 sisusb_revision; - __u8 sisusb_patchlevel; - __u8 sisusb_gfxinit; /* graphics core initialized? */ + __u32 sisusb_id; /* for identifying sisusb */ +#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ + __u8 sisusb_version; + __u8 sisusb_revision; + __u8 sisusb_patchlevel; + __u8 sisusb_gfxinit; /* graphics core initialized? */ - __u32 sisusb_vrambase; - __u32 sisusb_mmiobase; - __u32 sisusb_iobase; - __u32 sisusb_pcibase; + __u32 sisusb_vrambase; + __u32 sisusb_mmiobase; + __u32 sisusb_iobase; + __u32 sisusb_pcibase; - __u32 sisusb_vramsize; /* framebuffer size in bytes */ + __u32 sisusb_vramsize; /* framebuffer size in bytes */ - __u32 sisusb_minor; + __u32 sisusb_minor; - __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ + __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - __u32 sisusb_conactive; /* != 0 if console driver active */ + __u32 sisusb_conactive; /* != 0 if console driver active */ - __u8 sisusb_reserved[28]; /* for future use */ + __u8 sisusb_reserved[28]; /* for future use */ }; struct sisusb_command { - __u8 operation; /* see below */ - __u8 data0; /* operation dependent */ - __u8 data1; /* operation dependent */ - __u8 data2; /* operation dependent */ - __u32 data3; /* operation dependent */ - __u32 data4; /* for future use */ + __u8 operation; /* see below */ + __u8 data0; /* operation dependent */ + __u8 data1; /* operation dependent */ + __u8 data2; /* operation dependent */ + __u32 data3; /* operation dependent */ + __u32 data4; /* for future use */ }; #define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ @@ -306,7 +304,7 @@ struct sisusb_command { #define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ -#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ +#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ #define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ @@ -315,6 +313,4 @@ struct sisusb_command { #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) #define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) - #endif /* SISUSB_H */ - diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 8d0edc867f3..43722e5a49d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -52,6 +52,7 @@ #include <linux/kernel.h> #include <linux/signal.h> #include <linux/fs.h> +#include <linux/usb.h> #include <linux/tty.h> #include <linux/console.h> #include <linux/string.h> @@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; /* sisusb->lock is down */ - - /* Don't need to put the character into buffer ourselves, - * because the vt does this BEFORE calling us. - */ -#if 0 - sisusbcon_writew(ch, SISUSB_VADDR(x, y)); -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, struct sisusb_usb_data *sisusb; ssize_t written; int cols, length; -#if 0 - u16 *src, *dest; - int i; -#endif if (width <= 0 || height <= 0) return; @@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, cols = sisusb->sisusb_num_columns; - /* Don't need to move data outselves, because - * vt does this BEFORE calling us. - * This is only used by vt's insert/deletechar. - */ -#if 0 - if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) { - - sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy), - height * width * 2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - - src = SISUSB_VADDR(sx, sy); - dest = SISUSB_VADDR(dx, dy); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src += cols; - dest += cols; - } - - } else { - - src = SISUSB_VADDR(sx, sy + height - 1); - dest = SISUSB_VADDR(dx, dy + height - 1); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src -= cols; - dest -= cols; - } - - } -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c) */ if (c->vc_origin == (unsigned long)c->vc_screenbuf) { mutex_unlock(&sisusb->lock); - printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n"); return 0; } @@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = { int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) { - int i, ret, minor = sisusb->minor; + int i, ret; mutex_lock(&sisusb->lock); @@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Set up text mode (and upload default font) */ if (sisusb_reset_text_mode(sisusb, 1)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to set up text mode\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n"); return 1; } @@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Allocate screen buffer */ if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate screen buffer\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n"); return 1; } diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 9b30f896281..273de5d0934 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -55,109 +55,18 @@ /* POINTER INITIALIZATION */ /*********************************************/ -static void -SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) +static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) { - SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; - SiS_Pr->SiS_StandTable = SiSUSB_StandTable; - - SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; - SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; - SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - - SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; -} - -/*********************************************/ -/* HELPER: Get ModeID */ -/*********************************************/ + SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; + SiS_Pr->SiS_StandTable = SiSUSB_StandTable; -#if 0 -unsigned short -SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) -{ - unsigned short ModeIndex = 0; - - switch (HDisplay) - { - case 320: - if (VDisplay == 200) - ModeIndex = ModeIndex_320x200[Depth]; - else if (VDisplay == 240) - ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if (VDisplay == 300) - ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: - if (VDisplay == 384) - ModeIndex = ModeIndex_512x384[Depth]; - break; - case 640: - if (VDisplay == 480) - ModeIndex = ModeIndex_640x480[Depth]; - else if (VDisplay == 400) - ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if (VDisplay == 480) - ModeIndex = ModeIndex_720x480[Depth]; - else if (VDisplay == 576) - ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if (VDisplay == 576) - ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if (VDisplay == 600) - ModeIndex = ModeIndex_800x600[Depth]; - else if (VDisplay == 480) - ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if (VDisplay == 480) - ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if (VDisplay == 480) - ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if (VDisplay == 540) - ModeIndex = ModeIndex_960x540[Depth]; - else if (VDisplay == 600) - ModeIndex = ModeIndex_960x600[Depth]; - break; - case 1024: - if (VDisplay == 576) - ModeIndex = ModeIndex_1024x576[Depth]; - else if (VDisplay == 768) - ModeIndex = ModeIndex_1024x768[Depth]; - break; - case 1152: - if (VDisplay == 864) - ModeIndex = ModeIndex_1152x864[Depth]; - break; - case 1280: - switch (VDisplay) { - case 720: - ModeIndex = ModeIndex_1280x720[Depth]; - break; - case 768: - ModeIndex = ModeIndex_1280x768[Depth]; - break; - case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; - break; - } - } + SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; + SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - return ModeIndex; + SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } -#endif /* 0 */ /*********************************************/ /* HELPER: SetReg, GetReg */ @@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) static void SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short data) + unsigned short index, unsigned short data) { sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); } static void SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short data) + unsigned short data) { sisusb_setreg(SiS_Pr->sisusb, port, data); } static unsigned char -SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index) +SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index) { u8 data; @@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) static void SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND, - unsigned short DataOR) + unsigned short index, unsigned short DataAND, + unsigned short DataOR) { sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); } static void SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND) + unsigned short index, unsigned short DataAND) { sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); } static void -SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, - unsigned short index, unsigned short DataOR) +SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataOR) { sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); } @@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, /* HELPER: DisplayOn, DisplayOff */ /*********************************************/ -static void -SiS_DisplayOn(struct SiS_Private *SiS_Pr) +static void SiS_DisplayOn(struct SiS_Private *SiS_Pr) { SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); } @@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr) /* HELPER: Init Port Addresses */ /*********************************************/ -static void -SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) +static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) { SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; @@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) /* HELPER: GetSysFlags */ /*********************************************/ -static void -SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr) { SiS_Pr->SiS_MyCR63 = 0x63; } @@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr) /* HELPER: Init PCI & Engines */ /*********************************************/ -static void -SiSInitPCIetc(struct SiS_Private *SiS_Pr) +static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); /* - Enable 2D (0x40) @@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) /* HELPER: SET SEGMENT REGISTERS */ /*********************************************/ -static void -SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) { SiS_SetSegRegLower(SiS_Pr, value); SiS_SetSegRegUpper(SiS_Pr, value); } -static void -SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) { SiS_SetSegmentReg(SiS_Pr, 0); } @@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetSegmentReg(SiS_Pr, value); } -static void -SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) { SiS_SetSegmentRegOver(SiS_Pr, 0); } -static void -SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) { SiS_ResetSegmentReg(SiS_Pr); SiS_ResetSegmentRegOver(SiS_Pr); @@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) static int SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, - unsigned short *ModeIdIndex) + unsigned short *ModeIdIndex) { if ((*ModeNo) <= 0x13) { @@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, } else { - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + (*ModeNo)) break; - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + 0xFF) return 0; } @@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, /* HELPER: ENABLE CRT1 */ /*********************************************/ -static void -SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr) { /* Enable CRT1 gating */ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); @@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr) static unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { - static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; unsigned short modeflag; short index; @@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } index = (modeflag & ModeTypeMask) - ModeEGA; - if (index < 0) index = 0; + if (index < 0) + index = 0; return ColorDepth[index]; } @@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short xres, temp, colordepth, infoflag; @@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); - for(i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + for (i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); } } @@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - for(i = 0; i <= 0x18; i++) { + for (i = 0; i <= 0x18; i++) { CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); } @@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char ARdata; unsigned short i; - for(i = 0; i <= 0x13; i++) { + for (i = 0; i <= 0x13; i++) { ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); @@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char GRdata; unsigned short i; - for(i = 0; i <= 0x08; i++) { + for (i = 0; i <= 0x08; i++) { GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); } @@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) /* CLEAR EXTENDED REGISTERS */ /*********************************************/ -static void -SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { int i; - for(i = 0x0A; i <= 0x0E; i++) { + for (i = 0x0A; i <= 0x0E; i++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); } @@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) static unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short rrti, i, index, temp; if (ModeNo <= 0x13) return 0xFFFF; - index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; - if (index > 0) index--; + index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F; + if (index > 0) + index--; rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; @@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) break; - temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; + temp = + SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; if (temp < SiS_Pr->SiS_ModeType) break; i++; index--; - } while(index != 0xFFFF); + } while (index != 0xFFFF); i--; @@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SYNC */ /*********************************************/ -static void -SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) +static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) { unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; sync &= 0xC0; @@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) static void SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { - unsigned char index; + unsigned char index; unsigned short temp, i, j, modeflag; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; - for(i = 0,j = 0; i <= 7; i++, j++) { + for (i = 0, j = 0; i <= 7; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x10; i <= 10; i++, j++) { + for (j = 0x10; i <= 10; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x15; i <= 12; i++, j++) { + for (j = 0x15; i <= 12; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x0A; i <= 15; i++, j++) { + for (j = 0x0A; i <= 15; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp); temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if (modeflag & DoubleScanMode) temp |= 0x80; + if (modeflag & DoubleScanMode) + temp |= 0x80; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); if (SiS_Pr->SiS_ModeType > ModeVGA) @@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; unsigned short temp; temp = (du >> 8) & 0x0f; @@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); - if (infoflag & InterlaceMode) du >>= 1; + if (infoflag & InterlaceMode) + du >>= 1; du <<= 5; temp = (du >> 8) & 0xff; - if (du & 0xff) temp++; + if (du & 0xff) + temp++; temp++; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); } @@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01); } /*********************************************/ @@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) + unsigned short mi) { unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; @@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short data = 0, VCLK = 0, index = 0; @@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; } - if (VCLK >= 166) data |= 0x0c; + if (VCLK >= 166) + data |= 0x0c; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); if (VCLK >= 166) @@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short data, infoflag = 0, modeflag; @@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, data |= 0x02; data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); } - if (infoflag & InterlaceMode) data |= 0x20; + if (infoflag & InterlaceMode) + data |= 0x20; } SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); data = 0; if (infoflag & InterlaceMode) { /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ - unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; - unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; + unsigned short hrs = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) + - 3; + unsigned short hto = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + + 5; data = hrs - (hto >> 1) + 3; } SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); @@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, - unsigned short shiftflag, unsigned short dl, unsigned short ah, - unsigned short al, unsigned short dh) + unsigned short shiftflag, unsigned short dl, unsigned short ah, + unsigned short al, unsigned short dh) { unsigned short d1, d2, d3; switch (dl) { - case 0: - d1 = dh; d2 = ah; d3 = al; - break; - case 1: - d1 = ah; d2 = al; d3 = dh; - break; - default: - d1 = al; d2 = dh; d3 = ah; + case 0: + d1 = dh; + d2 = ah; + d3 = al; + break; + case 1: + d1 = ah; + d2 = al; + d3 = dh; + break; + default: + d1 = al; + d2 = dh; + d3 = ah; } SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); @@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, } static void -SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short mi) { unsigned short data, data2, time, i, j, k, m, n, o; unsigned short si, di, bx, sf; @@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); - for(i = 0; i < j; i++) { + for (i = 0; i < j; i++) { data = table[i]; - for(k = 0; k < 3; k++) { + for (k = 0; k < 3; k++) { data2 = 0; - if (data & 0x01) data2 += 0x2A; - if (data & 0x02) data2 += 0x15; + if (data & 0x01) + data2 += 0x2A; + if (data & 0x02) + data2 += 0x15; SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); data >>= 2; } } if (time == 256) { - for(i = 16; i < 32; i++) { + for (i = 16; i < 32; i++) { data = table[i] << sf; - for(k = 0; k < 3; k++) + for (k = 0; k < 3; k++) SiS_SetRegByte(SiS_Pr, DACData, data); } si = 32; - for(m = 0; m < 9; m++) { + for (m = 0; m < 9; m++) { di = si; bx = si + 4; - for(n = 0; n < 3; n++) { - for(o = 0; o < 5; o++) { + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[bx], table[si]); + table[di], table[bx], + table[si]); si++; } si -= 2; - for(o = 0; o < 3; o++) { + for (o = 0; o < 3; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[si], table[bx]); + table[di], table[si], + table[bx]); si--; } } - si += 5; + si += 5; } } } @@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi static void SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short StandTableIndex, rrti; @@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SiSSetMode() */ /*********************************************/ -int -SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { unsigned short ModeIdIndex; - unsigned long BaseAddr = SiS_Pr->IOAddress; + unsigned long BaseAddr = SiS_Pr->IOAddress; SiSUSB_InitPtr(SiS_Pr); SiSUSBRegInit(SiS_Pr, BaseAddr); @@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) ModeNo &= 0x7f; SiS_Pr->SiS_ModeType = - SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; + SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; SiS_Pr->SiS_SetFlag = LowModeTests; @@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) return 1; } -int -SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) { unsigned short ModeNo = 0; int i; @@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) } #endif /* INCL_SISUSB_CON */ - - - - diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index 864bc0e9659..c46ce42d448 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -46,7 +46,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -76,21 +76,21 @@ #define CRT2Mode 0x0800 #define HalfDCLK 0x1000 #define NoSupportSimuTV 0x2000 -#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ #define DoubleScanMode 0x8000 /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 -#define SupportCHTV 0x0800 -#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define SupportCHTV 0x0800 +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 #define SupportLCD 0x0020 #define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ -#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ -#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ -#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ #define InterlaceMode 0x0080 #define SyncPP 0x0000 #define SyncPN 0x4000 @@ -129,7 +129,7 @@ #define SIS_RI_856x480 19 #define SIS_RI_1280x768 20 #define SIS_RI_1400x1050 21 -#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ #define SIS_RI_848x480 23 #define SIS_RI_1360x768 24 #define SIS_RI_1024x600 25 @@ -147,691 +147,691 @@ #define SIS_CRT2_PORT_04 0x04 - 0x30 /* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; -static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; -static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; -static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; -static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; -static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; -static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; -static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; -static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; -static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; -static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; -static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; -static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; -static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; -static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; -static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; -static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; -static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; -static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; -static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25}; -static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; +static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; +static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; +static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; +static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; +static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; +static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; +static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; +static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; +static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; +static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; +static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; +static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; +static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; +static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; +static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; +static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; +static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; +static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; +static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; +static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; -static const unsigned char SiS_MDA_DAC[] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +static const unsigned char SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }; -static const unsigned char SiS_CGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_EGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, - 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, - 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, - 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, - 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, - 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, - 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_VGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, - 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, - 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, - 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, - 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, - 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, - 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, - 0x0B,0x0C,0x0D,0x0F,0x10 +static const unsigned char SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -static const struct SiS_St SiSUSB_SModeIDTable[] = -{ - {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, - {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +static const struct SiS_St SiSUSB_SModeIDTable[] = { + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = -{ - { 640,400}, - { 640,350}, - { 720,400}, - { 720,350}, - { 640,480} +static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} }; -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = -{ - { 320, 200, 8, 8}, /* 0x00 */ - { 320, 240, 8, 8}, /* 0x01 */ - { 320, 400, 8, 8}, /* 0x02 */ - { 400, 300, 8, 8}, /* 0x03 */ - { 512, 384, 8, 8}, /* 0x04 */ - { 640, 400, 8,16}, /* 0x05 */ - { 640, 480, 8,16}, /* 0x06 */ - { 800, 600, 8,16}, /* 0x07 */ - { 1024, 768, 8,16}, /* 0x08 */ - { 1280,1024, 8,16}, /* 0x09 */ - { 1600,1200, 8,16}, /* 0x0a */ - { 1920,1440, 8,16}, /* 0x0b */ - { 2048,1536, 8,16}, /* 0x0c */ - { 720, 480, 8,16}, /* 0x0d */ - { 720, 576, 8,16}, /* 0x0e */ - { 1280, 960, 8,16}, /* 0x0f */ - { 800, 480, 8,16}, /* 0x10 */ - { 1024, 576, 8,16}, /* 0x11 */ - { 1280, 720, 8,16}, /* 0x12 */ - { 856, 480, 8,16}, /* 0x13 */ - { 1280, 768, 8,16}, /* 0x14 */ - { 1400,1050, 8,16}, /* 0x15 */ - { 1152, 864, 8,16}, /* 0x16 */ - { 848, 480, 8,16}, /* 0x17 */ - { 1360, 768, 8,16}, /* 0x18 */ - { 1024, 600, 8,16}, /* 0x19 */ - { 1152, 768, 8,16}, /* 0x1a */ - { 768, 576, 8,16}, /* 0x1b */ - { 1360,1024, 8,16}, /* 0x1c */ - { 1680,1050, 8,16}, /* 0x1d */ - { 1280, 800, 8,16}, /* 0x1e */ - { 1920,1080, 8,16}, /* 0x1f */ - { 960, 540, 8,16}, /* 0x20 */ - { 960, 600, 8,16} /* 0x21 */ +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { + {320, 200, 8, 8}, /* 0x00 */ + {320, 240, 8, 8}, /* 0x01 */ + {320, 400, 8, 8}, /* 0x02 */ + {400, 300, 8, 8}, /* 0x03 */ + {512, 384, 8, 8}, /* 0x04 */ + {640, 400, 8, 16}, /* 0x05 */ + {640, 480, 8, 16}, /* 0x06 */ + {800, 600, 8, 16}, /* 0x07 */ + {1024, 768, 8, 16}, /* 0x08 */ + {1280, 1024, 8, 16}, /* 0x09 */ + {1600, 1200, 8, 16}, /* 0x0a */ + {1920, 1440, 8, 16}, /* 0x0b */ + {2048, 1536, 8, 16}, /* 0x0c */ + {720, 480, 8, 16}, /* 0x0d */ + {720, 576, 8, 16}, /* 0x0e */ + {1280, 960, 8, 16}, /* 0x0f */ + {800, 480, 8, 16}, /* 0x10 */ + {1024, 576, 8, 16}, /* 0x11 */ + {1280, 720, 8, 16}, /* 0x12 */ + {856, 480, 8, 16}, /* 0x13 */ + {1280, 768, 8, 16}, /* 0x14 */ + {1400, 1050, 8, 16}, /* 0x15 */ + {1152, 864, 8, 16}, /* 0x16 */ + {848, 480, 8, 16}, /* 0x17 */ + {1360, 768, 8, 16}, /* 0x18 */ + {1024, 600, 8, 16}, /* 0x19 */ + {1152, 768, 8, 16}, /* 0x1a */ + {768, 576, 8, 16}, /* 0x1b */ + {1360, 1024, 8, 16}, /* 0x1c */ + {1680, 1050, 8, 16}, /* 0x1d */ + {1280, 800, 8, 16}, /* 0x1e */ + {1920, 1080, 8, 16}, /* 0x1f */ + {960, 540, 8, 16}, /* 0x20 */ + {960, 600, 8, 16} /* 0x21 */ }; -static const struct SiS_StandTable SiSUSB_StandTable[] = -{ +static const struct SiS_StandTable SiSUSB_StandTable[] = { /* MD_3_400 - mode 0x03 - 400 */ { - 0x50,0x18,0x10,0x1000, - { 0x00,0x03,0x00,0x02 }, - 0x67, - { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, - 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x0c,0x00,0x0f,0x08 }, - { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff } - }, + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} + }, /* Generic for VGA and higher */ { - 0x00,0x00,0x00,0x0000, - { 0x01,0x0f,0x00,0x0e }, - 0x23, - { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, - 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x01,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff } - } + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} + } }; -static const struct SiS_Ext SiSUSB_EModeIDTable[] = -{ - {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ - {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ - {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ - {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ - {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ - {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ - {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ - {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ - {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ - {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */ - {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */ - {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ - {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ - {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ - {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */ - {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */ - {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */ - {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */ - {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */ - {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */ - {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */ - {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */ - {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */ - {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */ - {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ - {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ - {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ - {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ - {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */ - {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */ - {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */ - {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */ - {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */ - {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */ - {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */ - {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */ - {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */ - {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */ - {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */ - {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */ - {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */ - {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */ - {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */ - {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */ - {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */ - {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */ - {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */ - {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */ - {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */ - {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */ - {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +static const struct SiS_Ext SiSUSB_EModeIDTable[] = { + {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ + {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ + {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ + {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ + {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ + {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ + {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ + {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ + {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ + {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ + {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ + {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ + {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ + {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ + {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ + {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ + {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ + {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ + {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ + {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ + {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ + {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ + {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ + {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ + {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ + {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ + {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ + {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ + {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ + {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ + {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ + {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ + {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ + {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ + {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ + {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ + {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ + {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ + {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ + {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ + {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ + {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ + {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ + {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ + {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ + {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ + {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ + {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ + {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ + {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ + {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ + {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} }; -static const struct SiS_Ext2 SiSUSB_RefIndex[] = -{ - {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00} +static const struct SiS_Ext2 SiSUSB_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} }; -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = -{ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, /* 0x0 */ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x1 */ - {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, /* 0x2 */ - {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01}}, /* 0x3 */ - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, /* 0x4 */ - {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00}}, /* 0x5 */ - {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, - 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, - 0x00}}, /* 0x6 */ - {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, - 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, - 0x00}}, /* 0x7 */ - {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x00}}, /* 0x8 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x61}}, /* 0x9 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, - 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, - 0x61}}, /* 0xa */ - {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, - 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, - 0x61}}, /* 0xb */ - {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, - 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, - 0x00}}, /* 0xc */ - {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, - 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0xd */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, - 0x01}}, /* 0xe */ - {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, - 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, - 0x01}}, /* 0xf */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, - 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, - 0x01}}, /* 0x10 */ - {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, - 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, - 0x01}}, /* 0x11 */ - {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, - 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, - 0x61}}, /* 0x12 */ - {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, - 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, - 0x61}}, /* 0x13 */ - {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, - 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, - 0x61}}, /* 0x14 */ - {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, - 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, - 0x00}}, /* 0x15 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x16 */ - {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x17 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, - 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, - 0x01}}, /* 0x18 */ - {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, - 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, - 0x01}}, /* 0x19 */ - {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, - 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, - 0x62}}, /* 0x1a */ - {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, - 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, - 0x62}}, /* 0x1b */ - {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, - 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, - 0x00}}, /* 0x1c */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1d */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1e */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, - 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, - 0x01}}, /* 0x1f */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x20 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x21 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x22 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x23 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x24 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x25 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x26 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x27 */ - {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, - 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, - 0x63}}, /* 0x28 */ - {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, - 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, - 0x63}}, /* 0x29 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2a */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2b */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2c */ - {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, - 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, - 0x44}}, /* 0x2d */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, - 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, - 0x44}}, /* 0x2e */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, - 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, - 0x44}}, /* 0x2f */ - {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, - 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, - 0x44}}, /* 0x30 */ - {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, - 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, - 0x00}}, /* 0x31 */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, - 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, - 0x01}}, /* 0x32 */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, - 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, - 0x01}}, /* 0x33 */ - {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, - 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, - 0x01}}, /* 0x34 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, - 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, - 0x01}}, /* 0x35 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, - 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x36 */ - {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, - 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, - 0x01}}, /* 0x37 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x38 */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x39 */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, - 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, - 0x01}}, /* 0x3a */ - {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, - 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ - {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x3c */ - {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, /* 0x3d */ - {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, - 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, - 0x00}}, /* 0x3e */ - {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, - 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x3f */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, - 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x40 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x41 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, - 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, - 0x01}}, /* 0x42 */ - {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, - 0x00}}, /* 0x43 */ - {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, - 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, - 0x01}}, /* 0x44 */ - {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x45 */ - {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, - 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, - 0x00}}, /* 0x46 */ - {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x47 */ - {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, - 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x48 */ - {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, - 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, - 0x01}}, /* 0x49 */ - {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, - 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, - 0x01}}, /* 0x4a */ - {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, - 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, - 0x00}}, /* 0x4b */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, - 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, - 0x01}}, /* 0x4c */ - {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x4e */ - {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, - 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, - 0x21}}, /* 0x4f */ - {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, - 0x20}}, /* 0x50 */ - {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, - 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, - 0x61}}, /* 0x51 */ - {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, - 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, - 0x41}}, /* 0x52 */ - {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, - 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, - 0x01}}, /* 0x53 */ - {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, - 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x54 */ +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, /* 0x3d */ + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, /* 0x3e */ + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x3f */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, + 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x40 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x41 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, + 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, + 0x01}}, /* 0x42 */ + {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, + 0x00}}, /* 0x43 */ + {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, + 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, + 0x01}}, /* 0x44 */ + {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x45 */ + {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, + 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, + 0x00}}, /* 0x46 */ + {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x47 */ + {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, + 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x48 */ + {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, + 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, + 0x01}}, /* 0x49 */ + {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, + 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, + 0x01}}, /* 0x4a */ + {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, + 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, + 0x00}}, /* 0x4b */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, + 0x01}}, /* 0x4c */ + {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x4e */ + {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, + 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, + 0x21}}, /* 0x4f */ + {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, + 0x20}}, /* 0x50 */ + {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, + 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, + 0x61}}, /* 0x51 */ + {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, + 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, + 0x41}}, /* 0x52 */ + {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, + 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, + 0x01}}, /* 0x53 */ + {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, + 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, + 0x41}} /* 0x54 */ }; -static const struct SiS_VCLKData SiSUSB_VCLKData[] = -{ - { 0x1b,0xe1, 25}, /* 0x00 */ - { 0x4e,0xe4, 28}, /* 0x01 */ - { 0x57,0xe4, 31}, /* 0x02 */ - { 0xc3,0xc8, 36}, /* 0x03 */ - { 0x42,0xe2, 40}, /* 0x04 */ - { 0xfe,0xcd, 43}, /* 0x05 */ - { 0x5d,0xc4, 44}, /* 0x06 */ - { 0x52,0xe2, 49}, /* 0x07 */ - { 0x53,0xe2, 50}, /* 0x08 */ - { 0x74,0x67, 52}, /* 0x09 */ - { 0x6d,0x66, 56}, /* 0x0a */ - { 0x5a,0x64, 65}, /* 0x0b */ - { 0x46,0x44, 67}, /* 0x0c */ - { 0xb1,0x46, 68}, /* 0x0d */ - { 0xd3,0x4a, 72}, /* 0x0e */ - { 0x29,0x61, 75}, /* 0x0f */ - { 0x6e,0x46, 76}, /* 0x10 */ - { 0x2b,0x61, 78}, /* 0x11 */ - { 0x31,0x42, 79}, /* 0x12 */ - { 0xab,0x44, 83}, /* 0x13 */ - { 0x46,0x25, 84}, /* 0x14 */ - { 0x78,0x29, 86}, /* 0x15 */ - { 0x62,0x44, 94}, /* 0x16 */ - { 0x2b,0x41,104}, /* 0x17 */ - { 0x3a,0x23,105}, /* 0x18 */ - { 0x70,0x44,108}, /* 0x19 */ - { 0x3c,0x23,109}, /* 0x1a */ - { 0x5e,0x43,113}, /* 0x1b */ - { 0xbc,0x44,116}, /* 0x1c */ - { 0xe0,0x46,132}, /* 0x1d */ - { 0x54,0x42,135}, /* 0x1e */ - { 0xea,0x2a,139}, /* 0x1f */ - { 0x41,0x22,157}, /* 0x20 */ - { 0x70,0x24,162}, /* 0x21 */ - { 0x30,0x21,175}, /* 0x22 */ - { 0x4e,0x22,189}, /* 0x23 */ - { 0xde,0x26,194}, /* 0x24 */ - { 0x62,0x06,202}, /* 0x25 */ - { 0x3f,0x03,229}, /* 0x26 */ - { 0xb8,0x06,234}, /* 0x27 */ - { 0x34,0x02,253}, /* 0x28 */ - { 0x58,0x04,255}, /* 0x29 */ - { 0x24,0x01,265}, /* 0x2a */ - { 0x9b,0x02,267}, /* 0x2b */ - { 0x70,0x05,270}, /* 0x2c */ - { 0x25,0x01,272}, /* 0x2d */ - { 0x9c,0x02,277}, /* 0x2e */ - { 0x27,0x01,286}, /* 0x2f */ - { 0x3c,0x02,291}, /* 0x30 */ - { 0xef,0x0a,292}, /* 0x31 */ - { 0xf6,0x0a,310}, /* 0x32 */ - { 0x95,0x01,315}, /* 0x33 */ - { 0xf0,0x09,324}, /* 0x34 */ - { 0xfe,0x0a,331}, /* 0x35 */ - { 0xf3,0x09,332}, /* 0x36 */ - { 0xea,0x08,340}, /* 0x37 */ - { 0xe8,0x07,376}, /* 0x38 */ - { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b 301 TV */ - { 0x62,0x24, 70}, /* 0x3c 301 TV */ - { 0x62,0x64, 70}, /* 0x3d 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ - { 0x20,0x26, 33}, /* 0x3f 301 TV */ - { 0x31,0xc2, 39}, /* 0x40 */ - { 0x60,0x36, 30}, /* 0x41 Chrontel */ - { 0x40,0x4a, 28}, /* 0x42 Chrontel */ - { 0x9f,0x46, 44}, /* 0x43 Chrontel */ - { 0x97,0x2c, 26}, /* 0x44 */ - { 0x44,0xe4, 25}, /* 0x45 Chrontel */ - { 0x7e,0x32, 47}, /* 0x46 Chrontel */ - { 0x8a,0x24, 31}, /* 0x47 Chrontel */ - { 0x97,0x2c, 26}, /* 0x48 Chrontel */ - { 0xce,0x3c, 39}, /* 0x49 */ - { 0x52,0x4a, 36}, /* 0x4a Chrontel */ - { 0x34,0x61, 95}, /* 0x4b */ - { 0x78,0x27,108}, /* 0x4c - was 102 */ - { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - { 0x41,0x4e, 21}, /* 0x4e */ - { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ - { 0x19,0x42, 42}, /* 0x50 */ - { 0x54,0x46, 58}, /* 0x51 Chrontel */ - { 0x25,0x42, 61}, /* 0x52 */ - { 0x44,0x44, 66}, /* 0x53 Chrontel */ - { 0x3a,0x62, 70}, /* 0x54 Chrontel */ - { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ - { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ - { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - { 0x52,0x07,149}, /* 0x59 1280x960-85 */ - { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ - { 0x45,0x25, 83}, /* 0x5c 1280x800 */ - { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ - { 0x70,0x24,162}, /* 0x5e 1600x1200 */ - { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ - { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ - { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ - { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ - { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ - { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ - { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ - { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ - { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ - { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ - { 0x45,0x25, 83}, /* 0x6c 1280x800 */ - { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ - { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ - { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ +static const struct SiS_VCLKData SiSUSB_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x00 */ + {0x4e, 0xe4, 28}, /* 0x01 */ + {0x57, 0xe4, 31}, /* 0x02 */ + {0xc3, 0xc8, 36}, /* 0x03 */ + {0x42, 0xe2, 40}, /* 0x04 */ + {0xfe, 0xcd, 43}, /* 0x05 */ + {0x5d, 0xc4, 44}, /* 0x06 */ + {0x52, 0xe2, 49}, /* 0x07 */ + {0x53, 0xe2, 50}, /* 0x08 */ + {0x74, 0x67, 52}, /* 0x09 */ + {0x6d, 0x66, 56}, /* 0x0a */ + {0x5a, 0x64, 65}, /* 0x0b */ + {0x46, 0x44, 67}, /* 0x0c */ + {0xb1, 0x46, 68}, /* 0x0d */ + {0xd3, 0x4a, 72}, /* 0x0e */ + {0x29, 0x61, 75}, /* 0x0f */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a 301 TV */ + {0x52, 0x6a, 27}, /* 0x3b 301 TV */ + {0x62, 0x24, 70}, /* 0x3c 301 TV */ + {0x62, 0x64, 70}, /* 0x3d 301 TV */ + {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ + {0x20, 0x26, 33}, /* 0x3f 301 TV */ + {0x31, 0xc2, 39}, /* 0x40 */ + {0x60, 0x36, 30}, /* 0x41 Chrontel */ + {0x40, 0x4a, 28}, /* 0x42 Chrontel */ + {0x9f, 0x46, 44}, /* 0x43 Chrontel */ + {0x97, 0x2c, 26}, /* 0x44 */ + {0x44, 0xe4, 25}, /* 0x45 Chrontel */ + {0x7e, 0x32, 47}, /* 0x46 Chrontel */ + {0x8a, 0x24, 31}, /* 0x47 Chrontel */ + {0x97, 0x2c, 26}, /* 0x48 Chrontel */ + {0xce, 0x3c, 39}, /* 0x49 */ + {0x52, 0x4a, 36}, /* 0x4a Chrontel */ + {0x34, 0x61, 95}, /* 0x4b */ + {0x78, 0x27, 108}, /* 0x4c - was 102 */ + {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + {0x41, 0x4e, 21}, /* 0x4e */ + {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ + {0x19, 0x42, 42}, /* 0x50 */ + {0x54, 0x46, 58}, /* 0x51 Chrontel */ + {0x25, 0x42, 61}, /* 0x52 */ + {0x44, 0x44, 66}, /* 0x53 Chrontel */ + {0x3a, 0x62, 70}, /* 0x54 Chrontel */ + {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ + {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ + {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ + {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ + {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ + {0x45, 0x25, 83}, /* 0x5c 1280x800 */ + {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ + {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ + {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ + {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ + {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ + {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ + {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ + {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ + {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ + {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ + {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ + {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ + {0x45, 0x25, 83}, /* 0x6c 1280x800 */ + {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ + {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ + {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ }; -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 *data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand); +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 data); +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 * data); +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand, u8 myor); +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 myor); +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand); void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); -int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written); + u32 dest, int length, size_t * bytes_written); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 *arg, int cmapsz, int ch512, int dorecalc, + u8 * arg, int cmapsz, int ch512, int dorecalc, struct vc_data *c, int fh, int uplock); void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); @@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb); void sisusb_init_concode(void); #endif - diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index f325ecb29a6..1c4240e802c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -44,7 +44,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -52,85 +52,78 @@ #define _SISUSB_STRUCT_H_ struct SiS_St { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; - unsigned char St_PDC; + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; }; -struct SiS_StandTable -{ - unsigned char CRT_COLS; - unsigned char ROWS; - unsigned char CHAR_HEIGHT; - unsigned short CRT_LEN; - unsigned char SR[4]; - unsigned char MISC; - unsigned char CRTC[0x19]; - unsigned char ATTR[0x14]; - unsigned char GRC[9]; +struct SiS_StandTable { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; }; struct SiS_StResInfo_S { - unsigned short HTotal; - unsigned short VTotal; + unsigned short HTotal; + unsigned short VTotal; }; -struct SiS_Ext -{ - unsigned char Ext_ModeID; - unsigned short Ext_ModeFlag; - unsigned short Ext_VESAID; - unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; - unsigned char VB_ExtTVYFilterIndex; - unsigned char VB_ExtTVYFilterIndexROM661; - unsigned char REFindex; - char ROMMODEIDX661; +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; }; -struct SiS_Ext2 -{ - unsigned short Ext_InfoFlag; - unsigned char Ext_CRT1CRTC; - unsigned char Ext_CRTVCLK; - unsigned char Ext_CRT2CRTC; - unsigned char Ext_CRT2CRTC_NS; - unsigned char ModeID; - unsigned short XRes; - unsigned short YRes; - unsigned char Ext_PDC; - unsigned char Ext_FakeCRT2CRTC; - unsigned char Ext_FakeCRT2Clk; +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; }; -struct SiS_CRT1Table -{ - unsigned char CR[17]; +struct SiS_CRT1Table { + unsigned char CR[17]; }; -struct SiS_VCLKData -{ - unsigned char SR2B,SR2C; - unsigned short CLOCK; +struct SiS_VCLKData { + unsigned char SR2B, SR2C; + unsigned short CLOCK; }; -struct SiS_ModeResInfo -{ - unsigned short HTotal; - unsigned short VTotal; - unsigned char XChar; - unsigned char YChar; +struct SiS_ModeResInfo { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; }; -struct SiS_Private -{ +struct SiS_Private { void *sisusb; unsigned long IOAddress; @@ -151,19 +144,18 @@ struct SiS_Private unsigned long SiS_P3da; unsigned long SiS_Part1Port; - unsigned char SiS_MyCR63; - unsigned short SiS_CRT1Mode; - unsigned short SiS_ModeType; - unsigned short SiS_SetFlag; - - const struct SiS_StandTable *SiS_StandTable; - const struct SiS_St *SiS_SModeIDTable; - const struct SiS_Ext *SiS_EModeIDTable; - const struct SiS_Ext2 *SiS_RefIndex; - const struct SiS_CRT1Table *SiS_CRT1Table; - const struct SiS_VCLKData *SiS_VCLKData; - const struct SiS_ModeResInfo *SiS_ModeResInfo; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_ModeType; + unsigned short SiS_SetFlag; + + const struct SiS_StandTable *SiS_StandTable; + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_VCLKData *SiS_VCLKData; + const struct SiS_ModeResInfo *SiS_ModeResInfo; }; #endif - diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c03dfd7a9d3..f06e4e2b49d 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, #define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) +static unsigned char xfer_to_pipe[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + static struct class *mon_bin_class; static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb, const struct urb *urb, char ev_type) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); - } if (urb->setup_packet == NULL) return 'Z'; @@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, } static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { + const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; struct timeval ts; unsigned int urb_length; unsigned int offset; unsigned int length; + unsigned char dir; struct mon_bin_hdr *ep; char data_tag = 0; @@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, if (length >= rp->b_size/5) length = rp->b_size/5; - if (usb_pipein(urb->pipe)) { + if (usb_urb_dir_in(urb)) { if (ev_type == 'S') { length = 0; data_tag = '<'; } + /* Cannot rely on endpoint number in case of control ep.0 */ + dir = USB_DIR_IN; } else { if (ev_type == 'C') { length = 0; data_tag = '>'; } + dir = 0; } if (rp->mmap_active) @@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; + ep->epnum = dir | usb_endpoint_num(epd); + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; ep->ts_usec = ts.tv_usec; - ep->status = urb->status; + ep->status = status; ep->len_urb = urb_length; ep->len_cap = length; @@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, static void mon_bin_submit(void *data, struct urb *urb) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S'); + mon_bin_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_bin_complete(void *data, struct urb *urb) +static void mon_bin_complete(void *data, struct urb *urb, int status) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C'); + mon_bin_event(rp, urb, 'C', status); } static void mon_bin_error(void *data, struct urb *urb, int error) @@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; + ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; + ep->epnum |= usb_endpoint_num(&urb->ep->desc); + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->status = error; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index ce61d8b0fd8..b371ffd39d3 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, + int status) { unsigned long flags; struct list_head *pos; @@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); + r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); } -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; - mbus = ubus->mon_bus; - if (mbus == NULL) { - /* - * This should not happen. - * At this point we do not even know the bus number... - */ - printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n", - urb->pipe); - return; - } - - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_complete(mbus, urb, status); + mon_bus_complete(&mon_bus0, urb, status); } /* int (*unlink_urb) (struct urb *urb, int status); */ @@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) */ static void mon_stop(struct mon_bus *mbus) { - struct usb_bus *ubus = mbus->u_bus; + struct usb_bus *ubus; struct list_head *p; if (mbus == &mon_bus0) { diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 8f27a9e1c36..ebb04ac4857 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,10 +50,13 @@ struct mon_iso_desc { struct mon_event_text { struct list_head e_link; int type; /* submit, complete, etc. */ - unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; int busnum; + char devnum; + char epnum; + char is_in; + char xfertype; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, struct urb *urb, char ev_type, struct mon_bus *mbus) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); - } if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ @@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type, struct mon_bus *mbus) { - int pipe = urb->pipe; - if (len <= 0) return 'L'; if (len >= DATA_MAX) len = DATA_MAX; - if (usb_pipein(pipe)) { + if (ep->is_in) { if (ev_type != 'C') return '<'; } else { @@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void) } static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { struct mon_event_text *ep; unsigned int stamp; @@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, } ep->type = ev_type; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = urb->dev->bus->busnum; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ - ep->status = urb->status; + ep->status = status; - if (usb_pipeint(urb->pipe)) { + if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { ep->interval = urb->interval; ep->start_frame = urb->start_frame; ep->error_count = urb->error_count; } ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { + if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && + urb->number_of_packets > 0) { if ((ndesc = urb->number_of_packets) > ISODESC_MAX) ndesc = ISODESC_MAX; fp = urb->iso_frame_desc; @@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, static void mon_text_submit(void *data, struct urb *urb) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S'); + mon_text_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_text_complete(void *data, struct urb *urb) +static void mon_text_complete(void *data, struct urb *urb, int status) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C'); + mon_text_event(rp, urb, 'C', status); } static void mon_text_error(void *data, struct urb *urb, int error) @@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) } ep->type = 'E'; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = 0; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = 0; ep->length = 0; ep->status = error; @@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf, mon_text_read_head_u(rp, &ptr, ep); if (ep->type == 'E') { mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { mon_text_read_isostat(rp, &ptr, ep); mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { mon_text_read_intstat(rp, &ptr, ep); } else { mon_text_read_statset(rp, &ptr, ep); @@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->devnum, ep->epnum); } static void mon_text_read_head_u(struct mon_reader_text *rp, @@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->busnum, ep->devnum, ep->epnum); } static void mon_text_read_statset(struct mon_reader_text *rp, diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f68ad6d99ad..f5d84ff8c10 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -46,7 +46,7 @@ struct mon_reader { void (*rnf_submit)(void *data, struct urb *urb); void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb); + void (*rnf_complete)(void *data, struct urb *urb, int status); }; void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 43d6db696f9..99fefed7791 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN To compile this driver as a module, choose M here: the module will be called belkin_sa. +config USB_SERIAL_CH341 + tristate "USB Winchiphead CH341 Single Port Serial Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Winchiphead CH341 single port + USB to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called ch341. + config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 07a976eca6b..d6fb384e52b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o +obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index c9fd486c1c7..2a8e537cb04 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { *(port->tty->termios) = tty_std_termios; diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index a47a24f8820..0b14aea8ebd 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr return 0; } +static ssize_t show_port_number(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + + return sprintf(buf, "%d\n", port->number - port->serial->minor); +} + +static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); + static int usb_serial_device_probe (struct device *dev) { struct usb_serial_driver *driver; @@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev) goto exit; } + retval = device_create_file(dev, &dev_attr_port_number); + if (retval) + goto exit; + minor = port->number; tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, @@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev) return -ENODEV; } + device_remove_file(&port->dev, &dev_attr_port_number); + driver = port->serial->type; if (driver->port_remove) { if (!try_module_get(driver->driver.owner)) { diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c new file mode 100644 index 00000000000..6b252ceb39a --- /dev/null +++ b/drivers/usb/serial/ch341.c @@ -0,0 +1,354 @@ +/* + * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk> + * + * ch341.c implements a serial port driver for the Winchiphead CH341. + * + * The CH341 device can be used to implement an RS232 asynchronous + * serial port, an IEEE-1284 parallel printer port or a memory-like + * interface. In all cases the CH341 supports an I2C interface as well. + * This driver only supports the asynchronous serial interface. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/serial.h> + +#define DEFAULT_BAUD_RATE 2400 +#define DEFAULT_TIMEOUT 1000 + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x4348, 0x5523) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ch341_private { + unsigned baud_rate; + u8 dtr; + u8 rts; +}; + +static int ch341_control_out(struct usb_device *dev, u8 request, + u16 value, u16 index) +{ + int r; + dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, + (int)request, (int)value, (int)index); + + r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, index, NULL, 0, DEFAULT_TIMEOUT); + + return r; +} + +static int ch341_control_in(struct usb_device *dev, + u8 request, u16 value, u16 index, + char *buf, unsigned bufsize) +{ + int r; + dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, + (int)request, (int)value, (int)index, buf, (int)bufsize); + + r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, index, buf, bufsize, DEFAULT_TIMEOUT); + return r; +} + +static int ch341_set_baudrate(struct usb_device *dev, + struct ch341_private *priv) +{ + short a, b; + int r; + + dbg("ch341_set_baudrate(%d)", priv->baud_rate); + switch (priv->baud_rate) { + case 2400: + a = 0xd901; + b = 0x0038; + break; + case 4800: + a = 0x6402; + b = 0x001f; + break; + case 9600: + a = 0xb202; + b = 0x0013; + break; + case 19200: + a = 0xd902; + b = 0x000d; + break; + case 38400: + a = 0x6403; + b = 0x000a; + break; + case 115200: + a = 0xcc03; + b = 0x0008; + break; + default: + return -EINVAL; + } + + r = ch341_control_out(dev, 0x9a, 0x1312, a); + if (!r) + r = ch341_control_out(dev, 0x9a, 0x0f2c, b); + + return r; +} + +static int ch341_set_handshake(struct usb_device *dev, + struct ch341_private *priv) +{ + dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); + return ch341_control_out(dev, 0xa4, + ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); +} + +static int ch341_get_status(struct usb_device *dev) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_get_status()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); + if ( r < 0) + goto out; + + /* Not having the datasheet for the CH341, we ignore the bytes returned + * from the device. Return error if the device did not respond in time. + */ + r = 0; + +out: kfree(buffer); + return r; +} + +/* -------------------------------------------------------------------------- */ + +static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_configure()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* expect two bytes 0x27 0x00 */ + r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0, 0); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + /* expect two bytes 0x56 0x00 */ + r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050); + if (r < 0) + goto out; + + /* expect 0xff 0xee */ + r = ch341_get_status(dev); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + r = ch341_set_handshake(dev, priv); + if (r < 0) + goto out; + + /* expect 0x9f 0xee */ + r = ch341_get_status(dev); + +out: kfree(buffer); + return r; +} + +/* allocate private data */ +static int ch341_attach(struct usb_serial *serial) +{ + struct ch341_private *priv; + int r; + + dbg("ch341_attach()"); + + /* private data */ + priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r < 0) + goto error; + + usb_set_serial_port_data(serial->port[0], priv); + return 0; + +error: kfree(priv); + return r; +} + +/* open this device, set default parameters */ +static int ch341_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); + int r; + + dbg("ch341_open()"); + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_handshake(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_baudrate(serial->dev, priv); + if (r) + goto out; + + r = usb_serial_generic_open(port, filp); + +out: return r; +} + +/* Old_termios contains the original termios settings and + * tty->termios contains the new setting to be used. + */ +static void ch341_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty = port->tty; + unsigned baud_rate; + + dbg("ch341_set_termios()"); + + if (!tty || !tty->termios) + return; + + baud_rate = tty_get_baud_rate(tty); + + switch (baud_rate) { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 115200: + priv->baud_rate = baud_rate; + break; + default: + dbg("Rate %d not supported, using %d", + baud_rate, DEFAULT_BAUD_RATE); + priv->baud_rate = DEFAULT_BAUD_RATE; + } + + ch341_set_baudrate(port->serial->dev, priv); + + /* Unimplemented: + * (cflag & CSIZE) : data bits [5, 8] + * (cflag & PARENB) : parity {NONE, EVEN, ODD} + * (cflag & CSTOPB) : stop bits [1, 2] + */ +} + +static struct usb_driver ch341_driver = { + .name = "ch341", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver ch341_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ch341-uart", + }, + .id_table = id_table, + .usb_driver = &ch341_driver, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ch341_open, + .set_termios = ch341_set_termios, + .attach = ch341_attach, +}; + +static int __init ch341_init(void) +{ + int retval; + + retval = usb_serial_register(&ch341_device); + if (retval) + return retval; + retval = usb_register(&ch341_driver); + if (retval) + usb_serial_deregister(&ch341_device); + return retval; +} + +static void __exit ch341_exit(void) +{ + usb_deregister(&ch341_driver); + usb_serial_deregister(&ch341_device); +} + +module_init(ch341_init); +module_exit(ch341_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* EOF ch341.c */ diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 33f6ee50b8d..eb7df1835c1 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*); static int debug; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ @@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if ((!port->tty) || (!port->tty->termios)) { + if (!port->tty || !port->tty->termios) { dbg("%s - no tty structures", __FUNCTION__); return; } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2d045857b18..e4c248c98e8 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) { + if (priv->chip_type == FT232BM || + priv->chip_type == FT2232C || + priv->chip_type == FT232RL) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT8U232AM: case FT232BM: case FT2232C: + case FT232RL: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 4092f6dc9ef..b5194dc7d3b 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ktermios t; - - dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); - - if (cmd == TCSETSF) { - if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) - return -EFAULT; - - dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, - t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); - - if (!(t.c_lflag & ICANON)) - return -EINVAL; - } - return -ENOIOCTLCMD; -} - static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, - .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6a3a704b584..e836ad07fdb 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ + { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ @@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) kfree(port->bulk_out_buffer); port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_in_buffer == NULL) { + port->bulk_out_buffer = NULL; /* prevent double free */ goto enomem; } port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_out_buffer == NULL) { kfree(port->bulk_in_buffer); + port->bulk_in_buffer = NULL; goto enomem; } port->read_urb->transfer_buffer = port->bulk_in_buffer; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5a4127e62c4..90e3216abd1 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port, #endif } - switch(cflag & CBAUD) { - case B0: /* handled below */ + switch(tty_get_baud_rate(port->tty)) { + case 0: /* handled below */ break; - case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; + case 1200: + priv->cfg.baudrate = kl5kusb105a_sio_b1200; break; - case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; + case 2400: + priv->cfg.baudrate = kl5kusb105a_sio_b2400; break; - case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; + case 4800: + priv->cfg.baudrate = kl5kusb105a_sio_b4800; break; - case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; + case 9600: + priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; - case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; + case 19200: + priv->cfg.baudrate = kl5kusb105a_sio_b19200; break; - case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; + case 38400: + priv->cfg.baudrate = kl5kusb105a_sio_b38400; break; - case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; + case 57600: + priv->cfg.baudrate = kl5kusb105a_sio_b57600; break; - case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; + case 115200: + priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: err("KLSI USB->Serial converter:" diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 02a86dbc0e9..6f224195bd2 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void kobil_read_int_callback( struct urb *urb ); static void kobil_write_callback( struct urb *purb ); +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old); static struct usb_device_id id_table [] = { @@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = { .attach = kobil_startup, .shutdown = kobil_shutdown, .ioctl = kobil_ioctl, + .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, .tiocmset = kobil_tiocmset, .open = kobil_open, @@ -137,7 +139,6 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct ktermios internal_termios; }; @@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial) static int kobil_open (struct usb_serial_port *port, struct file *filp) { - int i, result = 0; + int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; @@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) - // set up internal termios structure - priv->internal_termios.c_iflag = port->tty->termios->c_iflag; - priv->internal_termios.c_oflag = port->tty->termios->c_oflag; - priv->internal_termios.c_cflag = port->tty->termios->c_cflag; - priv->internal_termios.c_lflag = port->tty->termios->c_lflag; - - for (i=0; i<NCCS; i++) { - priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i]; - } - // allocate memory for transfer buffer transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { @@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, return (result < 0) ? result : 0; } - -static int kobil_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old) { struct kobil_private * priv; int result; unsigned short urb_val = 0; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - char *settings; - void __user *user_arg = (void __user *)arg; + int c_cflag = port->tty->termios->c_cflag; + speed_t speed; + void * settings; priv = usb_get_serial_port_data(port); - if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) // This device doesn't support ioctl calls - return 0; - } - - switch (cmd) { - case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (kernel_termios_to_user_termios((struct ktermios __user *)arg, - &priv->internal_termios)) - return -EFAULT; - return 0; - - case TCSETS: // 0x5402 - if (!(port->tty->termios)) { - dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); - return -ENOTTY; - } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct ktermios __user *)arg)) - return -EFAULT; - - settings = kzalloc(50, GFP_KERNEL); - if (! settings) { - return -ENOBUFS; - } + return; - switch (priv->internal_termios.c_cflag & CBAUD) { - case B1200: + switch (speed = tty_get_baud_rate(port->tty)) { + case 1200: urb_val = SUSBCR_SBR_1200; - strcat(settings, "1200 "); break; - case B9600: + case 9600: default: urb_val = SUSBCR_SBR_9600; - strcat(settings, "9600 "); break; - } + } + urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; + + settings = kzalloc(50, GFP_KERNEL); + if (! settings) + return; - urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; - strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); + sprintf(settings, "%d ", speed); - if (priv->internal_termios.c_cflag & PARENB) { - if (priv->internal_termios.c_cflag & PARODD) { - urb_val |= SUSBCR_SPASB_OddParity; - strcat(settings, "Odd Parity"); - } else { - urb_val |= SUSBCR_SPASB_EvenParity; - strcat(settings, "Even Parity"); - } + if (c_cflag & PARENB) { + if (c_cflag & PARODD) { + urb_val |= SUSBCR_SPASB_OddParity; + strcat(settings, "Odd Parity"); } else { - urb_val |= SUSBCR_SPASB_NoParity; - strcat(settings, "No Parity"); + urb_val |= SUSBCR_SPASB_EvenParity; + strcat(settings, "Even Parity"); } - dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); + } else { + urb_val |= SUSBCR_SPASB_NoParity; + strcat(settings, "No Parity"); + } - result = usb_control_msg( port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0 ), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - urb_val, - 0, - settings, - 0, - KOBIL_TIMEOUT - ); + result = usb_control_msg( port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0 ), + SUSBCRequest_SetBaudRateParityAndStopBits, + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, + urb_val, + 0, + settings, + 0, + KOBIL_TIMEOUT + ); + kfree(settings); +} - dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); - kfree(settings); +static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct kobil_private * priv = usb_get_serial_port_data(port); + unsigned char *transfer_buffer; + int transfer_buffer_length = 8; + int result; + + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) + // This device doesn't support ioctl calls return 0; + switch (cmd) { case TCFLSH: // 0x540B transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); - if (! transfer_buffer) { + if (! transfer_buffer) return -ENOBUFS; - } result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), @@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, ); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); - kfree(transfer_buffer); - return ((result < 0) ? -EFAULT : 0); - + return (result < 0) ? -EFAULT : 0; + default: + return -ENOIOCTLCMD; } - return -ENOIOCTLCMD; } - static int __init kobil_init (void) { int retval; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index e08c9bb403d..0dc99f75bb0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value } } else { switch (value) { - case 300: break; - case 600: break; - case 1200: break; - case 2400: break; - case 4800: break; - case 9600: break; - case 19200: break; - case 38400: break; - case 57600: break; - case 115200: break; - default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); - value = 9600; + case 300: break; + case 600: break; + case 1200: break; + case 2400: break; + case 4800: break; + case 9600: break; + case 19200: break; + case 38400: break; + case 57600: break; + case 115200: break; + default: + err("MCT USB-RS232: unsupported baudrate request 0x%x," + " using default of B9600", value); + value = 9600; } return 115200/value; } diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 64f3f66a7a3..d19861166b5 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) if (size == 0) return NULL; - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); if (pb == NULL) return NULL; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f9f85f56f0d..1da57fd9ea2 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index f9a71d0c102..c39bace5cbc 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -59,6 +59,7 @@ #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 #define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 #define SYNTECH_VENDOR_ID 0x0745 #define SYNTECH_PRODUCT_ID 0x0001 diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 51669b7622b..4e6dcc199be 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); -#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" -#endif - -#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) static __u16 vendor; // no default static __u16 product; // no default module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); -#endif module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); @@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp -#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR) - {MY_USB_DEVICE - (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS, - LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -#endif // extra null entry for module // vendor/produc parameters {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9bf01a5efc8..4b1bd7def4a 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); + /* + * This is tricky. + * Some drivers submit the read_urb in the + * handler for the write_urb or vice versa + * this order determines the order in which + * usb_kill_urb() must be used to reliably + * kill the URBs. As it is unknown here, + * both orders must be used in turn. + * The call below is not redundant. + */ + usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); } @@ -651,16 +662,14 @@ exit: static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { - struct list_head *p; const struct usb_device_id *id; - struct usb_serial_driver *t; + struct usb_serial_driver *drv; /* Check if the usb id matches a known device */ - list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_driver, driver_list); - id = get_iface_id(t, iface); + list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { + id = get_iface_id(drv, iface); if (id) - return t; + return drv; } return NULL; @@ -800,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface, /* END HORRIBLE HACK FOR PL2303 */ #endif - /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->description); - #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; @@ -836,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_out = num_interrupt_out; + /* check that the device meets the driver's requirements */ + if ((type->num_interrupt_in != NUM_DONT_CARE && + type->num_interrupt_in != num_interrupt_in) + || (type->num_interrupt_out != NUM_DONT_CARE && + type->num_interrupt_out != num_interrupt_out) + || (type->num_bulk_in != NUM_DONT_CARE && + type->num_bulk_in != num_bulk_in) + || (type->num_bulk_out != NUM_DONT_CARE && + type->num_bulk_out != num_bulk_out)) { + dbg("wrong number of endpoints"); + kfree(serial); + return -EIO; + } + + /* found all that we need */ + dev_info(&interface->dev, "%s converter detected\n", + type->description); + /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = max(num_bulk_in, num_bulk_out); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 30e08c0bcdc..7ee087fed91 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = { .unthrottle = visor_unthrottle, .attach = clie_3_5_startup, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign return -ENOIOCTLCMD; } - -/* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) -{ - unsigned int cflag; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if ((!port->tty) || (!port->tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - - cflag = port->tty->termios->c_cflag; - - /* get the byte size */ - switch (cflag & CSIZE) { - case CS5: dbg("%s - data bits = 5", __FUNCTION__); break; - case CS6: dbg("%s - data bits = 6", __FUNCTION__); break; - case CS7: dbg("%s - data bits = 7", __FUNCTION__); break; - default: - case CS8: dbg("%s - data bits = 8", __FUNCTION__); break; - } - - /* determine the parity */ - if (cflag & PARENB) - if (cflag & PARODD) - dbg("%s - parity = odd", __FUNCTION__); - else - dbg("%s - parity = even", __FUNCTION__); - else - dbg("%s - parity = none", __FUNCTION__); - - /* figure out the stop bits requested */ - if (cflag & CSTOPB) - dbg("%s - stop bits = 2", __FUNCTION__); - else - dbg("%s - stop bits = 1", __FUNCTION__); - - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) - dbg("%s - RTS/CTS is enabled", __FUNCTION__); - else - dbg("%s - RTS/CTS is disabled", __FUNCTION__); - - /* determine software flow control */ - if (I_IXOFF(port->tty)) - dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty)); - else - dbg("%s - XON/XOFF is disabled", __FUNCTION__); - - /* get the baud rate wanted */ - dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty)); - - return; -} - - static int __init visor_init (void) { int i, retval; diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 3a41740cad9..ee5b42aa536 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return (res ? -1 : 0); } + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us) +{ + int result; + + us->iobuf[0] = 0x1; + result = usb_stor_control_msg(us, us->send_ctrl_pipe, + USB_REQ_SET_FEATURE, + USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0x01, 0x0, us->iobuf, 0x1, 1000); + US_DEBUGP("usb_control_msg performing result is %d\n", result); + return (result ? 0 : -1); +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index e2967a4d48a..ad3ffd4236c 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us); /* This function is required to activate all four slots on the UCR-61S2B * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us); diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 5e27297c017..17ca4d73577 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us) unsigned char *reply = us->iobuf; int rc; - if (!us) - return USB_STOR_TRANSPORT_ERROR; - rc = usbat_get_status(us, reply); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c6b78ba815e..9b656ec427d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Bardur Arantsson <bardur@scientician.net> */ -UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610, "Nokia", "6131", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */ +UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D200", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Emil Larsson <emil@swip.net> */ UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, "NIKON", @@ -355,6 +362,20 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Paul Check <paul@openstreet.com> */ +UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D2Xs", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + +/* Reported by Shan Destromp (shansan@gmail.com) */ +UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D40X", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena <mfombuena@ya.com> and * Frank Copeland <fjc@thingy.apana.org.au> */ @@ -1463,6 +1484,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com> + * and by linlei <linlei83@huawei.com> + * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at> + * This brings the HUAWEI E220 devices into multi-port mode + */ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, + "HUAWEI MOBILE", + "Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init, + 0), + /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */ UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001, "Minolta", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 59181667066..3451e8d03ab 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf, return -ENOMEM; } + /* + * Allow 16-byte CDBs and thus > 2TB + */ + host->max_cmd_len = 16; us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 8de11deb5d1..c815a40e167 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file) /* save our object in the file's private structure */ file->private_data = dev; + mutex_unlock(&dev->io_mutex); exit: return retval; diff --git a/drivers/video/output.c b/drivers/video/output.c index 1473f2c892d..f2df5519c9c 100644 --- a/drivers/video/output.c +++ b/drivers/video/output.c @@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>"); -static ssize_t video_output_show_state(struct class_device *dev,char *buf) +static ssize_t video_output_show_state(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t ret_size = 0; struct output_device *od = to_output_device(dev); @@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf) return ret_size; } -static ssize_t video_output_store_state(struct class_device *dev, - const char *buf,size_t count) +static ssize_t video_output_store_state(struct device *dev, + struct device_attribute *attr, + const char *buf,size_t count) { char *endp; struct output_device *od = to_output_device(dev); @@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev, return count; } -static void video_output_class_release(struct class_device *dev) +static void video_output_release(struct device *dev) { struct output_device *od = to_output_device(dev); kfree(od); } -static struct class_device_attribute video_output_attributes[] = { +static struct device_attribute video_output_attributes[] = { __ATTR(state, 0644, video_output_show_state, video_output_store_state), __ATTR_NULL, }; + static struct class video_output_class = { .name = "video_output", - .release = video_output_class_release, - .class_dev_attrs = video_output_attributes, + .dev_release = video_output_release, + .dev_attrs = video_output_attributes, }; struct output_device *video_output_register(const char *name, @@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name, goto error_return; } new_dev->props = op; - new_dev->class_dev.class = &video_output_class; - new_dev->class_dev.dev = dev; - strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); - class_set_devdata(&new_dev->class_dev,devdata); - ret_code = class_device_register(&new_dev->class_dev); + new_dev->dev.class = &video_output_class; + new_dev->dev.parent = dev; + strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE); + dev_set_drvdata(&new_dev->dev, devdata); + ret_code = device_register(&new_dev->dev); if (ret_code) { kfree(new_dev); goto error_return; @@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev) { if (!dev) return; - class_device_unregister(&dev->class_dev); + device_unregister(&dev->dev); } EXPORT_SYMBOL(video_output_unregister); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a593f900eff..070217322c9 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -197,7 +197,7 @@ static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; -static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); static struct bus_type w1_bus_type = { .name = "w1", @@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master) } #ifdef CONFIG_HOTPLUG -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; struct w1_slave *sl = NULL; char *event_owner, *name; - int err, cur_index=0, cur_len=0; + int err; if (dev->driver == &w1_master_driver) { md = container_of(dev, struct w1_master, dev); @@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, if (dev->driver != &w1_slave_driver || !sl) return 0; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_FID=%02X", sl->reg_num.family); + err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family); if (err) return err; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_SLAVE_ID=%024LX", - (unsigned long long)sl->reg_num.id); - envp[cur_index] = NULL; + err = add_uevent_var(env, "W1_SLAVE_ID=%024LX", + (unsigned long long)sl->reg_num.id); if (err) return err; return 0; }; #else -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { return 0; } |