/shark/trunk/drivers/linuxc26/linuxcomp.c |
---|
38,8 → 38,15 |
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ |
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ |
__kernel_size_t strnlen(const char *s, __kernel_size_t count) |
{ |
const char *sc; |
for (sc = s; count-- && *sc != '\0'; ++sc) |
/* nothing */; |
return sc - s; |
} |
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); |
struct resource ioport_resource = { |
246,146 → 253,9 |
return err; |
} |
void device_initialize(struct device *dev) |
{ |
kobject_init(&dev->kobj); |
INIT_LIST_HEAD(&dev->node); |
INIT_LIST_HEAD(&dev->children); |
INIT_LIST_HEAD(&dev->driver_list); |
INIT_LIST_HEAD(&dev->bus_list); |
} |
int device_add(struct device *dev) |
{ |
struct device * parent; |
int error; |
dev = get_device(dev); |
if (!dev || !strlen(dev->bus_id)) |
return -EINVAL; |
parent = get_device(dev->parent); |
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); |
/* first, register with generic layer. */ |
kobject_set_name(&dev->kobj,dev->bus_id); |
if (parent) |
dev->kobj.parent = &parent->kobj; |
if ((error = kobject_add(&dev->kobj))) |
goto Error; |
if (parent) |
list_add_tail(&dev->node,&parent->children); |
Done: |
put_device(dev); |
return error; |
Error: |
if (parent) |
put_device(parent); |
goto Done; |
} |
void device_del(struct device * dev) |
{ |
struct device * parent = dev->parent; |
if (parent) |
list_del_init(&dev->node); |
kobject_del(&dev->kobj); |
if (parent) |
put_device(parent); |
} |
#define to_drv(obj) container_of(obj,struct device_driver,kobj) |
struct device_driver * get_driver(struct device_driver * drv) |
{ |
return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; |
} |
void put_driver(struct device_driver * drv) |
{ |
kobject_put(&drv->kobj); |
} |
void driver_unregister(struct device_driver * drv) |
{ |
} |
int driver_register(struct device_driver * drv) |
{ |
INIT_LIST_HEAD(&drv->devices); |
return 0; |
} |
#define to_dev(obj) container_of(obj,struct device,kobj) |
struct device * get_device(struct device * dev) |
{ |
return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; |
} |
void put_device(struct device * dev) |
{ |
kobject_put(&dev->kobj); |
} |
int device_register(struct device *dev) |
{ |
return device_add(dev); |
} |
void device_unregister(struct device * dev) |
{ |
pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); |
device_del(dev); |
put_device(dev); |
} |
int bus_register(struct bus_type * bus) |
{ |
return 0; |
} |
int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot) |
{ return 0; } |
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) |
{ |
unsigned long result = 0,value; |
if (!base) { |
base = 10; |
if (*cp == '0') { |
base = 8; |
cp++; |
if ((*cp == 'x') && isxdigit(cp[1])) { |
cp++; |
base = 16; |
} |
} |
} |
while (isxdigit(*cp) && |
(value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { |
result = result*base + value; |
cp++; |
} |
if (endp) |
*endp = (char *)cp; |
return result; |
} |
long simple_strtol(const char *cp,char **endp,unsigned int base) |
{ |
if(*cp=='-') |
return -simple_strtoul(cp+1,endp,base); |
return simple_strtoul(cp,endp,base); |
} |
void dump_stack(void) { } |
void panic(const char * fmt, ...) { |
/shark/trunk/drivers/linuxc26/base.h |
---|
0,0 → 1,17 |
extern int bus_add_device(struct device * dev); |
extern void bus_remove_device(struct device * dev); |
extern int bus_add_driver(struct device_driver *); |
extern void bus_remove_driver(struct device_driver *); |
static inline struct class_device *to_class_dev(struct kobject *obj) |
{ |
return container_of(obj,struct class_device,kobj); |
} |
static inline |
struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) |
{ |
return container_of(_attr,struct class_device_attribute,attr); |
} |
/shark/trunk/drivers/linuxc26/interface.c |
---|
0,0 → 1,53 |
/* |
* drivers/base/interface.c - common driverfs interface that's exported to |
* the world for all devices. |
* |
* Copyright (c) 2002-3 Patrick Mochel |
* Copyright (c) 2002-3 Open Source Development Labs |
* |
* This file is released under the GPLv2 |
* |
*/ |
#include <linuxcomp.h> |
#include <linux/device.h> |
#include <linux/err.h> |
#include <linux/stat.h> |
#include <linux/string.h> |
/** |
* detach_state - control the default power state for the device. |
* |
* This is the state the device enters when it's driver module is |
* unloaded. The value is an unsigned integer, in the range of 0-4. |
* '0' indicates 'On', so no action will be taken when the driver is |
* unloaded. This is the default behavior. |
* '4' indicates 'Off', meaning the driver core will call the driver's |
* shutdown method to quiesce the device. |
* 1-3 indicate a low-power state for the device to enter via the |
* driver's suspend method. |
*/ |
static ssize_t detach_show(struct device * dev, char * buf) |
{ |
return sprintf26(buf,"%u\n",dev->detach_state); |
} |
static ssize_t detach_store(struct device * dev, const char * buf, size_t n) |
{ |
u32 state; |
state = simple_strtoul(buf,NULL,10); |
if (state > 4) |
return -EINVAL; |
dev->detach_state = state; |
return n; |
} |
static DEVICE_ATTR(detach_state,0644,detach_show,detach_store); |
struct attribute * dev_default_attrs[] = { |
&dev_attr_detach_state.attr, |
NULL, |
}; |
/shark/trunk/drivers/linuxc26/kobject.c |
---|
316,8 → 316,8 |
/* |
* First, try the static array |
*/ |
need = vsnprintf(kobj->name,limit,fmt,args); |
if (need < limit) |
need = vsnprintf26(kobj->name,limit,fmt,args); |
if (need < limit) |
name = kobj->name; |
else { |
/* |
329,7 → 329,7 |
goto Done; |
} |
limit = need; |
need = vsnprintf(name,limit,fmt,args); |
need = vsnprintf26(name,limit,fmt,args); |
/* Still? Give up. */ |
if (need > limit) { |
/shark/trunk/drivers/linuxc26/include/linux/kernel.h |
---|
66,16 → 66,16 |
extern long simple_strtol(const char *,char **,unsigned int); |
extern unsigned long long simple_strtoull(const char *,char **,unsigned int); |
extern long long simple_strtoll(const char *,char **,unsigned int); |
extern int sprintf(char * buf, const char * fmt, ...) |
extern int sprintf26(char * buf, const char * fmt, ...) |
__attribute__ ((format (printf, 2, 3))); |
extern int vsprintf(char *buf, const char *, va_list); |
extern int snprintf(char * buf, size_t size, const char * fmt, ...) |
extern int vsprintf26(char *buf, const char *, va_list); |
extern int snprintf26(char * buf, size_t size, const char * fmt, ...) |
__attribute__ ((format (printf, 3, 4))); |
extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); |
extern int vsnprintf26(char *buf, size_t size, const char *fmt, va_list args); |
extern int sscanf(const char *, const char *, ...) |
extern int sscanf26(const char *, const char *, ...) |
__attribute__ ((format (scanf,2,3))); |
extern int vsscanf(const char *, const char *, va_list); |
extern int vsscanf26(const char *, const char *, va_list); |
extern int get_option(char **str, int *pint); |
extern char *get_options(const char *str, int nints, int *ints); |
/shark/trunk/drivers/linuxc26/core.c |
---|
0,0 → 1,422 |
/* |
* drivers/base/core.c - core driver model code (device registration, etc) |
* |
* Copyright (c) 2002-3 Patrick Mochel |
* Copyright (c) 2002-3 Open Source Development Labs |
* |
* This file is released under the GPLv2 |
* |
*/ |
#undef DEBUG |
#include <linuxcomp.h> |
#include <linux/device.h> |
#include <linux/err.h> |
#include <linux/init.h> |
#include <linux/module.h> |
#include <linux/slab.h> |
#include <linux/string.h> |
#include <asm/semaphore.h> |
#include "base.h" |
int (*platform_notify)(struct device * dev) = NULL; |
int (*platform_notify_remove)(struct device * dev) = NULL; |
/* |
* sysfs bindings for devices. |
*/ |
#define to_dev(obj) container_of(obj,struct device,kobj) |
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) |
extern struct attribute * dev_default_attrs[]; |
static ssize_t |
dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) |
{ |
struct device_attribute * dev_attr = to_dev_attr(attr); |
struct device * dev = to_dev(kobj); |
ssize_t ret = 0; |
if (dev_attr->show) |
ret = dev_attr->show(dev,buf); |
return ret; |
} |
static ssize_t |
dev_attr_store(struct kobject * kobj, struct attribute * attr, |
const char * buf, size_t count) |
{ |
struct device_attribute * dev_attr = to_dev_attr(attr); |
struct device * dev = to_dev(kobj); |
ssize_t ret = 0; |
if (dev_attr->store) |
ret = dev_attr->store(dev,buf,count); |
return ret; |
} |
static struct sysfs_ops dev_sysfs_ops = { |
.show = dev_attr_show, |
.store = dev_attr_store, |
}; |
/** |
* device_release - free device structure. |
* @kobj: device's kobject. |
* |
* This is called once the reference count for the object |
* reaches 0. We forward the call to the device's release |
* method, which should handle actually freeing the structure. |
*/ |
static void device_release(struct kobject * kobj) |
{ |
struct device * dev = to_dev(kobj); |
//struct completion * c = dev->complete; |
if (dev->release) |
dev->release(dev); |
else { |
printk(KERN_ERR "Device '%s' does not have a release() function, " |
"it is broken and must be fixed.\n", |
dev->bus_id); |
WARN_ON(1); |
} |
//if (c) |
// complete(c); |
} |
static struct kobj_type ktype_device = { |
.release = device_release, |
.sysfs_ops = &dev_sysfs_ops, |
.default_attrs = dev_default_attrs, |
}; |
static int dev_hotplug_filter(struct kset *kset, struct kobject *kobj) |
{ |
struct kobj_type *ktype = get_ktype(kobj); |
if (ktype == &ktype_device) { |
struct device *dev = to_dev(kobj); |
if (dev->bus) |
return 1; |
} |
return 0; |
} |
static char *dev_hotplug_name(struct kset *kset, struct kobject *kobj) |
{ |
struct device *dev = to_dev(kobj); |
return dev->bus->name; |
} |
static int dev_hotplug(struct kset *kset, struct kobject *kobj, char **envp, |
int num_envp, char *buffer, int buffer_size) |
{ |
struct device *dev = to_dev(kobj); |
int retval = 0; |
if (dev->bus->hotplug) { |
/* have the bus specific function add its stuff */ |
retval = dev->bus->hotplug (dev, envp, num_envp, buffer, buffer_size); |
if (retval) { |
pr_debug ("%s - hotplug() returned %d\n", |
__FUNCTION__, retval); |
} |
} |
return retval; |
} |
static struct kset_hotplug_ops device_hotplug_ops = { |
.filter = dev_hotplug_filter, |
.name = dev_hotplug_name, |
.hotplug = dev_hotplug, |
}; |
/** |
* device_subsys - structure to be registered with kobject core. |
*/ |
decl_subsys(devices, &ktype_device, &device_hotplug_ops); |
/** |
* device_create_file - create sysfs attribute file for device. |
* @dev: device. |
* @attr: device attribute descriptor. |
*/ |
int device_create_file(struct device * dev, struct device_attribute * attr) |
{ |
int error = 0; |
if (get_device(dev)) { |
error = 0;//sysfs_create_file(&dev->kobj,&attr->attr); |
put_device(dev); |
} |
return error; |
} |
/** |
* device_remove_file - remove sysfs attribute file. |
* @dev: device. |
* @attr: device attribute descriptor. |
*/ |
void device_remove_file(struct device * dev, struct device_attribute * attr) |
{ |
if (get_device(dev)) { |
//sysfs_remove_file(&dev->kobj,&attr->attr); |
put_device(dev); |
} |
} |
/** |
* device_initialize - init device structure. |
* @dev: device. |
* |
* This prepares the device for use by other layers, |
* including adding it to the device hierarchy. |
* It is the first half of device_register(), if called by |
* that, though it can also be called separately, so one |
* may use @dev's fields (e.g. the refcount). |
*/ |
void device_initialize(struct device *dev) |
{ |
kobj_set_kset_s(dev,devices_subsys); |
kobject_init(&dev->kobj); |
INIT_LIST_HEAD(&dev->node); |
INIT_LIST_HEAD(&dev->children); |
INIT_LIST_HEAD(&dev->driver_list); |
INIT_LIST_HEAD(&dev->bus_list); |
} |
/** |
* device_add - add device to device hierarchy. |
* @dev: device. |
* |
* This is part 2 of device_register(), though may be called |
* separately _iff_ device_initialize() has been called separately. |
* |
* This adds it to the kobject hierarchy via kobject_add(), adds it |
* to the global and sibling lists for the device, then |
* adds it to the other relevant subsystems of the driver model. |
*/ |
int device_add(struct device *dev) |
{ |
struct device * parent; |
int error; |
dev = get_device(dev); |
if (!dev || !strlen(dev->bus_id)) |
return -EINVAL; |
parent = get_device(dev->parent); |
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); |
/* first, register with generic layer. */ |
kobject_set_name(&dev->kobj,dev->bus_id); |
if (parent) |
dev->kobj.parent = &parent->kobj; |
if ((error = kobject_add(&dev->kobj))) |
goto Error; |
//if ((error = device_pm_add(dev))) |
// goto PMError; |
if ((error = bus_add_device(dev))) |
goto BusError; |
//down_write(&devices_subsys.rwsem); |
if (parent) |
list_add_tail(&dev->node,&parent->children); |
//up_write(&devices_subsys.rwsem); |
/* notify platform of device entry */ |
if (platform_notify) |
platform_notify(dev); |
Done: |
put_device(dev); |
return error; |
BusError: |
//device_pm_remove(dev); |
//PMError: |
kobject_unregister(&dev->kobj); |
Error: |
if (parent) |
put_device(parent); |
goto Done; |
} |
/** |
* device_register - register a device with the system. |
* @dev: pointer to the device structure |
* |
* This happens in two clean steps - initialize the device |
* and add it to the system. The two steps can be called |
* separately, but this is the easiest and most common. |
* I.e. you should only call the two helpers separately if |
* have a clearly defined need to use and refcount the device |
* before it is added to the hierarchy. |
*/ |
int device_register(struct device *dev) |
{ |
device_initialize(dev); |
return device_add(dev); |
} |
/** |
* get_device - increment reference count for device. |
* @dev: device. |
* |
* This simply forwards the call to kobject_get(), though |
* we do take care to provide for the case that we get a NULL |
* pointer passed in. |
*/ |
struct device * get_device(struct device * dev) |
{ |
return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; |
} |
/** |
* put_device - decrement reference count. |
* @dev: device in question. |
*/ |
void put_device(struct device * dev) |
{ |
kobject_put(&dev->kobj); |
} |
/** |
* device_del - delete device from system. |
* @dev: device. |
* |
* This is the first part of the device unregistration |
* sequence. This removes the device from the lists we control |
* from here, has it removed from the other driver model |
* subsystems it was added to in device_add(), and removes it |
* from the kobject hierarchy. |
* |
* NOTE: this should be called manually _iff_ device_add() was |
* also called manually. |
*/ |
void device_del(struct device * dev) |
{ |
struct device * parent = dev->parent; |
//down_write(&devices_subsys.rwsem); |
if (parent) |
list_del_init(&dev->node); |
//up_write(&devices_subsys.rwsem); |
/* Notify the platform of the removal, in case they |
* need to do anything... |
*/ |
if (platform_notify_remove) |
platform_notify_remove(dev); |
bus_remove_device(dev); |
//device_pm_remove(dev); |
kobject_del(&dev->kobj); |
if (parent) |
put_device(parent); |
} |
/** |
* device_unregister - unregister device from system. |
* @dev: device going away. |
* |
* We do this in two parts, like we do device_register(). First, |
* we remove it from all the subsystems with device_del(), then |
* we decrement the reference count via put_device(). If that |
* is the final reference count, the device will be cleaned up |
* via device_release() above. Otherwise, the structure will |
* stick around until the final reference to the device is dropped. |
*/ |
void device_unregister(struct device * dev) |
{ |
pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); |
device_del(dev); |
put_device(dev); |
} |
/** |
* device_unregister_wait - Unregister device and wait for it to be freed. |
* @dev: Device to unregister. |
* |
* For the cases where the caller needs to wait for all references to |
* be dropped from the device before continuing (e.g. modules with |
* statically allocated devices), this function uses a completion struct |
* to wait, along with a matching complete() in device_release() above. |
*/ |
void device_unregister_wait(struct device * dev) |
{ |
struct completion c; |
init_completion(&c); |
dev->complete = &c; |
device_unregister(dev); |
//wait_for_completion(&c); |
} |
/** |
* device_for_each_child - device child iterator. |
* @dev: parent struct device. |
* @data: data for the callback. |
* @fn: function to be called for each device. |
* |
* Iterate over @dev's child devices, and call @fn for each, |
* passing it @data. |
* |
* We check the return of @fn each time. If it returns anything |
* other than 0, we break out and return that value. |
*/ |
int device_for_each_child(struct device * dev, void * data, |
int (*fn)(struct device *, void *)) |
{ |
struct device * child; |
int error = 0; |
//down_read(&devices_subsys.rwsem); |
list_for_each_entry(child,&dev->children,node) { |
if((error = fn(child,data))) |
break; |
} |
//up_read(&devices_subsys.rwsem); |
return error; |
} |
int __init devices_init(void) |
{ |
return subsystem_register(&devices_subsys); |
} |
EXPORT_SYMBOL(device_for_each_child); |
EXPORT_SYMBOL(device_initialize); |
EXPORT_SYMBOL(device_add); |
EXPORT_SYMBOL(device_register); |
EXPORT_SYMBOL(device_del); |
EXPORT_SYMBOL(device_unregister); |
EXPORT_SYMBOL(device_unregister_wait); |
EXPORT_SYMBOL(get_device); |
EXPORT_SYMBOL(put_device); |
EXPORT_SYMBOL(device_create_file); |
EXPORT_SYMBOL(device_remove_file); |
/shark/trunk/drivers/linuxc26/bus.c |
---|
0,0 → 1,610 |
/* |
* bus.c - bus driver management |
* |
* Copyright (c) 2002-3 Patrick Mochel |
* Copyright (c) 2002-3 Open Source Development Labs |
* |
* This file is released under the GPLv2 |
* |
*/ |
#undef DEBUG |
#include <linuxcomp.h> |
#include <linux/device.h> |
#include <linux/module.h> |
#include <linux/errno.h> |
#include <linux/init.h> |
#include <linux/string.h> |
#include "base.h" |
#define to_dev(node) container_of(node,struct device,bus_list) |
#define to_drv(node) container_of(node,struct device_driver,kobj.entry) |
#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr) |
#define to_bus(obj) container_of(obj,struct bus_type,subsys.kset.kobj) |
/* |
* sysfs bindings for drivers |
*/ |
#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr) |
#define to_driver(obj) container_of(obj, struct device_driver, kobj) |
static ssize_t |
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) |
{ |
struct driver_attribute * drv_attr = to_drv_attr(attr); |
struct device_driver * drv = to_driver(kobj); |
ssize_t ret = 0; |
if (drv_attr->show) |
ret = drv_attr->show(drv,buf); |
return ret; |
} |
static ssize_t |
drv_attr_store(struct kobject * kobj, struct attribute * attr, |
const char * buf, size_t count) |
{ |
struct driver_attribute * drv_attr = to_drv_attr(attr); |
struct device_driver * drv = to_driver(kobj); |
ssize_t ret = 0; |
if (drv_attr->store) |
ret = drv_attr->store(drv,buf,count); |
return ret; |
} |
static struct sysfs_ops driver_sysfs_ops = { |
.show = drv_attr_show, |
.store = drv_attr_store, |
}; |
static void driver_release(struct kobject * kobj) |
{ |
struct device_driver * drv = to_driver(kobj); |
//up(&drv->unload_sem); |
} |
static struct kobj_type ktype_driver = { |
.sysfs_ops = &driver_sysfs_ops, |
.release = driver_release, |
}; |
/* |
* sysfs bindings for buses |
*/ |
static ssize_t |
bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) |
{ |
struct bus_attribute * bus_attr = to_bus_attr(attr); |
struct bus_type * bus = to_bus(kobj); |
ssize_t ret = 0; |
if (bus_attr->show) |
ret = bus_attr->show(bus,buf); |
return ret; |
} |
static ssize_t |
bus_attr_store(struct kobject * kobj, struct attribute * attr, |
const char * buf, size_t count) |
{ |
struct bus_attribute * bus_attr = to_bus_attr(attr); |
struct bus_type * bus = to_bus(kobj); |
ssize_t ret = 0; |
if (bus_attr->store) |
ret = bus_attr->store(bus,buf,count); |
return ret; |
} |
static struct sysfs_ops bus_sysfs_ops = { |
.show = bus_attr_show, |
.store = bus_attr_store, |
}; |
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) |
{ |
int error; |
if (get_bus(bus)) { |
error = 0;//sysfs_create_file(&bus->subsys.kset.kobj,&attr->attr); |
put_bus(bus); |
} else |
error = -EINVAL; |
return error; |
} |
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) |
{ |
if (get_bus(bus)) { |
//sysfs_remove_file(&bus->subsys.kset.kobj,&attr->attr); |
put_bus(bus); |
} |
} |
static struct kobj_type ktype_bus = { |
.sysfs_ops = &bus_sysfs_ops, |
}; |
decl_subsys(bus,&ktype_bus,NULL); |
/** |
* bus_for_each_dev - device iterator. |
* @bus: bus type. |
* @start: device to start iterating from. |
* @data: data for the callback. |
* @fn: function to be called for each device. |
* |
* Iterate over @bus's list of devices, and call @fn for each, |
* passing it @data. If @start is not NULL, we use that device to |
* begin iterating from. |
* |
* We check the return of @fn each time. If it returns anything |
* other than 0, we break out and return that value. |
* |
* NOTE: The device that returns a non-zero value is not retained |
* in any way, nor is its refcount incremented. If the caller needs |
* to retain this data, it should do, and increment the reference |
* count in the supplied callback. |
*/ |
int bus_for_each_dev(struct bus_type * bus, struct device * start, |
void * data, int (*fn)(struct device *, void *)) |
{ |
struct list_head * head, * entry; |
int error = 0; |
if (!(bus = get_bus(bus))) |
return -EINVAL; |
head = start ? &start->bus_list : &bus->devices.list; |
//down_read(&bus->subsys.rwsem); |
list_for_each(entry,head) { |
struct device * dev = get_device(to_dev(entry)); |
error = fn(dev,data); |
put_device(dev); |
if (error) |
break; |
} |
//up_read(&bus->subsys.rwsem); |
put_bus(bus); |
return error; |
} |
/** |
* bus_for_each_drv - driver iterator |
* @bus: bus we're dealing with. |
* @start: driver to start iterating on. |
* @data: data to pass to the callback. |
* @fn: function to call for each driver. |
* |
* This is nearly identical to the device iterator above. |
* We iterate over each driver that belongs to @bus, and call |
* @fn for each. If @fn returns anything but 0, we break out |
* and return it. If @start is not NULL, we use it as the head |
* of the list. |
* |
* NOTE: we don't return the driver that returns a non-zero |
* value, nor do we leave the reference count incremented for that |
* driver. If the caller needs to know that info, it must set it |
* in the callback. It must also be sure to increment the refcount |
* so it doesn't disappear before returning to the caller. |
*/ |
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, |
void * data, int (*fn)(struct device_driver *, void *)) |
{ |
struct list_head * head, * entry; |
int error = 0; |
if(!(bus = get_bus(bus))) |
return -EINVAL; |
head = start ? &start->kobj.entry : &bus->drivers.list; |
//down_read(&bus->subsys.rwsem); |
list_for_each(entry,head) { |
struct device_driver * drv = get_driver(to_drv(entry)); |
error = fn(drv,data); |
put_driver(drv); |
if(error) |
break; |
} |
//up_read(&bus->subsys.rwsem); |
put_bus(bus); |
return error; |
} |
/** |
* device_bind_driver - bind a driver to one device. |
* @dev: device. |
* |
* Allow manual attachment of a driver to a deivce. |
* Caller must have already set @dev->driver. |
* |
* Note that this does not modify the bus reference count |
* nor take the bus's rwsem. Please verify those are accounted |
* for before calling this. (It is ok to call with no other effort |
* from a driver's probe() method.) |
*/ |
void device_bind_driver(struct device * dev) |
{ |
pr_debug("bound device '%s' to driver '%s'\n", |
dev->bus_id,dev->driver->name); |
list_add_tail(&dev->driver_list,&dev->driver->devices); |
//sysfs_create_link(&dev->driver->kobj,&dev->kobj,kobject_name(&dev->kobj)); |
} |
/** |
* bus_match - check compatibility between device & driver. |
* @dev: device. |
* @drv: driver. |
* |
* First, we call the bus's match function, which should compare |
* the device IDs the driver supports with the device IDs of the |
* device. Note we don't do this ourselves because we don't know |
* the format of the ID structures, nor what is to be considered |
* a match and what is not. |
* |
* If we find a match, we call @drv->probe(@dev) if it exists, and |
* call attach() above. |
*/ |
static int bus_match(struct device * dev, struct device_driver * drv) |
{ |
int error = -ENODEV; |
if (dev->bus->match(dev,drv)) { |
dev->driver = drv; |
if (drv->probe) { |
if ((error = drv->probe(dev))) { |
dev->driver = NULL; |
return error; |
} |
} |
device_bind_driver(dev); |
error = 0; |
} |
return error; |
} |
/** |
* device_attach - try to attach device to a driver. |
* @dev: device. |
* |
* Walk the list of drivers that the bus has and call bus_match() |
* for each pair. If a compatible pair is found, break out and return. |
*/ |
static int device_attach(struct device * dev) |
{ |
struct bus_type * bus = dev->bus; |
struct list_head * entry; |
int error; |
if (dev->driver) { |
device_bind_driver(dev); |
return 1; |
} |
if (bus->match) { |
list_for_each(entry,&bus->drivers.list) { |
struct device_driver * drv = to_drv(entry); |
error = bus_match(dev,drv); |
if (!error ) |
/* success, driver matched */ |
return 1; |
if (error != -ENODEV) |
/* driver matched but the probe failed */ |
printk(KERN_WARNING |
"%s: probe of %s failed with error %d\n", |
drv->name, dev->bus_id, error); |
} |
} |
return 0; |
} |
/** |
* driver_attach - try to bind driver to devices. |
* @drv: driver. |
* |
* Walk the list of devices that the bus has on it and try to match |
* the driver with each one. |
* If bus_match() returns 0 and the @dev->driver is set, we've found |
* a compatible pair. |
* |
* Note that we ignore the -ENODEV error from bus_match(), since it's |
* perfectly valid for a driver not to bind to any devices. |
*/ |
void driver_attach(struct device_driver * drv) |
{ |
struct bus_type * bus = drv->bus; |
struct list_head * entry; |
int error; |
if (!bus->match) |
return; |
list_for_each(entry,&bus->devices.list) { |
struct device * dev = container_of(entry,struct device,bus_list); |
if (!dev->driver) { |
error = bus_match(dev,drv); |
if (error && (error != -ENODEV)) |
/* driver matched but the probe failed */ |
printk(KERN_WARNING |
"%s: probe of %s failed with error %d\n", |
drv->name, dev->bus_id, error); |
} |
} |
} |
/** |
* device_release_driver - manually detach device from driver. |
* @dev: device. |
* |
* Manually detach device from driver. |
* Note that this is called without incrementing the bus |
* reference count nor taking the bus's rwsem. Be sure that |
* those are accounted for before calling this function. |
*/ |
void device_release_driver(struct device * dev) |
{ |
struct device_driver * drv = dev->driver; |
if (drv) { |
//sysfs_remove_link(&drv->kobj,kobject_name(&dev->kobj)); |
list_del_init(&dev->driver_list); |
//device_detach_shutdown(dev); |
if (drv->remove) |
drv->remove(dev); |
dev->driver = NULL; |
} |
} |
/** |
* driver_detach - detach driver from all devices it controls. |
* @drv: driver. |
*/ |
static void driver_detach(struct device_driver * drv) |
{ |
struct list_head * entry, * next; |
list_for_each_safe(entry,next,&drv->devices) { |
struct device * dev = container_of(entry,struct device,driver_list); |
device_release_driver(dev); |
} |
} |
/** |
* bus_add_device - add device to bus |
* @dev: device being added |
* |
* - Add the device to its bus's list of devices. |
* - Try to attach to driver. |
* - Create link to device's physical location. |
*/ |
int bus_add_device(struct device * dev) |
{ |
struct bus_type * bus = get_bus(dev->bus); |
int error = 0; |
if (bus) { |
//down_write(&dev->bus->subsys.rwsem); |
pr_debug("bus %s: add device %s\n",bus->name,dev->bus_id); |
list_add_tail(&dev->bus_list,&dev->bus->devices.list); |
device_attach(dev); |
//up_write(&dev->bus->subsys.rwsem); |
//sysfs_create_link(&bus->devices.kobj,&dev->kobj,dev->bus_id); |
} |
return error; |
} |
/** |
* bus_remove_device - remove device from bus |
* @dev: device to be removed |
* |
* - Remove symlink from bus's directory. |
* - Delete device from bus's list. |
* - Detach from its driver. |
* - Drop reference taken in bus_add_device(). |
*/ |
void bus_remove_device(struct device * dev) |
{ |
if (dev->bus) { |
//sysfs_remove_link(&dev->bus->devices.kobj,dev->bus_id); |
//down_write(&dev->bus->subsys.rwsem); |
pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id); |
device_release_driver(dev); |
list_del_init(&dev->bus_list); |
//up_write(&dev->bus->subsys.rwsem); |
put_bus(dev->bus); |
} |
} |
/** |
* bus_add_driver - Add a driver to the bus. |
* @drv: driver. |
* |
*/ |
int bus_add_driver(struct device_driver * drv) |
{ |
struct bus_type * bus = get_bus(drv->bus); |
int error = 0; |
if (bus) { |
pr_debug("bus %s: add driver %s\n",bus->name,drv->name); |
kobject_set_name(&drv->kobj,drv->name); |
drv->kobj.kset = &bus->drivers; |
if ((error = kobject_register(&drv->kobj))) { |
put_bus(bus); |
return error; |
} |
//down_write(&bus->subsys.rwsem); |
driver_attach(drv); |
//up_write(&bus->subsys.rwsem); |
} |
return error; |
} |
/** |
* bus_remove_driver - delete driver from bus's knowledge. |
* @drv: driver. |
* |
* Detach the driver from the devices it controls, and remove |
* it from its bus's list of drivers. Finally, we drop the reference |
* to the bus we took in bus_add_driver(). |
*/ |
void bus_remove_driver(struct device_driver * drv) |
{ |
if (drv->bus) { |
//down_write(&drv->bus->subsys.rwsem); |
pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name); |
driver_detach(drv); |
//up_write(&drv->bus->subsys.rwsem); |
kobject_unregister(&drv->kobj); |
put_bus(drv->bus); |
} |
} |
/* Helper for bus_rescan_devices's iter */ |
static int bus_rescan_devices_helper(struct device *dev, void *data) |
{ |
int *count = data; |
if (!dev->driver && device_attach(dev)) |
(*count)++; |
return 0; |
} |
/** |
* bus_rescan_devices - rescan devices on the bus for possible drivers |
* @bus: the bus to scan. |
* |
* This function will look for devices on the bus with no driver |
* attached and rescan it against existing drivers to see if it |
* matches any. Calls device_attach(). Returns the number of devices |
* that were sucessfully bound to a driver. |
*/ |
int bus_rescan_devices(struct bus_type * bus) |
{ |
int count = 0; |
bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper); |
return count; |
} |
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. |
* |
* Call kset_find_obj() to iterate over list of buses to |
* find a bus by name. Return bus if found. |
*/ |
struct bus_type * find_bus(char * name) |
{ |
struct kobject * k = kset_find_obj(&bus_subsys.kset,name); |
return k ? to_bus(k) : NULL; |
} |
/** |
* bus_register - register a bus with the system. |
* @bus: bus. |
* |
* Once we have that, we registered the bus with the kobject |
* infrastructure, then register the children subsystems it has: |
* the devices and drivers that belong to the bus. |
*/ |
int bus_register(struct bus_type * bus) |
{ |
kobject_set_name(&bus->subsys.kset.kobj,bus->name); |
subsys_set_kset(bus,bus_subsys); |
subsystem_register(&bus->subsys); |
kobject_set_name(&bus->devices.kobj, "devices"); |
bus->devices.subsys = &bus->subsys; |
kset_register(&bus->devices); |
kobject_set_name(&bus->drivers.kobj, "drivers"); |
bus->drivers.subsys = &bus->subsys; |
bus->drivers.ktype = &ktype_driver; |
kset_register(&bus->drivers); |
pr_debug("bus type '%s' registered\n",bus->name); |
return 0; |
} |
/** |
* bus_unregister - remove a bus from the system |
* @bus: bus. |
* |
* Unregister the child subsystems and the bus itself. |
* Finally, we call put_bus() to release the refcount |
*/ |
void bus_unregister(struct bus_type * bus) |
{ |
pr_debug("bus %s: unregistering\n",bus->name); |
kset_unregister(&bus->drivers); |
kset_unregister(&bus->devices); |
subsystem_unregister(&bus->subsys); |
} |
int __init buses_init(void) |
{ |
return subsystem_register(&bus_subsys); |
} |
EXPORT_SYMBOL(bus_for_each_dev); |
EXPORT_SYMBOL(bus_for_each_drv); |
EXPORT_SYMBOL(device_bind_driver); |
EXPORT_SYMBOL(device_release_driver); |
EXPORT_SYMBOL(bus_add_device); |
EXPORT_SYMBOL(bus_remove_device); |
EXPORT_SYMBOL(bus_register); |
EXPORT_SYMBOL(bus_unregister); |
EXPORT_SYMBOL(bus_rescan_devices); |
EXPORT_SYMBOL(get_bus); |
EXPORT_SYMBOL(put_bus); |
EXPORT_SYMBOL(find_bus); |
EXPORT_SYMBOL(bus_create_file); |
EXPORT_SYMBOL(bus_remove_file); |
/shark/trunk/drivers/linuxc26/driver.c |
---|
0,0 → 1,123 |
/* |
* driver.c - centralized device driver management |
* |
* Copyright (c) 2002-3 Patrick Mochel |
* Copyright (c) 2002-3 Open Source Development Labs |
* |
* This file is released under the GPLv2 |
* |
*/ |
#undef DEBUG |
#include <linuxcomp.h> |
#include <linux/device.h> |
#include <linux/module.h> |
#include <linux/errno.h> |
#include <linux/string.h> |
#include "base.h" |
#define to_dev(node) container_of(node,struct device,driver_list) |
#define to_drv(obj) container_of(obj,struct device_driver,kobj) |
/** |
* driver_create_file - create sysfs file for driver. |
* @drv: driver. |
* @attr: driver attribute descriptor. |
*/ |
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) |
{ |
int error; |
if (get_driver(drv)) { |
error = 0;//sysfs_create_file(&drv->kobj,&attr->attr); |
put_driver(drv); |
} else |
error = -EINVAL; |
return error; |
} |
/** |
* driver_remove_file - remove sysfs file for driver. |
* @drv: driver. |
* @attr: driver attribute descriptor. |
*/ |
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) |
{ |
if (get_driver(drv)) { |
//sysfs_remove_file(&drv->kobj,&attr->attr); |
put_driver(drv); |
} |
} |
/** |
* get_driver - increment driver reference count. |
* @drv: driver. |
*/ |
struct device_driver * get_driver(struct device_driver * drv) |
{ |
return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; |
} |
/** |
* put_driver - decrement driver's refcount. |
* @drv: driver. |
*/ |
void put_driver(struct device_driver * drv) |
{ |
kobject_put(&drv->kobj); |
} |
/** |
* driver_register - register driver with bus |
* @drv: driver to register |
* |
* We pass off most of the work to the bus_add_driver() call, |
* since most of the things we have to do deal with the bus |
* structures. |
* |
* The one interesting aspect is that we initialize @drv->unload_sem |
* to a locked state here. It will be unlocked when the driver |
* reference count reaches 0. |
*/ |
int driver_register(struct device_driver * drv) |
{ |
INIT_LIST_HEAD(&drv->devices); |
//init_MUTEX_LOCKED(&drv->unload_sem); |
return bus_add_driver(drv); |
} |
/** |
* driver_unregister - remove driver from system. |
* @drv: driver. |
* |
* Again, we pass off most of the work to the bus-level call. |
* |
* Though, once that is done, we attempt to take @drv->unload_sem. |
* This will block until the driver refcount reaches 0, and it is |
* released. Only modular drivers will call this function, and we |
* have to guarantee that it won't complete, letting the driver |
* unload until all references are gone. |
*/ |
void driver_unregister(struct device_driver * drv) |
{ |
bus_remove_driver(drv); |
//down(&drv->unload_sem); |
//up(&drv->unload_sem); |
} |
EXPORT_SYMBOL(driver_register); |
EXPORT_SYMBOL(driver_unregister); |
EXPORT_SYMBOL(get_driver); |
EXPORT_SYMBOL(put_driver); |
EXPORT_SYMBOL(driver_create_file); |
EXPORT_SYMBOL(driver_remove_file); |
/shark/trunk/drivers/linuxc26/vsprintf.c |
---|
0,0 → 1,745 |
/* |
* linux/lib/vsprintf.c |
* |
* Copyright (C) 1991, 1992 Linus Torvalds |
*/ |
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ |
/* |
* Wirzenius wrote this portably, Torvalds fucked it up :-) |
*/ |
/* |
* Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> |
* - changed to provide snprintf and vsnprintf functions |
*/ |
#include <linuxcomp.h> |
#include <stdarg.h> |
#include <linux/module.h> |
#include <linux/types.h> |
#include <linux/string.h> |
#include <linux/ctype.h> |
#include <linux/kernel.h> |
#include <asm/div64.h> |
/** |
* simple_strtoul - convert a string to an unsigned long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) |
{ |
unsigned long result = 0,value; |
if (!base) { |
base = 10; |
if (*cp == '0') { |
base = 8; |
cp++; |
if ((*cp == 'x') && isxdigit(cp[1])) { |
cp++; |
base = 16; |
} |
} |
} |
while (isxdigit(*cp) && |
(value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { |
result = result*base + value; |
cp++; |
} |
if (endp) |
*endp = (char *)cp; |
return result; |
} |
EXPORT_SYMBOL(simple_strtoul); |
/** |
* simple_strtol - convert a string to a signed long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
long simple_strtol(const char *cp,char **endp,unsigned int base) |
{ |
if(*cp=='-') |
return -simple_strtoul(cp+1,endp,base); |
return simple_strtoul(cp,endp,base); |
} |
EXPORT_SYMBOL(simple_strtol); |
/** |
* simple_strtoull - convert a string to an unsigned long long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) |
{ |
unsigned long long result = 0,value; |
if (!base) { |
base = 10; |
if (*cp == '0') { |
base = 8; |
cp++; |
if ((*cp == 'x') && isxdigit(cp[1])) { |
cp++; |
base = 16; |
} |
} |
} |
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) |
? toupper(*cp) : *cp)-'A'+10) < base) { |
result = result*base + value; |
cp++; |
} |
if (endp) |
*endp = (char *)cp; |
return result; |
} |
EXPORT_SYMBOL(simple_strtoull); |
/** |
* simple_strtoll - convert a string to a signed long long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
long long simple_strtoll(const char *cp,char **endp,unsigned int base) |
{ |
if(*cp=='-') |
return -simple_strtoull(cp+1,endp,base); |
return simple_strtoull(cp,endp,base); |
} |
static int skip_atoi(const char **s) |
{ |
int i=0; |
while (isdigit(**s)) |
i = i*10 + *((*s)++) - '0'; |
return i; |
} |
#define ZEROPAD 1 /* pad with zero */ |
#define SIGN 2 /* unsigned/signed long */ |
#define PLUS 4 /* show plus */ |
#define SPACE 8 /* space if plus */ |
#define LEFT 16 /* left justified */ |
#define SPECIAL 32 /* 0x */ |
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ |
static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type) |
{ |
char c,sign,tmp[66]; |
const char *digits; |
static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
int i; |
digits = (type & LARGE) ? large_digits : small_digits; |
if (type & LEFT) |
type &= ~ZEROPAD; |
if (base < 2 || base > 36) |
return 0; |
c = (type & ZEROPAD) ? '0' : ' '; |
sign = 0; |
if (type & SIGN) { |
if ((signed long long) num < 0) { |
sign = '-'; |
num = - (signed long long) num; |
size--; |
} else if (type & PLUS) { |
sign = '+'; |
size--; |
} else if (type & SPACE) { |
sign = ' '; |
size--; |
} |
} |
if (type & SPECIAL) { |
if (base == 16) |
size -= 2; |
else if (base == 8) |
size--; |
} |
i = 0; |
if (num == 0) |
tmp[i++]='0'; |
else while (num != 0) |
tmp[i++] = digits[do_div(num,base)]; |
if (i > precision) |
precision = i; |
size -= precision; |
if (!(type&(ZEROPAD+LEFT))) { |
while(size-->0) { |
if (buf <= end) |
*buf = ' '; |
++buf; |
} |
} |
if (sign) { |
if (buf <= end) |
*buf = sign; |
++buf; |
} |
if (type & SPECIAL) { |
if (base==8) { |
if (buf <= end) |
*buf = '0'; |
++buf; |
} else if (base==16) { |
if (buf <= end) |
*buf = '0'; |
++buf; |
if (buf <= end) |
*buf = digits[33]; |
++buf; |
} |
} |
if (!(type & LEFT)) { |
while (size-- > 0) { |
if (buf <= end) |
*buf = c; |
++buf; |
} |
} |
while (i < precision--) { |
if (buf <= end) |
*buf = '0'; |
++buf; |
} |
while (i-- > 0) { |
if (buf <= end) |
*buf = tmp[i]; |
++buf; |
} |
while (size-- > 0) { |
if (buf <= end) |
*buf = ' '; |
++buf; |
} |
return buf; |
} |
/** |
* vsnprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @size: The size of the buffer, including the trailing null space |
* @fmt: The format string to use |
* @args: Arguments for the format string |
* |
* Call this function if you are already dealing with a va_list. |
* You probably want snprintf instead. |
*/ |
int vsnprintf26(char *buf, size_t size, const char *fmt, va_list args) |
{ |
int len; |
unsigned long long num; |
int i, base; |
char *str, *end, c; |
const char *s; |
int flags; /* flags to number() */ |
int field_width; /* width of output field */ |
int precision; /* min. # of digits for integers; max |
number of chars for from string */ |
int qualifier; /* 'h', 'l', or 'L' for integer fields */ |
/* 'z' support added 23/7/1999 S.H. */ |
/* 'z' changed to 'Z' --davidm 1/25/99 */ |
str = buf; |
end = buf + size - 1; |
if (end < buf - 1) { |
end = ((void *) -1); |
size = end - buf + 1; |
} |
for (; *fmt ; ++fmt) { |
if (*fmt != '%') { |
if (str <= end) |
*str = *fmt; |
++str; |
continue; |
} |
/* process flags */ |
flags = 0; |
repeat: |
++fmt; /* this also skips first '%' */ |
switch (*fmt) { |
case '-': flags |= LEFT; goto repeat; |
case '+': flags |= PLUS; goto repeat; |
case ' ': flags |= SPACE; goto repeat; |
case '#': flags |= SPECIAL; goto repeat; |
case '0': flags |= ZEROPAD; goto repeat; |
} |
/* get field width */ |
field_width = -1; |
if (isdigit(*fmt)) |
field_width = skip_atoi(&fmt); |
else if (*fmt == '*') { |
++fmt; |
/* it's the next argument */ |
field_width = va_arg(args, int); |
if (field_width < 0) { |
field_width = -field_width; |
flags |= LEFT; |
} |
} |
/* get the precision */ |
precision = -1; |
if (*fmt == '.') { |
++fmt; |
if (isdigit(*fmt)) |
precision = skip_atoi(&fmt); |
else if (*fmt == '*') { |
++fmt; |
/* it's the next argument */ |
precision = va_arg(args, int); |
} |
if (precision < 0) |
precision = 0; |
} |
/* get the conversion qualifier */ |
qualifier = -1; |
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
*fmt =='Z' || *fmt == 'z') { |
qualifier = *fmt; |
++fmt; |
if (qualifier == 'l' && *fmt == 'l') { |
qualifier = 'L'; |
++fmt; |
} |
} |
/* default base */ |
base = 10; |
switch (*fmt) { |
case 'c': |
if (!(flags & LEFT)) { |
while (--field_width > 0) { |
if (str <= end) |
*str = ' '; |
++str; |
} |
} |
c = (unsigned char) va_arg(args, int); |
if (str <= end) |
*str = c; |
++str; |
while (--field_width > 0) { |
if (str <= end) |
*str = ' '; |
++str; |
} |
continue; |
case 's': |
s = va_arg(args, char *); |
if ((unsigned long)s < PAGE_SIZE) |
s = "<NULL>"; |
len = strnlen(s, precision); |
if (!(flags & LEFT)) { |
while (len < field_width--) { |
if (str <= end) |
*str = ' '; |
++str; |
} |
} |
for (i = 0; i < len; ++i) { |
if (str <= end) |
*str = *s; |
++str; ++s; |
} |
while (len < field_width--) { |
if (str <= end) |
*str = ' '; |
++str; |
} |
continue; |
case 'p': |
if (field_width == -1) { |
field_width = 2*sizeof(void *); |
flags |= ZEROPAD; |
} |
str = number(str, end, |
(unsigned long) va_arg(args, void *), |
16, field_width, precision, flags); |
continue; |
case 'n': |
/* FIXME: |
* What does C99 say about the overflow case here? */ |
if (qualifier == 'l') { |
long * ip = va_arg(args, long *); |
*ip = (str - buf); |
} else if (qualifier == 'Z' || qualifier == 'z') { |
size_t * ip = va_arg(args, size_t *); |
*ip = (str - buf); |
} else { |
int * ip = va_arg(args, int *); |
*ip = (str - buf); |
} |
continue; |
case '%': |
if (str <= end) |
*str = '%'; |
++str; |
continue; |
/* integer number formats - set up the flags and "break" */ |
case 'o': |
base = 8; |
break; |
case 'X': |
flags |= LARGE; |
case 'x': |
base = 16; |
break; |
case 'd': |
case 'i': |
flags |= SIGN; |
case 'u': |
break; |
default: |
if (str <= end) |
*str = '%'; |
++str; |
if (*fmt) { |
if (str <= end) |
*str = *fmt; |
++str; |
} else { |
--fmt; |
} |
continue; |
} |
if (qualifier == 'L') |
num = va_arg(args, long long); |
else if (qualifier == 'l') { |
num = va_arg(args, unsigned long); |
if (flags & SIGN) |
num = (signed long) num; |
} else if (qualifier == 'Z' || qualifier == 'z') { |
num = va_arg(args, size_t); |
} else if (qualifier == 'h') { |
num = (unsigned short) va_arg(args, int); |
if (flags & SIGN) |
num = (signed short) num; |
} else { |
num = va_arg(args, unsigned int); |
if (flags & SIGN) |
num = (signed int) num; |
} |
str = number(str, end, num, base, |
field_width, precision, flags); |
} |
if (str <= end) |
*str = '\0'; |
else if (size > 0) |
/* don't write out a null byte if the buf size is zero */ |
*end = '\0'; |
/* the trailing null byte doesn't count towards the total |
* ++str; |
*/ |
return str-buf; |
} |
EXPORT_SYMBOL(vsnprintf26); |
/** |
* snprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @size: The size of the buffer, including the trailing null space |
* @fmt: The format string to use |
* @...: Arguments for the format string |
*/ |
int snprintf26(char * buf, size_t size, const char *fmt, ...) |
{ |
va_list args; |
int i; |
va_start(args, fmt); |
i=vsnprintf26(buf,size,fmt,args); |
va_end(args); |
return i; |
} |
EXPORT_SYMBOL(snprintf26); |
/** |
* vsprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @fmt: The format string to use |
* @args: Arguments for the format string |
* |
* Call this function if you are already dealing with a va_list. |
* You probably want sprintf instead. |
*/ |
int vsprintf26(char *buf, const char *fmt, va_list args) |
{ |
return vsnprintf26(buf, 0xFFFFFFFFUL, fmt, args); |
} |
EXPORT_SYMBOL(vsprintf26); |
/** |
* sprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @fmt: The format string to use |
* @...: Arguments for the format string |
*/ |
int sprintf26(char * buf, const char *fmt, ...) |
{ |
va_list args; |
int i; |
va_start(args, fmt); |
i=vsprintf26(buf,fmt,args); |
va_end(args); |
return i; |
} |
EXPORT_SYMBOL(sprintf26); |
/** |
* vsscanf - Unformat a buffer into a list of arguments |
* @buf: input buffer |
* @fmt: format of buffer |
* @args: arguments |
*/ |
int vsscanf26(const char * buf, const char * fmt, va_list args) |
{ |
const char *str = buf; |
char *next; |
char digit; |
int num = 0; |
int qualifier; |
int base; |
int field_width; |
int is_sign = 0; |
while(*fmt && *str) { |
/* skip any white space in format */ |
/* white space in format matchs any amount of |
* white space, including none, in the input. |
*/ |
if (isspace(*fmt)) { |
while (isspace(*fmt)) |
++fmt; |
while (isspace(*str)) |
++str; |
} |
/* anything that is not a conversion must match exactly */ |
if (*fmt != '%' && *fmt) { |
if (*fmt++ != *str++) |
break; |
continue; |
} |
if (!*fmt) |
break; |
++fmt; |
/* skip this conversion. |
* advance both strings to next white space |
*/ |
if (*fmt == '*') { |
while (!isspace(*fmt) && *fmt) |
fmt++; |
while (!isspace(*str) && *str) |
str++; |
continue; |
} |
/* get field width */ |
field_width = -1; |
if (isdigit(*fmt)) |
field_width = skip_atoi(&fmt); |
/* get conversion qualifier */ |
qualifier = -1; |
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
*fmt == 'Z' || *fmt == 'z') { |
qualifier = *fmt; |
fmt++; |
} |
base = 10; |
is_sign = 0; |
if (!*fmt || !*str) |
break; |
switch(*fmt++) { |
case 'c': |
{ |
char *s = (char *) va_arg(args,char*); |
if (field_width == -1) |
field_width = 1; |
do { |
*s++ = *str++; |
} while(field_width-- > 0 && *str); |
num++; |
} |
continue; |
case 's': |
{ |
char *s = (char *) va_arg(args, char *); |
if(field_width == -1) |
field_width = ((int)(~0U>>1)); |
/* first, skip leading white space in buffer */ |
while (isspace(*str)) |
str++; |
/* now copy until next white space */ |
while (*str && !isspace(*str) && field_width--) { |
*s++ = *str++; |
} |
*s = '\0'; |
num++; |
} |
continue; |
case 'n': |
/* return number of characters read so far */ |
{ |
int *i = (int *)va_arg(args,int*); |
*i = str - buf; |
} |
continue; |
case 'o': |
base = 8; |
break; |
case 'x': |
case 'X': |
base = 16; |
break; |
case 'i': |
base = 0; |
case 'd': |
is_sign = 1; |
case 'u': |
break; |
case '%': |
/* looking for '%' in str */ |
if (*str++ != '%') |
return num; |
continue; |
default: |
/* invalid format; stop here */ |
return num; |
} |
/* have some sort of integer conversion. |
* first, skip white space in buffer. |
*/ |
while (isspace(*str)) |
str++; |
digit = *str; |
if (is_sign && digit == '-') |
digit = *(str + 1); |
if (!digit |
|| (base == 16 && !isxdigit(digit)) |
|| (base == 10 && !isdigit(digit)) |
|| (base == 8 && (!isdigit(digit) || digit > '7')) |
|| (base == 0 && !isdigit(digit))) |
break; |
switch(qualifier) { |
case 'h': |
if (is_sign) { |
short *s = (short *) va_arg(args,short *); |
*s = (short) simple_strtol(str,&next,base); |
} else { |
unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); |
*s = (unsigned short) simple_strtoul(str, &next, base); |
} |
break; |
case 'l': |
if (is_sign) { |
long *l = (long *) va_arg(args,long *); |
*l = simple_strtol(str,&next,base); |
} else { |
unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); |
*l = simple_strtoul(str,&next,base); |
} |
break; |
case 'L': |
if (is_sign) { |
long long *l = (long long*) va_arg(args,long long *); |
*l = simple_strtoll(str,&next,base); |
} else { |
unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); |
*l = simple_strtoull(str,&next,base); |
} |
break; |
case 'Z': |
case 'z': |
{ |
size_t *s = (size_t*) va_arg(args,size_t*); |
*s = (size_t) simple_strtoul(str,&next,base); |
} |
break; |
default: |
if (is_sign) { |
int *i = (int *) va_arg(args, int*); |
*i = (int) simple_strtol(str,&next,base); |
} else { |
unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); |
*i = (unsigned int) simple_strtoul(str,&next,base); |
} |
break; |
} |
num++; |
if (!next) |
break; |
str = next; |
} |
return num; |
} |
EXPORT_SYMBOL(vsscanf26); |
/** |
* sscanf - Unformat a buffer into a list of arguments |
* @buf: input buffer |
* @fmt: formatting of buffer |
* @...: resulting arguments |
*/ |
int sscanf26(const char * buf, const char * fmt, ...) |
{ |
va_list args; |
int i; |
va_start(args,fmt); |
i = vsscanf26(buf,fmt,args); |
va_end(args); |
return i; |
} |
EXPORT_SYMBOL(sscanf26); |
/shark/trunk/drivers/linuxc26/makefile |
---|
10,7 → 10,7 |
OBJS_PATH = $(BASE)/drivers/linuxc26 |
OBJS = linuxcomp.o kobject.o |
OBJS = bus.o linuxcomp.o core.o driver.o vsprintf.o interface.o kobject.o |
C_OPT += -I../linuxc26/include |