Hello, guys.
This is the third round of devparam patches. I think it's mostly
ready now. Changes from the last round include
1. vector is gone. BTW, I found out that implementing simple
vector-like thing inside devparam looked quite okay. I actually like
this way better now. :-)
2. KPARAM_NO_RANGE added. Unfortunately, macros still need to use
explicit 1, 0 as KPARAM_NO_RANGE is recognized as one argument rather
than two for macros. However, all those macros are right under the
definition of its ranged counterpart, so I don't think it will cause
any confusion.
3. DEFINE_DEVICE_PARAMSET_NS() added. This macros accepts one
additional argument - @Namespace. All parameters defined inside this
macro are assumed to have dot-appened @Namespace as their prefix.
Please read Documentation/devparam.txt for more details.
4. parameters subdirectory handling fixed and improved. Also,
parameters subdirectory isn't created when no devparam is used.
Regarding the last posting, Rusty, parameters subdirectory rename is
not really a user-visible breakage. It hasn't seen the light of day,
yet. I was talking about parameters subdirectory under the device's
sysfs node.
I'm also posting another set of patches for device manual attach.
This was what I was aiming for from the start. This basically dumps
device-driver association management to user-space and allows
user-space to specify the driver to attach to and what arguments to
use when attaching. I'll write more about it when I post the patches.
Whether manualattach is accepted or not, manualattach at least will
show that devparam implements per-device parameter which can be
specified dynamically while maintaining backward compatibility (No
user-visible breakage!).
All patches are against a freshly updated Linus bk tree and as
before, the updated document and dptest module source codes are at
http://home-tj.org/devparam/devparam.txt
http://home-tj.org/devparam/dptest.tar.gz
Also, all patches are available at the following URL.
http://home-tj.org/devparam/20041104/
I believe inssues are mostly resolved and devparam is ready to be
tested now. Please consider accepting it or tell me what you guys
dislike. I'll fix'em ASAP. :-)
Thanks.
--
tejun
dp_01_param_array_bug.patch
This is the 1st patch of 15 patches for devparam.
This patches fixes param_array_set() to not use arr->max as nump
argument of param_array. If arr->max is used as nump and the
configuration variable is exported writeable in the syfs, the size of
the array will be limited by the smallest number of elements
specified. One side effect is that as the actual number of elements
is not recorded anymore when nump is NULL, all elements should be
printed when referencing the corresponding sysfs node. I don't think
that will cause any problem.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 10:25:51.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 11:04:07.000000000 +0900
@@ -305,9 +305,10 @@ int param_array(const char *name,
int param_array_set(const char *val, struct kernel_param *kp)
{
struct kparam_array *arr = kp->arg;
+ unsigned int t;
return param_array(kp->name, val, 1, arr->max, arr->elem,
- arr->elemsize, arr->set, arr->num ?: &arr->max);
+ arr->elemsize, arr->set, arr->num ?: &t);
}
int param_array_get(char *buffer, struct kernel_param *kp)
dp_02_module_param_flag.patch
This is the 2nd patch of 15 patches for devparam.
This patch implements module_param_flag() and module_param_invflag().
They appear as boolean parameter to the outside, and bitwise OR the
specified flag to flags when the specified boolean value is 1 and 0
respectively.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 10:25:53.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 11:04:07.000000000 +0900
@@ -45,6 +45,12 @@ struct kparam_array
void *elem;
};
+/* Special one for flags */
+struct kparam_flag
+{
+ unsigned int *pflags, flag, inv;
+};
+
/* This is the fundamental function for registering boot/module
parameters. perm sets the visibility in driverfs: 000 means it's
not there, read bits mean it's readable, write bits mean it's
@@ -76,6 +82,20 @@ struct kparam_array
module_param_call(name, param_set_copystring, param_get_string, \
&__param_string_##name, perm)
+/* Bit flag */
+#define __module_param_flag(name, flags, flag, inv, perm) \
+ param_check_uint(name, &(flags)); \
+ static struct kparam_flag __param_flag_##name \
+ = { &(flags), flag, inv }; \
+ module_param_call(name, param_set_flag, param_get_flag, \
+ &__param_flag_##name, perm)
+
+#define module_param_flag(name, flags, flag, perm) \
+ __module_param_flag(name, flags, flag, 0, perm)
+
+#define module_param_invflag(name, flags, flag, perm) \
+ __module_param_flag(name, flags, flag, 1, perm)
+
/* Called on module insert or kernel boot */
extern int parse_args(const char *name,
char *args,
@@ -146,6 +166,9 @@ extern int param_array_get(char *buffer,
extern int param_set_copystring(const char *val, struct kernel_param *kp);
extern int param_get_string(char *buffer, struct kernel_param *kp);
+extern int param_set_flag(const char *val, struct kernel_param *kp);
+extern int param_get_flag(char *buffer, struct kernel_param *kp);
+
int param_array(const char *name,
const char *val,
unsigned int min, unsigned int max,
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 11:04:07.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 11:04:07.000000000 +0900
@@ -350,6 +350,32 @@ int param_get_string(char *buffer, struc
return strlcpy(buffer, kps->string, kps->maxlen);
}
+int param_set_flag(const char *val, struct kernel_param *kp)
+{
+ struct kparam_flag *kflag = kp->arg;
+ int boolval, ret;
+ struct kernel_param dummy = { .arg = &boolval };
+
+ ret = param_set_bool(val, &dummy);
+ if (ret == 0) {
+ if (boolval ^ kflag->inv)
+ *kflag->pflags |= kflag->flag;
+ else
+ *kflag->pflags &= ~kflag->flag;
+ }
+ return ret;
+}
+
+int param_get_flag(char *buffer, struct kernel_param *kp)
+{
+ struct kparam_flag *kflag = kp->arg;
+ int val;
+ struct kernel_param dummy = { .arg = &val };
+
+ val = (!!(*kflag->pflags & kflag->flag)) ^ kflag->inv;
+ return param_get_bool(buffer, &dummy);
+}
+
/* sysfs output in /sys/modules/XYZ/parameters/ */
extern struct kernel_param __start___param[], __stop___param[];
@@ -762,3 +788,5 @@ EXPORT_SYMBOL(param_array_set);
EXPORT_SYMBOL(param_array_get);
EXPORT_SYMBOL(param_set_copystring);
EXPORT_SYMBOL(param_get_string);
+EXPORT_SYMBOL(param_set_flag);
+EXPORT_SYMBOL(param_get_flag);
dp_03_module_param_ranged.patch
This is the 3rd patch of 15 patches for devparam.
This patches implements _ranged variants of module param macros. min
and max fields live inside struct kernel_param and struct kparam_string
is removed as its length field can be replaced with the new max field.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:48:37.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:48:38.000000000 +0900
@@ -26,12 +26,7 @@ struct kernel_param {
param_set_fn set;
param_get_fn get;
void *arg;
-};
-
-/* Special one for strings we want to copy into */
-struct kparam_string {
- unsigned int maxlen;
- char *string;
+ long min, max;
};
/* Special one for arrays */
@@ -51,36 +46,51 @@ struct kparam_flag
unsigned int *pflags, flag, inv;
};
+/* Range of min=1 and max=0 is special case which indicates unranged
+ kparams. The following KPARAM_NO_RANGE defined to clarify the 1, 0
+ case. Note that macros cannot use KPARAM_NO_RANGE, so they should
+ use 1, 0 directly. */
+#define KPARAM_NO_RANGE 1, 0
+
/* This is the fundamental function for registering boot/module
parameters. perm sets the visibility in driverfs: 000 means it's
not there, read bits mean it's readable, write bits mean it's
writable. */
-#define __module_param_call(prefix, name, set, get, arg, perm) \
+#define __module_param_call(prefix, name, set, get, arg, min, max, perm) \
static char __param_str_##name[] = prefix #name; \
static struct kernel_param const __param_##name \
__attribute_used__ \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
- = { __param_str_##name, perm, set, get, arg }
+ = { __param_str_##name, perm, set, get, arg, min, max }
-#define module_param_call(name, set, get, arg, perm) \
- __module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)
+#define module_param_call_ranged(name, set, get, arg, min, max, perm) \
+ __module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, \
+ min, max, perm)
+
+#define module_param_call(name, set, get, arg, perm) \
+ module_param_call_ranged(name, set, get, arg, 1, 0, perm)
/* Helper functions: type is byte, short, ushort, int, uint, long,
ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
param_set_XXX and param_check_XXX. */
-#define module_param_named(name, value, type, perm) \
- param_check_##type(name, &(value)); \
- module_param_call(name, param_set_##type, param_get_##type, &value, perm)
+#define module_param_named_ranged(name, value, type, min, max, perm) \
+ param_check_##type(name, &(value)); \
+ module_param_call_ranged(name, param_set_##type, param_get_##type, \
+ &value, min, max, perm)
+
+#define module_param_ranged(name, type, min, max, perm) \
+ module_param_named_ranged(name, name, type, min, max, perm) \
-#define module_param(name, type, perm) \
+#define module_param_named(name, value, type, perm) \
+ module_param_named_ranged(name, value, type, 1, 0, perm)
+
+#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
/* Actually copy string: maxlen param is usually sizeof(string). */
#define module_param_string(name, string, len, perm) \
- static struct kparam_string __param_string_##name \
- = { len, string }; \
- module_param_call(name, param_set_copystring, param_get_string, \
- &__param_string_##name, perm)
+ module_param_call_ranged(name, param_set_copystring, \
+ param_get_string, string, 0, len, perm)
/* Bit flag */
#define __module_param_flag(name, flags, flag, inv, perm) \
@@ -150,14 +160,20 @@ extern int param_get_invbool(char *buffe
#define param_check_invbool(name, p) __param_check(name, p, int)
/* Comma-separated array: *nump is set to number they actually specified. */
-#define module_param_array_named(name, array, type, nump, perm) \
+#define module_param_array_named_ranged(name, array, type, nump, min, max, perm)\
static struct kparam_array __param_arr_##name \
= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
sizeof(array[0]), array }; \
- module_param_call(name, param_array_set, param_array_get, \
- &__param_arr_##name, perm)
+ module_param_call_ranged(name, param_array_set, param_array_get,\
+ &__param_arr_##name, min, max, perm)
+
+#define module_param_array_ranged(name, type, nump, min, max, perm) \
+ module_param_array_named_ranged(name, name, type, nump, min, max, perm)
+
+#define module_param_array_named(name, array, type, nump, perm) \
+ module_param_array_named_ranged(name, array, type, nump, 1, 0, perm)
-#define module_param_array(name, type, nump, perm) \
+#define module_param_array(name, type, nump, perm) \
module_param_array_named(name, name, type, nump, perm)
extern int param_array_set(const char *val, struct kernel_param *kp);
@@ -169,9 +185,8 @@ extern int param_get_string(char *buffer
extern int param_set_flag(const char *val, struct kernel_param *kp);
extern int param_get_flag(char *buffer, struct kernel_param *kp);
-int param_array(const char *name,
- const char *val,
- unsigned int min, unsigned int max,
+int param_array(const char *name, const char *val,
+ long min_val, long max_val, unsigned int min, unsigned int max,
void *elem, int elemsize,
int (*set)(const char *, struct kernel_param *kp),
int *num);
Index: linux-export/kernel/module.c
===================================================================
--- linux-export.orig/kernel/module.c 2004-11-04 10:25:56.000000000 +0900
+++ linux-export/kernel/module.c 2004-11-04 14:48:38.000000000 +0900
@@ -722,20 +722,25 @@ int set_obsolete(const char *val, struct
max = min;
switch (*endp) {
case 'b':
- return param_array(kp->name, val, min, max, obsparm->addr,
- 1, param_set_byte, &dummy);
+ return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ obsparm->addr, 1,
+ param_set_byte, &dummy);
case 'h':
- return param_array(kp->name, val, min, max, obsparm->addr,
- sizeof(short), param_set_short, &dummy);
+ return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ obsparm->addr, sizeof(short),
+ param_set_short, &dummy);
case 'i':
- return param_array(kp->name, val, min, max, obsparm->addr,
- sizeof(int), param_set_int, &dummy);
+ return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ obsparm->addr, sizeof(int),
+ param_set_int, &dummy);
case 'l':
- return param_array(kp->name, val, min, max, obsparm->addr,
- sizeof(long), param_set_long, &dummy);
+ return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ obsparm->addr, sizeof(long),
+ param_set_long, &dummy);
case 's':
- return param_array(kp->name, val, min, max, obsparm->addr,
- sizeof(char *), param_set_charp, &dummy);
+ return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ obsparm->addr, sizeof(char *),
+ param_set_charp, &dummy);
case 'c':
/* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars,
@@ -751,8 +756,9 @@ int set_obsolete(const char *val, struct
}
if (size >= maxsize)
goto oversize;
- return param_array(kp->name, val, min, max, obsparm->addr,
- maxsize, obsparm_copy_string, &dummy);
+ return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ obsparm->addr, maxsize,
+ obsparm_copy_string, &dummy);
}
printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type);
return -EINVAL;
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 14:48:37.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 14:48:38.000000000 +0900
@@ -141,6 +141,11 @@ int parse_args(const char *name,
"%s: `%s' too large for parameter `%s'\n",
name, val ?: "", param);
return ret;
+ case -ERANGE:
+ printk(KERN_ERR
+ "%s: `%s' out of range for parameter `%s'\n",
+ name, val ?: "", param);
+ return ret;
case 0:
break;
default:
@@ -166,6 +171,9 @@ int parse_args(const char *name,
l = strtolfn(val, &endp, 0); \
if (endp == val || ((type)l != l)) \
return -EINVAL; \
+ if (!(kp->min == 1 && kp->max == 0) && \
+ (l < (type)kp->min || l > (type)kp->max)) \
+ return -ERANGE; \
*((type *)kp->arg) = l; \
return 0; \
} \
@@ -184,15 +192,26 @@ STANDARD_PARAM_DEF(ulong, unsigned long,
int param_set_charp(const char *val, struct kernel_param *kp)
{
+ size_t min, max, len;
+
if (!val) {
printk(KERN_ERR "%s: string parameter expected\n",
kp->name);
return -EINVAL;
}
- if (strlen(val) > 1024) {
- printk(KERN_ERR "%s: string parameter too long\n",
- kp->name);
+ if (kp->min == 1 && kp->max == 0) {
+ min = 0;
+ max = 1024;
+ } else {
+ min = kp->min;
+ max = kp->max;
+ }
+
+ len = strlen(val);
+ if (len < min || len > max) {
+ printk(KERN_ERR "%s: string parameter too %s\n",
+ kp->name, len < min ? "short" : "long");
return -ENOSPC;
}
@@ -249,9 +268,8 @@ int param_get_invbool(char *buffer, stru
}
/* We cheat here and temporarily mangle the string. */
-int param_array(const char *name,
- const char *val,
- unsigned int min, unsigned int max,
+int param_array(const char *name, const char *val,
+ long min_val, long max_val, unsigned int min, unsigned int max,
void *elem, int elemsize,
int (*set)(const char *, struct kernel_param *kp),
int *num)
@@ -263,6 +281,8 @@ int param_array(const char *name,
/* Get the name right for errors. */
kp.name = name;
kp.arg = elem;
+ kp.min = min_val;
+ kp.max = max_val;
/* No equals sign? */
if (!val) {
@@ -307,8 +327,9 @@ int param_array_set(const char *val, str
struct kparam_array *arr = kp->arg;
unsigned int t;
- return param_array(kp->name, val, 1, arr->max, arr->elem,
- arr->elemsize, arr->set, arr->num ?: &t);
+ return param_array(kp->name, val, kp->min, kp->max,
+ 1, arr->max, arr->elem, arr->elemsize,
+ arr->set, arr->num ?: &t);
}
int param_array_get(char *buffer, struct kernel_param *kp)
@@ -333,21 +354,18 @@ int param_array_get(char *buffer, struct
int param_set_copystring(const char *val, struct kernel_param *kp)
{
- struct kparam_string *kps = kp->arg;
-
- if (strlen(val)+1 > kps->maxlen) {
- printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
- kp->name, kps->maxlen-1);
+ if (strlen(val)+1 > kp->max) {
+ printk(KERN_ERR "%s: string doesn't fit in %lu chars.\n",
+ kp->name, kp->max - 1);
return -ENOSPC;
}
- strcpy(kps->string, val);
+ strcpy(kp->arg, val);
return 0;
}
int param_get_string(char *buffer, struct kernel_param *kp)
{
- struct kparam_string *kps = kp->arg;
- return strlcpy(buffer, kps->string, kps->maxlen);
+ return strlcpy(buffer, kp->arg, kp->max);
}
int param_set_flag(const char *val, struct kernel_param *kp)
dp_04_param_array_val_noconst.patch
This is the 4th patch of 15 patches for devparam.
This patch removes the const qualifier from @val of param_array().
param_array() does modify @val and I think it's clearer this way.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:48:38.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:48:38.000000000 +0900
@@ -185,7 +185,7 @@ extern int param_get_string(char *buffer
extern int param_set_flag(const char *val, struct kernel_param *kp);
extern int param_get_flag(char *buffer, struct kernel_param *kp);
-int param_array(const char *name, const char *val,
+int param_array(const char *name, char *val,
long min_val, long max_val, unsigned int min, unsigned int max,
void *elem, int elemsize,
int (*set)(const char *, struct kernel_param *kp),
Index: linux-export/kernel/module.c
===================================================================
--- linux-export.orig/kernel/module.c 2004-11-04 14:48:38.000000000 +0900
+++ linux-export/kernel/module.c 2004-11-04 14:48:38.000000000 +0900
@@ -703,6 +703,7 @@ int set_obsolete(const char *val, struct
int dummy;
char *endp;
const char *p;
+ char *v = (char *)val;
struct obsolete_modparm *obsparm = kp->arg;
if (!val) {
@@ -722,23 +723,23 @@ int set_obsolete(const char *val, struct
max = min;
switch (*endp) {
case 'b':
- return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ return param_array(kp->name, v, KPARAM_NO_RANGE, min, max,
obsparm->addr, 1,
param_set_byte, &dummy);
case 'h':
- return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ return param_array(kp->name, v, KPARAM_NO_RANGE, min, max,
obsparm->addr, sizeof(short),
param_set_short, &dummy);
case 'i':
- return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ return param_array(kp->name, v, KPARAM_NO_RANGE, min, max,
obsparm->addr, sizeof(int),
param_set_int, &dummy);
case 'l':
- return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ return param_array(kp->name, v, KPARAM_NO_RANGE, min, max,
obsparm->addr, sizeof(long),
param_set_long, &dummy);
case 's':
- return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ return param_array(kp->name, v, KPARAM_NO_RANGE, min, max,
obsparm->addr, sizeof(char *),
param_set_charp, &dummy);
@@ -756,7 +757,7 @@ int set_obsolete(const char *val, struct
}
if (size >= maxsize)
goto oversize;
- return param_array(kp->name, val, KPARAM_NO_RANGE, min, max,
+ return param_array(kp->name, v, KPARAM_NO_RANGE, min, max,
obsparm->addr, maxsize,
obsparm_copy_string, &dummy);
}
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 14:48:38.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 14:48:38.000000000 +0900
@@ -268,7 +268,7 @@ int param_get_invbool(char *buffer, stru
}
/* We cheat here and temporarily mangle the string. */
-int param_array(const char *name, const char *val,
+int param_array(const char *name, char *val,
long min_val, long max_val, unsigned int min, unsigned int max,
void *elem, int elemsize,
int (*set)(const char *, struct kernel_param *kp),
@@ -304,7 +304,7 @@ int param_array(const char *name, const
/* nul-terminate and parse */
save = val[len];
- ((char *)val)[len] = '\0';
+ val[len] = '\0';
ret = set(val, &kp);
if (ret != 0)
@@ -327,7 +327,7 @@ int param_array_set(const char *val, str
struct kparam_array *arr = kp->arg;
unsigned int t;
- return param_array(kp->name, val, kp->min, kp->max,
+ return param_array(kp->name, (char *)val, kp->min, kp->max,
1, arr->max, arr->elem, arr->elemsize,
arr->set, arr->num ?: &t);
}
dp_06_param_array_delim_colon.patch
This is the 6th patch of 15 patches for devparam.
This adds ':' to the delimeters for param_array(). ':' is used as
the nested array delimeter in devparam.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:25:58.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:25:58.000000000 +0900
@@ -199,7 +199,7 @@ static inline int param_array(const char
{
return param_array_delims(name, val, min_val, max_val,
min_elems, max_elems, elem, elemsize,
- set, num, ",");
+ set, num, ",:");
}
dp_05_param_array_delims.patch
This is the 5th patch of 15 patches for devparam.
This patch reimplements param_array(). New param_array_delims()
accepts a string parameter @delims which specify delimeters.
param_array_delims() also supports backslash escaping of delimeters.
param_array() now just calls param_array() with @delims set to ",".
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:25:58.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:25:58.000000000 +0900
@@ -185,11 +185,23 @@ extern int param_get_string(char *buffer
extern int param_set_flag(const char *val, struct kernel_param *kp);
extern int param_get_flag(char *buffer, struct kernel_param *kp);
-int param_array(const char *name, char *val,
- long min_val, long max_val, unsigned int min, unsigned int max,
- void *elem, int elemsize,
- int (*set)(const char *, struct kernel_param *kp),
- int *num);
+int param_array_delims(const char *name, char *val,
+ unsigned long min_val, unsigned long max_val,
+ unsigned int min_elems, unsigned int max_elems,
+ void *elem, int elemsize,
+ param_set_fn set, int *num, const char *delims);
+
+static inline int param_array(const char *name, char *val,
+ unsigned long min_val, unsigned long max_val,
+ unsigned int min_elems, unsigned int max_elems,
+ void *elem, int elemsize,
+ param_set_fn set, int *num)
+{
+ return param_array_delims(name, val, min_val, max_val,
+ min_elems, max_elems, elem, elemsize,
+ set, num, ",");
+}
+
/* for exporting parameters in /sys/parameters */
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 14:25:58.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 14:25:58.000000000 +0900
@@ -267,16 +267,16 @@ int param_get_invbool(char *buffer, stru
return param_get_bool(buffer, &dummy);
}
-/* We cheat here and temporarily mangle the string. */
-int param_array(const char *name, char *val,
- long min_val, long max_val, unsigned int min, unsigned int max,
- void *elem, int elemsize,
- int (*set)(const char *, struct kernel_param *kp),
- int *num)
+/* We cheat here and mangle the string. */
+int param_array_delims(const char *name, char *val,
+ unsigned long min_val, unsigned long max_val,
+ unsigned int min_elems, unsigned int max_elems,
+ void *elem, int elemsize,
+ param_set_fn set, int *num, const char *delims)
{
int ret;
struct kernel_param kp;
- char save;
+ char save, *sp, *dp;
/* Get the name right for errors. */
kp.name = name;
@@ -290,33 +290,53 @@ int param_array(const char *name, char *
return -EINVAL;
}
+ sp = val;
+ dp = val;
*num = 0;
- /* We expect a comma-separated list of values. */
- do {
- int len;
+ save = *val;
+ /* We expect a list of values which are separated by any of
+ delimiters in @delims. Escaping using backslash is supported. */
+ while (save != '\0') {
+ val = dp;
- if (*num == max) {
+ if (*num == max_elems) {
printk(KERN_ERR "%s: can only take %i arguments\n",
- name, max);
+ name, max_elems);
return -EINVAL;
}
- len = strcspn(val, ",");
- /* nul-terminate and parse */
- save = val[len];
- val[len] = '\0';
- ret = set(val, &kp);
+ next:
+ if (*sp == '\0' || strchr(delims, *sp))
+ goto end_token;
+ else if (*sp == '\\') {
+ sp++;
+ goto escape;
+ } else {
+ *dp++ = *sp++;
+ goto next;
+ }
- if (ret != 0)
+ escape:
+ if (*sp != '\0') {
+ *dp++ = *sp++;
+ goto next;
+ } else
+ goto end_token;
+
+ end_token:
+ save = *sp;
+ *dp = '\0';
+ if ((ret = set(val, &kp)) != 0)
return ret;
kp.arg += elemsize;
- val += len+1;
+ sp++;
+ *dp++ = save;
(*num)++;
- } while (save == ',');
+ }
- if (*num < min) {
+ if (*num < min_elems) {
printk(KERN_ERR "%s: needs at least %i arguments\n",
- name, min);
+ name, min_elems);
return -EINVAL;
}
return 0;
dp_07_export_param_next_arg.patch
This is the 7th patch of 15 patches for devparam.
Rename next_arg to param_next_arg and make it global function. This
function is used by devparam.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:25:58.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:25:59.000000000 +0900
@@ -106,6 +106,9 @@ struct kparam_flag
#define module_param_invflag(name, flags, flag, perm) \
__module_param_flag(name, flags, flag, 1, perm)
+/* Used by deviceparam */
+extern char *param_next_arg(char *args, char **param, char **val);
+
/* Called on module insert or kernel boot */
extern int parse_args(const char *name,
char *args,
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 14:25:58.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 14:25:59.000000000 +0900
@@ -74,7 +74,7 @@ static int parse_one(char *param,
/* You can use " around spaces, but can't escape ". */
/* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
+char *param_next_arg(char *args, char **param, char **val)
{
unsigned int i, equals = 0;
int in_quote = 0;
@@ -129,7 +129,7 @@ int parse_args(const char *name,
while (*args) {
int ret;
- args = next_arg(args, ¶m, &val);
+ args = param_next_arg(args, ¶m, &val);
ret = parse_one(param, val, params, num, unknown);
switch (ret) {
case -ENOENT:
dp_09_module_param_unknown_arg.patch
This is the 9th patch of 15 patches for devparam.
The @unknown function of parse_args() is changed to take a void *arg.
This is used by devparam.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:25:59.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:25:59.000000000 +0900
@@ -114,7 +114,8 @@ extern int parse_args(const char *name,
char *args,
struct kernel_param *params,
unsigned num,
- int (*unknown)(char *param, char *val));
+ int (*unknown)(char *param, char *val, void *arg),
+ void *uarg);
/* All the helper functions */
/* The macros to do compile-time type checking stolen from Jakub
Index: linux-export/init/main.c
===================================================================
--- linux-export.orig/init/main.c 2004-11-04 10:25:56.000000000 +0900
+++ linux-export/init/main.c 2004-11-04 14:25:59.000000000 +0900
@@ -284,7 +284,7 @@ __setup("quiet", quiet_kernel);
* Unknown boot options get handed to init, unless they look like
* failed parameters
*/
-static int __init unknown_bootoption(char *param, char *val)
+static int __init unknown_bootoption(char *param, char *val, void *arg)
{
/* Change NUL term back to "=", to make "param" the whole string. */
if (val) {
@@ -450,7 +450,7 @@ static void noinline rest_init(void)
}
/* Check for early params. */
-static int __init do_early_param(char *param, char *val)
+static int __init do_early_param(char *param, char *val, void *arg)
{
struct obs_kernel_param *p;
extern struct obs_kernel_param __setup_start, __setup_end;
@@ -477,7 +477,7 @@ void __init parse_early_param(void)
/* All fall through to do_early_param. */
strlcpy(tmp_cmdline, saved_command_line, COMMAND_LINE_SIZE);
- parse_args("early options", tmp_cmdline, NULL, 0, do_early_param);
+ parse_args("early options", tmp_cmdline, NULL, 0, do_early_param, NULL);
done = 1;
}
@@ -517,7 +517,7 @@ asmlinkage void __init start_kernel(void
parse_early_param();
parse_args("Booting kernel", command_line, __start___param,
__stop___param - __start___param,
- &unknown_bootoption);
+ &unknown_bootoption, NULL);
sort_main_extable();
trap_init();
rcu_init();
Index: linux-export/kernel/module.c
===================================================================
--- linux-export.orig/kernel/module.c 2004-11-04 14:25:58.000000000 +0900
+++ linux-export/kernel/module.c 2004-11-04 14:25:59.000000000 +0900
@@ -807,7 +807,7 @@ static int obsolete_params(const char *n
kp[i].arg = &obsparm[i];
}
- ret = parse_args(name, args, kp, num, NULL);
+ ret = parse_args(name, args, kp, num, NULL, NULL);
out:
kfree(kp);
return ret;
@@ -1716,7 +1716,7 @@ static struct module *load_module(void _
sechdrs[setupindex].sh_addr,
sechdrs[setupindex].sh_size
/ sizeof(struct kernel_param),
- NULL);
+ NULL, NULL);
}
err = mod_sysfs_setup(mod,
(struct kernel_param *)
Index: linux-export/kernel/params.c
===================================================================
--- linux-export.orig/kernel/params.c 2004-11-04 14:25:59.000000000 +0900
+++ linux-export/kernel/params.c 2004-11-04 14:25:59.000000000 +0900
@@ -50,7 +50,8 @@ static int parse_one(char *param,
char *val,
struct kernel_param *params,
unsigned num_params,
- int (*handle_unknown)(char *param, char *val))
+ int (*handle_unknown)(char *param, char *val, void *arg),
+ void *uarg)
{
unsigned int i;
@@ -65,7 +66,7 @@ static int parse_one(char *param,
if (handle_unknown) {
DEBUGP("Unknown argument: calling %p\n", handle_unknown);
- return handle_unknown(param, val);
+ return handle_unknown(param, val, uarg);
}
DEBUGP("Unknown argument `%s'\n", param);
@@ -120,7 +121,7 @@ int parse_args(const char *name,
char *args,
struct kernel_param *params,
unsigned num,
- int (*unknown)(char *param, char *val))
+ int (*unknown)(char *param, char *val, void *arg), void *uarg)
{
char *param, *val;
@@ -130,7 +131,7 @@ int parse_args(const char *name,
int ret;
args = param_next_arg(args, ¶m, &val);
- ret = parse_one(param, val, params, num, unknown);
+ ret = parse_one(param, val, params, num, unknown, uarg);
switch (ret) {
case -ENOENT:
printk(KERN_ERR "%s: Unknown parameter `%s'\n",
dp_15_DEVPARAM_via-velocity.patch
This is the 15th patch of 15 patches for devparam.
This patch converts via-velocity driver to use devparam.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/drivers/net/via-velocity.c
===================================================================
--- linux-export.orig/drivers/net/via-velocity.c 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/drivers/net/via-velocity.c 2004-11-04 11:04:13.000000000 +0900
@@ -84,7 +84,6 @@
#include "via-velocity.h"
-static int velocity_nics = 0;
static int msglevel = MSG_LEVEL_INFO;
@@ -99,134 +98,106 @@ MODULE_AUTHOR("VIA Networking Technologi
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
-#define VELOCITY_PARAM(N,D) \
- static const int N[MAX_UNITS]=OPTION_DEFAULT;\
- MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\
- MODULE_PARM_DESC(N, D);
-
#define RX_DESC_MIN 64
#define RX_DESC_MAX 255
#define RX_DESC_DEF 64
-VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
-
-#define TX_DESC_MIN 16
-#define TX_DESC_MAX 256
-#define TX_DESC_DEF 64
-VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
-
-#define VLAN_ID_MIN 0
-#define VLAN_ID_MAX 4095
-#define VLAN_ID_DEF 0
-/* VID_setting[] is used for setting the VID of NIC.
- 0: default VID.
- 1-4094: other VIDs.
-*/
-VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
-
-#define RX_THRESH_MIN 0
-#define RX_THRESH_MAX 3
-#define RX_THRESH_DEF 0
-/* rx_thresh[] is used for controlling the receive fifo threshold.
- 0: indicate the rxfifo threshold is 128 bytes.
- 1: indicate the rxfifo threshold is 512 bytes.
- 2: indicate the rxfifo threshold is 1024 bytes.
- 3: indicate the rxfifo threshold is store & forward.
-*/
-VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
-
-#define DMA_LENGTH_MIN 0
-#define DMA_LENGTH_MAX 7
-#define DMA_LENGTH_DEF 0
-
-/* DMA_length[] is used for controlling the DMA length
- 0: 8 DWORDs
- 1: 16 DWORDs
- 2: 32 DWORDs
- 3: 64 DWORDs
- 4: 128 DWORDs
- 5: 256 DWORDs
- 6: SF(flush till emply)
- 7: SF(flush till emply)
-*/
-VELOCITY_PARAM(DMA_length, "DMA length");
-
-#define TAGGING_DEF 0
-/* enable_tagging[] is used for enabling 802.1Q VID tagging.
- 0: disable VID seeting(default).
- 1: enable VID setting.
-*/
-VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
-
-#define IP_ALIG_DEF 0
-/* IP_byte_align[] is used for IP header DWORD byte aligned
- 0: indicate the IP header won't be DWORD byte aligned.(Default) .
- 1: indicate the IP header will be DWORD byte aligned.
- In some enviroment, the IP header should be DWORD byte aligned,
- or the packet will be droped when we receive it. (eg: IPVS)
-*/
-VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
-
-#define TX_CSUM_DEF 1
-/* txcsum_offload[] is used for setting the checksum offload ability of NIC.
- (We only support RX checksum offload now)
- 0: disable csum_offload[checksum offload
- 1: enable checksum offload. (Default)
-*/
-VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload");
-
-#define FLOW_CNTL_DEF 1
-#define FLOW_CNTL_MIN 1
-#define FLOW_CNTL_MAX 5
-
-/* flow_control[] is used for setting the flow control ability of NIC.
- 1: hardware deafult - AUTO (default). Use Hardware default value in ANAR.
- 2: enable TX flow control.
- 3: enable RX flow control.
- 4: enable RX/TX flow control.
- 5: disable
-*/
-VELOCITY_PARAM(flow_control, "Enable flow control ability");
-
-#define MED_LNK_DEF 0
-#define MED_LNK_MIN 0
-#define MED_LNK_MAX 4
-/* speed_duplex[] is used for setting the speed and duplex mode of NIC.
- 0: indicate autonegotiation for both speed and duplex mode
- 1: indicate 100Mbps half duplex mode
- 2: indicate 100Mbps full duplex mode
- 3: indicate 10Mbps half duplex mode
- 4: indicate 10Mbps full duplex mode
-
- Note:
- if EEPROM have been set to the force mode, this option is ignored
- by driver.
-*/
-VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
-
-#define VAL_PKT_LEN_DEF 0
-/* ValPktLen[] is used for setting the checksum offload ability of NIC.
- 0: Receive frame with invalid layer 2 length (Default)
- 1: Drop frame with invalid layer 2 length
-*/
-VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
-
-#define WOL_OPT_DEF 0
-#define WOL_OPT_MIN 0
-#define WOL_OPT_MAX 7
-/* wol_opts[] is used for controlling wake on lan behavior.
- 0: Wake up if recevied a magic packet. (Default)
- 1: Wake up if link status is on/off.
- 2: Wake up if recevied an arp packet.
- 4: Wake up if recevied any unicast packet.
- Those value can be sumed up to support more than one option.
-*/
-VELOCITY_PARAM(wol_opts, "Wake On Lan options");
-#define INT_WORKS_DEF 20
-#define INT_WORKS_MIN 10
-#define INT_WORKS_MAX 64
-
-VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
+#define VELOCITY_INT_PARAM(name, field, min, max, dfl, desc) \
+ DEVICE_PARAM_NAMED_RANGED(name, field, int, min, max, #dfl, 0444, desc)
+#define VELOCITY_FLAG_PARAM(name, flag, dfl, desc) \
+ DEVICE_PARAM_FLAG(name, flags, flag, #dfl, 0444, desc)
+
+static DEFINE_DEVICE_PARAMSET(velocity_paramset_def, struct velocity_opt,
+ VELOCITY_INT_PARAM(RxDescriptors, numrx, 64, 255, 64,
+ "Number of receive descriptors")
+
+ VELOCITY_INT_PARAM(TxDescriptors, numtx, 16, 256, 64,
+ "Number of transmit descriptors")
+
+ /* VID_setting is used for setting the VID of NIC.
+ 0: default VID.
+ 1-4094: other VIDs. */
+ VELOCITY_INT_PARAM(VID_setting, vid, 0, 4095, 0, "802.1Q VLAN ID")
+
+ /* rx_thresh is used for controlling the receive fifo threshold.
+ 0: indicate the rxfifo threshold is 128 bytes.
+ 1: indicate the rxfifo threshold is 512 bytes.
+ 2: indicate the rxfifo threshold is 1024 bytes.
+ 3: indicate the rxfifo threshold is store & forward. */
+ VELOCITY_INT_PARAM(rx_thresh, rx_thresh, 0, 3, 0,
+ "Receive fifo threshold")
+
+ /* DMA_length is used for controlling the DMA length
+ 0: 8 DWORDs
+ 1: 16 DWORDs
+ 2: 32 DWORDs
+ 3: 64 DWORDs
+ 4: 128 DWORDs
+ 5: 256 DWORDs
+ 6: SF(flush till emply)
+ 7: SF(flush till emply) */
+ VELOCITY_INT_PARAM(DMA_length, DMA_length, 0, 7, 0, "DMA length")
+
+ /* enable_tagging is used for enabling 802.1Q VID tagging.
+ 0: disable VID seeting(default).
+ 1: enable VID setting. */
+ VELOCITY_FLAG_PARAM(enable_tagging, VELOCITY_FLAGS_TAGGING, 0,
+ "Enable 802.1Q tagging")
+
+ /* IP_byte_align is used for IP header DWORD byte aligned
+ 0: indicate the IP header won't be DWORD byte aligned.(Default) .
+ 1: indicate the IP header will be DWORD byte aligned.
+ In some enviroment, the IP header should be DWORD byte aligned,
+ or the packet will be droped when we receive it. (eg: IPVS) */
+ VELOCITY_FLAG_PARAM(IP_byte_align, VELOCITY_FLAGS_IP_ALIGN, 0,
+ "Enable IP header dword aligned")
+
+ /* txcsum_offload is used for setting the checksum offload ability of NIC.
+ (We only support RX checksum offload now)
+ 0: disable csum_offload[checksum offload
+ 1: enable checksum offload. (Default) */
+ VELOCITY_FLAG_PARAM(txcsum_offload, VELOCITY_FLAGS_TX_CSUM, 1,
+ "Enable transmit packet checksum offload")
+
+ /* flow_control is used for setting the flow control ability of NIC.
+ 1: hardware deafult - AUTO (default). Use Hardware default value in ANAR.
+ 2: enable TX flow control.
+ 3: enable RX flow control.
+ 4: enable RX/TX flow control.
+ 5: disable */
+ VELOCITY_INT_PARAM(flow_control, flow_cntl, 1, 5, 1,
+ "Enable flow control ability")
+
+ /* speed_duplex is used for setting the speed and duplex mode of NIC.
+ 0: indicate autonegotiation for both speed and duplex mode
+ 1: indicate 100Mbps half duplex mode
+ 2: indicate 100Mbps full duplex mode
+ 3: indicate 10Mbps half duplex mode
+ 4: indicate 10Mbps full duplex mode
+
+ Note:
+ if EEPROM have been set to the force mode, this option is ignored
+ by driver. */
+ VELOCITY_INT_PARAM(speed_duplex, spd_dpx, 0, 4, 0,
+ "Setting the speed and duplex mode")
+
+ /* ValPktLen is used for setting the checksum offload ability of NIC.
+ 0: Receive frame with invalid layer 2 length (Default)
+ 1: Drop frame with invalid layer 2 length */
+ VELOCITY_FLAG_PARAM(ValPktLen, VELOCITY_FLAGS_VAL_PKT_LEN, 0,
+ "Receiving or Drop invalid 802.3 frame")
+
+ /* wol_opts is used for controlling wake on lan behavior.
+ 0: Wake up if recevied a magic packet. (Default)
+ 1: Wake up if link status is on/off.
+ 2: Wake up if recevied an arp packet.
+ 4: Wake up if recevied any unicast packet.
+ Those value can be sumed up to support more than one option. */
+ VELOCITY_INT_PARAM(wol_opts, wol_opts, 0, 7, 0, "Wake On Lan options")
+
+ VELOCITY_INT_PARAM(int_works, int_works, 10, 64, 20,
+ "Number of packets per interrupt services")
+);
static int rx_copybreak = 200;
MODULE_PARM(rx_copybreak, "i");
@@ -359,97 +330,6 @@ static void __devexit velocity_remove1(s
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
-
- velocity_nics--;
-}
-
-/**
- * velocity_set_int_opt - parser for integer options
- * @opt: pointer to option value
- * @val: value the user requested (or -1 for default)
- * @min: lowest value allowed
- * @max: highest value allowed
- * @def: default value
- * @name: property name
- * @dev: device name
- *
- * Set an integer property in the module options. This function does
- * all the verification and checking as well as reporting so that
- * we don't duplicate code for each option.
- */
-
-static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, char *devname)
-{
- if (val == -1)
- *opt = def;
- else if (val < min || val > max) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n",
- devname, name, min, max);
- *opt = def;
- } else {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n",
- devname, name, val);
- *opt = val;
- }
-}
-
-/**
- * velocity_set_bool_opt - parser for boolean options
- * @opt: pointer to option value
- * @val: value the user requested (or -1 for default)
- * @def: default value (yes/no)
- * @flag: numeric value to set for true.
- * @name: property name
- * @dev: device name
- *
- * Set a boolean property in the module options. This function does
- * all the verification and checking as well as reporting so that
- * we don't duplicate code for each option.
- */
-
-static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, char *devname)
-{
- (*opt) &= (~flag);
- if (val == -1)
- *opt |= (def ? flag : 0);
- else if (val < 0 || val > 1) {
- printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
- devname, name);
- *opt |= (def ? flag : 0);
- } else {
- printk(KERN_INFO "%s: set parameter %s to %s\n",
- devname, name, val ? "TRUE" : "FALSE");
- *opt |= (val ? flag : 0);
- }
-}
-
-/**
- * velocity_get_options - set options on device
- * @opts: option structure for the device
- * @index: index of option to use in module options array
- * @devname: device name
- *
- * Turn the module and command options into a single structure
- * for the current device
- */
-
-static void __devinit velocity_get_options(struct velocity_opt *opts, int index, char *devname)
-{
-
- velocity_set_int_opt(&opts->rx_thresh, rx_thresh[index], RX_THRESH_MIN, RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh", devname);
- velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
- velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
- velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
- velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
- velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
- velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
- velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
- velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
- velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
- velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
- velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
- velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname);
- opts->numrx = (opts->numrx & ~3);
}
/**
@@ -478,10 +358,10 @@ static void velocity_init_cam_filter(str
if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
/* If Tagging option is enabled and VLAN ID is not zero, then
turn on MCFG_RTGOPT also */
- if (vptr->options.vid != 0)
+ if (vptr->options->vid != 0)
WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG);
- mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+ mac_set_cam(regs, 0, (u8 *) & (vptr->options->vid), VELOCITY_VLAN_ID_CAM);
vptr->vCAMmask[0] |= 1;
mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
} else {
@@ -511,13 +391,13 @@ static void velocity_rx_reset(struct vel
/*
* Init state, all RD entries belong to the NIC
*/
- for (i = 0; i < vptr->options.numrx; ++i)
+ for (i = 0; i < vptr->options->numrx; ++i)
vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC;
- writew(vptr->options.numrx, ®s->RBRDU);
+ writew(vptr->options->numrx, ®s->RBRDU);
writel(vptr->rd_pool_dma, ®s->RDBaseLo);
writew(0, ®s->RDIdx);
- writew(vptr->options.numrx - 1, ®s->RDCSize);
+ writew(vptr->options->numrx - 1, ®s->RDCSize);
}
/**
@@ -582,8 +462,8 @@ static void velocity_init_registers(stru
* clear Pre_ACPI bit.
*/
BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
- mac_set_rx_thresh(regs, vptr->options.rx_thresh);
- mac_set_dma_length(regs, vptr->options.DMA_length);
+ mac_set_rx_thresh(regs, vptr->options->rx_thresh);
+ mac_set_dma_length(regs, vptr->options->DMA_length);
writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet);
/*
@@ -609,11 +489,11 @@ static void velocity_init_registers(stru
vptr->int_mask = INT_MASK_DEF;
writel(cpu_to_le32(vptr->rd_pool_dma), ®s->RDBaseLo);
- writew(vptr->options.numrx - 1, ®s->RDCSize);
+ writew(vptr->options->numrx - 1, ®s->RDCSize);
mac_rx_queue_run(regs);
mac_rx_queue_wake(regs);
- writew(vptr->options.numtx - 1, ®s->TDCSize);
+ writew(vptr->options->numtx - 1, ®s->TDCSize);
for (i = 0; i < vptr->num_txq; i++) {
writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i]));
@@ -693,12 +573,6 @@ static int __devinit velocity_found1(str
struct mac_regs __iomem * regs;
int ret = -ENOMEM;
- if (velocity_nics >= MAX_UNITS) {
- printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n",
- velocity_nics);
- return -ENODEV;
- }
-
dev = alloc_etherdev(sizeof(struct velocity_info));
if (dev == NULL) {
@@ -711,7 +585,8 @@ static int __devinit velocity_found1(str
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
vptr = dev->priv;
-
+ vptr->options = pdev->dev.paramsets[0];
+ vptr->options->numrx &= ~3;
if (first) {
printk(KERN_INFO "%s Ver. %s\n",
@@ -758,22 +633,19 @@ static int __devinit velocity_found1(str
for (i = 0; i < 6; i++)
dev->dev_addr[i] = readb(®s->PAR[i]);
-
- velocity_get_options(&vptr->options, velocity_nics, dev->name);
-
/*
* Mask out the options cannot be set to the chip
*/
- vptr->options.flags &= info->flags;
+ vptr->options->flags &= info->flags;
/*
* Enable the chip specified capbilities
*/
- vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
+ vptr->flags = vptr->options->flags | (info->flags & 0xFF000000UL);
- vptr->wol_opts = vptr->options.wol_opts;
+ vptr->wol_opts = vptr->options->wol_opts;
vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
@@ -814,7 +686,6 @@ static int __devinit velocity_found1(str
spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
#endif
- velocity_nics++;
out:
return ret;
@@ -936,8 +807,8 @@ static int velocity_init_rings(struct ve
* Allocate all RD/TD rings a single pool
*/
- psize = vptr->options.numrx * sizeof(struct rx_desc) +
- vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+ psize = vptr->options->numrx * sizeof(struct rx_desc) +
+ vptr->options->numtx * sizeof(struct tx_desc) * vptr->num_txq;
/*
* pci_alloc_consistent() fulfills the requirement for 64 bytes
@@ -957,7 +828,7 @@ static int velocity_init_rings(struct ve
vptr->rd_pool_dma = pool_dma;
- tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+ tsize = vptr->options->numtx * PKT_BUF_SZ * vptr->num_txq;
vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize,
&vptr->tx_bufs_dma);
@@ -968,13 +839,13 @@ static int velocity_init_rings(struct ve
return -ENOMEM;
}
- memset(vptr->tx_bufs, 0, vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq);
+ memset(vptr->tx_bufs, 0, vptr->options->numtx * PKT_BUF_SZ * vptr->num_txq);
- i = vptr->options.numrx * sizeof(struct rx_desc);
+ i = vptr->options->numrx * sizeof(struct rx_desc);
pool += i;
pool_dma += i;
for (i = 0; i < vptr->num_txq; i++) {
- int offset = vptr->options.numtx * sizeof(struct tx_desc);
+ int offset = vptr->options->numtx * sizeof(struct tx_desc);
vptr->td_pool_dma[i] = pool_dma;
vptr->td_rings[i] = (struct tx_desc *) pool;
@@ -995,12 +866,12 @@ static void velocity_free_rings(struct v
{
int size;
- size = vptr->options.numrx * sizeof(struct rx_desc) +
- vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+ size = vptr->options->numrx * sizeof(struct rx_desc) +
+ vptr->options->numtx * sizeof(struct tx_desc) * vptr->num_txq;
pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma);
- size = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+ size = vptr->options->numtx * PKT_BUF_SZ * vptr->num_txq;
pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma);
}
@@ -1022,7 +893,7 @@ static inline void velocity_give_many_rx
unusable = vptr->rd_filled & 0x0003;
dirty = vptr->rd_dirty - unusable;
for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
- dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+ dirty = (dirty > 0) ? dirty - 1 : vptr->options->numrx - 1;
vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
}
@@ -1047,7 +918,7 @@ static int velocity_rx_refill(struct vel
break;
}
done++;
- dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
+ dirty = (dirty < vptr->options->numrx - 1) ? dirty + 1 : 0;
} while (dirty != vptr->rd_curr);
if (done) {
@@ -1071,7 +942,7 @@ static int velocity_init_rd_ring(struct
{
int ret = -ENOMEM;
unsigned int rsize = sizeof(struct velocity_rd_info) *
- vptr->options.numrx;
+ vptr->options->numrx;
vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
if(vptr->rd_info == NULL)
@@ -1105,7 +976,7 @@ static void velocity_free_rd_ring(struct
if (vptr->rd_info == NULL)
return;
- for (i = 0; i < vptr->options.numrx; i++) {
+ for (i = 0; i < vptr->options->numrx; i++) {
struct velocity_rd_info *rd_info = &(vptr->rd_info[i]);
if (!rd_info->skb)
@@ -1138,7 +1009,7 @@ static int velocity_init_td_ring(struct
struct tx_desc *td;
struct velocity_td_info *td_info;
unsigned int tsize = sizeof(struct velocity_td_info) *
- vptr->options.numtx;
+ vptr->options->numtx;
/* Init the TD ring entries */
for (j = 0; j < vptr->num_txq; j++) {
@@ -1153,13 +1024,13 @@ static int velocity_init_td_ring(struct
}
memset(vptr->td_infos[j], 0, tsize);
- for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
+ for (i = 0; i < vptr->options->numtx; i++, curr += sizeof(struct tx_desc)) {
td = &(vptr->td_rings[j][i]);
td_info = &(vptr->td_infos[j][i]);
td_info->buf = vptr->tx_bufs +
- (j * vptr->options.numtx + i) * PKT_BUF_SZ;
+ (j * vptr->options->numtx + i) * PKT_BUF_SZ;
td_info->buf_dma = vptr->tx_bufs_dma +
- (j * vptr->options.numtx + i) * PKT_BUF_SZ;
+ (j * vptr->options->numtx + i) * PKT_BUF_SZ;
}
vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0;
}
@@ -1208,7 +1079,7 @@ static void velocity_free_td_ring(struct
for (j = 0; j < vptr->num_txq; j++) {
if (vptr->td_infos[j] == NULL)
continue;
- for (i = 0; i < vptr->options.numtx; i++) {
+ for (i = 0; i < vptr->options->numtx; i++) {
velocity_free_td_ring_entry(vptr, j, i);
}
@@ -1266,7 +1137,7 @@ static int velocity_rx_srv(struct veloci
vptr->dev->last_rx = jiffies;
rd_curr++;
- if (rd_curr >= vptr->options.numrx)
+ if (rd_curr >= vptr->options->numrx)
rd_curr = 0;
} while (++works <= 15);
@@ -1494,7 +1365,7 @@ static int velocity_tx_srv(struct veloci
for (qnum = 0; qnum < vptr->num_txq; qnum++) {
for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0;
- idx = (idx + 1) % vptr->options.numtx) {
+ idx = (idx + 1) % vptr->options->numtx) {
/*
* Get Tx Descriptor
@@ -1557,7 +1428,7 @@ static void velocity_print_link_status(s
if (vptr->mii_status & VELOCITY_LINK_FAIL) {
VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
- } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ } else if (vptr->options->spd_dpx == SPD_DPX_AUTO) {
VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link autonegation", vptr->dev->name);
if (vptr->mii_status & VELOCITY_SPEED_1000)
@@ -1573,7 +1444,7 @@ static void velocity_print_link_status(s
VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
} else {
VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
- switch (vptr->options.spd_dpx) {
+ switch (vptr->options->spd_dpx) {
case SPD_DPX_100_HALF:
VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
break;
@@ -1623,7 +1494,7 @@ static void velocity_error(struct veloci
struct mac_regs __iomem * regs = vptr->mac_regs;
int linked;
- if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ if (vptr->options->spd_dpx == SPD_DPX_AUTO) {
vptr->mii_status = check_connection_type(regs);
/*
@@ -1986,7 +1857,7 @@ static int velocity_xmit(struct sk_buff
}
if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
- td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+ td_ptr->tdesc1.pqinf.VID = (vptr->options->vid & 0xfff);
td_ptr->tdesc1.pqinf.priority = 0;
td_ptr->tdesc1.pqinf.CFI = 0;
td_ptr->tdesc1.TCR |= TCR0_VETAG;
@@ -2009,10 +1880,10 @@ static int velocity_xmit(struct sk_buff
int prev = index - 1;
if (prev < 0)
- prev = vptr->options.numtx - 1;
+ prev = vptr->options->numtx - 1;
td_ptr->tdesc0.owner = OWNED_BY_NIC;
vptr->td_used[qnum]++;
- vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx;
+ vptr->td_curr[qnum] = (index + 1) % vptr->options->numtx;
if (AVAIL_TD(vptr, qnum) < 1)
netif_stop_queue(dev);
@@ -2071,7 +1942,7 @@ static int velocity_intr(int irq, void *
if (isr_status & (ISR_PTXI | ISR_PPTXI))
max_count += velocity_tx_srv(vptr, isr_status);
isr_status = mac_read_isr(vptr->mac_regs);
- if (max_count > vptr->options.int_works)
+ if (max_count > vptr->options->int_works)
{
printk(KERN_WARNING "%s: excessive work at interrupt.\n",
dev->name);
@@ -2219,14 +2090,20 @@ static int velocity_ioctl(struct net_dev
* uses this to handle all our card discover and plugging
*/
+static struct device_paramset_def *paramset_defs[] = {
+ &velocity_paramset_def,
+ NULL
+};
+
static struct pci_driver velocity_driver = {
- .name = VELOCITY_NAME,
- .id_table = velocity_id_table,
- .probe = velocity_found1,
- .remove = __devexit_p(velocity_remove1),
+ .name = VELOCITY_NAME,
+ .id_table = velocity_id_table,
+ .driver.paramset_defs = paramset_defs,
+ .probe = velocity_found1,
+ .remove = __devexit_p(velocity_remove1),
#ifdef CONFIG_PM
- .suspend = velocity_suspend,
- .resume = velocity_resume,
+ .suspend = velocity_suspend,
+ .resume = velocity_resume,
#endif
};
@@ -2484,7 +2361,7 @@ static u32 velocity_get_opt_media_mode(s
{
u32 status = 0;
- switch (vptr->options.spd_dpx) {
+ switch (vptr->options->spd_dpx) {
case SPD_DPX_AUTO:
status = VELOCITY_AUTONEG_ENABLE;
break;
@@ -2539,7 +2416,7 @@ static void mii_set_auto_off(struct velo
static void set_mii_flow_control(struct velocity_info *vptr)
{
/*Enable or Disable PAUSE in ANAR */
- switch (vptr->options.flow_cntl) {
+ switch (vptr->options->flow_cntl) {
case FLOW_CNTL_TX:
MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
@@ -2766,7 +2643,7 @@ static void enable_flow_control_ability(
struct mac_regs __iomem * regs = vptr->mac_regs;
- switch (vptr->options.flow_cntl) {
+ switch (vptr->options->flow_cntl) {
case FLOW_CNTL_DEFAULT:
if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0))
Index: linux-export/drivers/net/via-velocity.h
===================================================================
--- linux-export.orig/drivers/net/via-velocity.h 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/drivers/net/via-velocity.h 2004-11-04 11:04:13.000000000 +0900
@@ -33,9 +33,6 @@
#define PKT_BUF_SZ 1540
-#define MAX_UNITS 8
-#define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1}
-
#define REV_ID_VT6110 (0)
#define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0)
@@ -1193,7 +1190,7 @@ struct velocity_info_tbl {
char *name;
int io_size;
int txqueue;
- u32 flags;
+ unsigned flags;
};
#define mac_hw_mibs_init(regs) {\
@@ -1718,7 +1715,7 @@ enum velocity_flow_cntl_type {
struct velocity_opt {
int numrx; /* Number of RX descriptors */
int numtx; /* Number of TX descriptors */
- enum speed_opt spd_dpx; /* Media link mode */
+ int spd_dpx; /* Media link mode */
int vid; /* vlan id */
int DMA_length; /* DMA length */
int rx_thresh; /* RX_THRESH */
@@ -1729,7 +1726,7 @@ struct velocity_opt {
int rx_bandwidth_hi;
int rx_bandwidth_lo;
int rx_bandwidth_en;
- u32 flags;
+ unsigned flags;
};
struct velocity_info {
@@ -1755,7 +1752,7 @@ struct velocity_info {
u8 rev_id;
-#define AVAIL_TD(p,q) ((p)->options.numtx-((p)->td_used[(q)]))
+#define AVAIL_TD(p,q) ((p)->options->numtx-((p)->td_used[(q)]))
int num_txq;
@@ -1773,11 +1770,11 @@ struct velocity_info {
#define GET_RD_BY_IDX(vptr, idx) (vptr->rd_ring[idx])
u32 mib_counter[MAX_HW_MIB_COUNTER];
- struct velocity_opt options;
+ struct velocity_opt *options;
u32 int_mask;
- u32 flags;
+ unsigned flags;
int rx_buf_sz;
u32 mii_status;
@@ -1872,7 +1869,7 @@ static inline void init_flow_control_reg
writew(0xFFFF, ®s->tx_pause_timer);
/* Initialize RBRDU to Rx buffer count. */
- writew(vptr->options.numrx, ®s->RBRDU);
+ writew(vptr->options->numrx, ®s->RBRDU);
}
dp_14_devparam_doc.patch
This is the 14th patch of 15 patches for devparam.
Devparam document.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/Documentation/driver-model/devparam.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-export/Documentation/driver-model/devparam.txt 2004-11-04 11:04:13.000000000 +0900
@@ -0,0 +1,419 @@
+Per-Device Parameter
+
+Tejun Heo <[email protected]>
+
+19 October 2004
+
+
+ INTRO
+ =====
+
+ Per-device parameter wasn't supported by Linux driver model
+previously. It was usually done using the moduleparam facility. As
+the name suggests, moduleparam implements per-module parameters and
+drivers used fixed-size array to implement per-device parameters.
+This results in unnecessary duplication of codes, variation in usage
+and random limits on the number of supported devices or devices which
+users can specify parameters for. Devparam integrates per-device
+parameter support into the driver model to solve these issues.
+
+ Devparam aims to
+
+ 1. Remove duplicated parameter handling codes from drivers
+ 2. Retain user-visible syntax for converted drivers
+ 3. Remove hard-coded random limits on the number of devices
+ parameters can be specified for
+ 4. Support multiple paramsets
+ 5. Support sysfs access to per-device paramters
+
+
+ OVERVIEW
+ ========
+
+ Parameters are organized into parameter sets or paramsets. Each
+paramset is represented by a user-defined structure (e.g. struct
+my_dev_paramset). A paramset definition, or paramset_def, describes
+the paramset to the driver model - what it contains, how to parse each
+parameter and so on.
+
+ A device driver passes paramset_defs it wants to use to the driver
+model when registering the driver, and before the driver is attached
+to a device, the driver model parses user supplied parameters and
+fills the paramsets and pass them to the device driver.
+
+ There are two categories of paramsets.
+
+ I. DEV PARAMSETS
+
+ These are device specific parameters used by the driver. This
+category includes most parameters currently used by drivers. Examples
+for network drivers would be stuff like the size of tx/rx descriptor
+ring and hardware checksum enable/disable option.
+
+ As the tailing 'S' suggests, drivers can use multiple paramsets.
+Primary usage of multiple paramsets would be for class parameters for
+class devices. For example, if the input layer wants to accept some
+common set of parameters for each input device, it can define a
+paramset_def and all input device drivers can use it to accept the
+common parameters. Once modified to use the facility, the content of
+the paramset_def doesn't matter to specific device drivers, so the
+input paramset_def can be modified without changing or even
+recompiling individual device drivers.
+
+ II. BUS PARAMSET
+
+ These are bus specific parameters. Individual device drivers
+wouldn't care or know about this paramset. These paramsets are
+defined and used only by bus drivers. When a bus driver wants to
+accept some common paramters for all devices living on the bus, the
+driver will supply the bus paramset_def and all device drivers for the
+bus will accept bus parameters. Examples would be PCI command
+register setting, PCIe QoS settings and so on.
+
+
+ USING DEVPARAM
+ ==============
+
+ Paramset definition is defined using DEFINE_DEVICE_PARAMSET[_NS] and
+DEVICE_PARAM_* macros and passed to the driver-model via the
+paramset_def[s] fields of struct device_driver or struct bus_type.
+The usage is very similar to moduleparam; actually, most of devparam
+is built using moduleparam.
+
+- DEFINE_DEVICE_PARAMSET_NS(Name, Type, Namespace, Paramdefs) macro
+
+ Defines a struct device_paramset_def @Name which contains
+ parameters described by @Paramdefs. Each parameter definition
+ in @Paramdefs describes how to handle a parameter which is
+ contained in a @Type variable. All parameters defined with
+ this macros has dot-appended @Namespace as their prefixes.
+
+- DEFINE_DEVICE_PARAMSET(Name, Type, Paramdefs) macro
+
+ Identical with the above macro except that there's no prefix
+ to the parameters.
+
+- DEVICE_PARAM_*() macros
+
+ Syntax is almost identical to module_param_*() macros defined
+ in moduleparam.h. There are three differences. The first is
+ that instead of referring directly to a variable to be set,
+ the field name inside @Type of enclosing
+ DEFINE_DEVICE_PARAMSET is used. The second is that there's an
+ extra argument @Dfl which is a string containing the default
+ value to use when the user didn't specify the parameter.
+ The last is the additional argument @Desc which serves the
+ same purpose as MODULE_PARAM_DESC().
+
+
+ When attaching a device, its paramset structures are allocated and
+cleared with zero, and for each defined parameter, set function is
+called with user supplied argument if it's available or the default
+string. If the default string is also NULL, set function isn't
+called). (Actually, all parameters are parsed when the device driver
+is initialized and cached inside the device_driver structure, but the
+end result is the same as described above.)
+
+ Device parameters are passed as comma-separated values via
+moduleparam facility (the first value is for the first device which
+gets attached to the driver, the second value for the second device
+and so on). In parameter strings, '\' escapes the following
+character, so by using "\," strings containing commas or
+comma-separated arrays can be specified. To ease nested array
+specification, ':' is also accepted as nested array separator.
+
+ It's best explained with examples. I'll present two examples - one
+simple and the other more complete. If you're a driver developer just
+wanting to receive per-device parameters for your driver, reading the
+first example should suffice.
+
+
+ A SIMPLE ONE
+ ============
+
+ I'll use an imaginary pci device driver for this example. Let's
+say it wants to accept the following parameters.
+
+ - One integer parameter named integer_knob which should be in the
+ range [0, 255] and defaults to 16 when none is specified.
+ - One string parameter named string which can be as long as 63
+ characters and defaults to "mung mung".
+ - A boolean parameter named enable_feature0 which, when 1, sets
+ MY_FEATURE0 in flags and defaults to 0.
+
+ First, a paramset structure needs to be defined.
+
+| struct my_drv_paramset {
+| int integer_knob;
+| char string[64];
+| unsigned flags;
+| };
+
+ Then, the corresponding my_drv_paramset_def.
+
+| static DEFINE_DEVICE_PARAMSET(my_drv_paramset_def, struct my_drv_paramset,
+| DEVICE_PARAM_RANGED(integer_knob, int, 0, 255, "16", 0444,
+| "integer_knob does something, [0,255] default 16")
+| DEVICE_PARAM_STRING(string, "mung mung", 0444,
+| "A string is a string")
+| DEVICE_PARAM_FLAG(enable_feature0, flags, MY_FEATURE0, "0", 0444,
+| "Enables feature0. Whatever that is.")
+| );
+
+ We're almost done already. The only thing left is to register the
+paramset_def.
+
+| static struct device_paramset_def *paramset_defs[] = {
+| &my_drv_paramset_def,
+| NULL
+| };
+|
+| static struct pci_driver my_drv = {
+| .name = "my_drv",
+| .owner = THIS_MODULE,
+| .probe = my_probe,
+| .driver.paramset_defs = paramset_defs,
+| ...
+| };
+|
+| static int __init my_init(void)
+| {
+| ...
+| return pci_register_driver(&my_drv);
+| }
+
+ And we can use the paramset however we want to.
+
+| static int __devinit my_probe(struct pci_dev *pdev,
+| const struct pci_device_id *ent)
+| {
+| struct my_drv_paramset *ps = pdev->dev.paramsets[0];
+| ...
+| }
+
+ Now, let's see how a user can specify those device parameters. If
+the driver is compiled into the kernel, parameters can be specified in
+the boot options.
+
+> my_drv.integer_knob=32,32,64 my_drv.string="bungga,asdf"
+
+ The results would be...
+
+ integer_knob string flags
+ ----------------------------------------------------------
+ 1st dev: 32 "bungga" 0
+ 2st dev: 32 "asdf" 0
+ 3st dev: 64 "mung mung" 0
+ 4th-Nth: 16 "mung mung" 0
+
+ If the module is compiled as a module, parameters can be specified
+like the following.
+
+> modprobe my_drv integer_knob=8,8,32 enable_feature0=1,1
+
+ integer_knob string flags
+ ----------------------------------------------------------
+ 1st dev: 8 "mung mung" MY_FEATURE0
+ 2st dev: 8 "mung mung" MY_FEATURE0
+ 3st dev: 32 "mung mung" 0
+ 4th-Nth: 16 "mung mung" 0
+
+ Note that when a device attaches, the first empty paramset slot is
+used. For example, let's say there's device A, B, C and D all of
+which are controlled by my_drv, and three paramsets ps0, ps1 and ps2
+of which ps2 is the default paramset.
+
+ Event Paramset
+ -----------------------
+ A attaches ps0
+ B attaches ps1
+ C attaches ps2
+ B detaches
+ D attaches ps1
+ B attaches ps2
+
+ However, as each device gets its own copy of the paramsets, it can
+modify the paramset as needed. Modifying its paramset won't affect
+other devices attaching later.
+
+
+ A FULL EXAMPLE
+ ==============
+
+ I'll use a pseudo bus, class and driver respectively named dp_bus,
+dp_class and dp_drv for explanation. A dp_drv lives on dp_bus and a
+dp_drv device implements a class device belonging to dp_class. All of
+dp_bus, dp_class and dp_drv accept their own sets of parameters.
+
+ Let's look at dp_bus first.
+
+ I. DP_BUS
+
+ dp_bus defines struct dp_driver (just like struct pci_drv) and
+registration unregistration functions (just like
+pci_[un]register_driver() functions). So, it defines the following
+interface in dp_bus.h.
+
+| struct dp_driver {
+| int (*probe)(struct device *dev);
+| void (*remove)(struct device *dev);
+| struct device_driver driver;
+| };
+|
+| extern struct bus_type dp_bus_type;
+|
+| int dp_register_driver(struct dp_driver *drv);
+| void dp_unregister_driver(struct dp_driver *drv);
+
+ dp_bus wants to accept the following parameters.
+
+ - Three integer parameters named bus_a, bus_b and bus_c.
+ - An array of intergers which can have 6 elements at maximum.
+
+ So, in dp_bus.c, the following structure is defined.
+
+| struct dp_bus_paramset {
+| int a, b, c;
+| int ar[6], ar_cnt;
+| };
+
+ Also corresponding dp_bus_paramset_def.
+
+| static DEFINE_DEVICE_PARAMSET_NS(dp_bus_paramset_def, struct dp_bus_paramset,
+| "dp_bus",
+| DEVICE_PARAM(a, int, "0", 0444, "mung mung")
+| DEVICE_PARAM(b, int, "1", 0444, "bungga bungga")
+| DEVICE_PARAM(c, int, "2", 0444, "OTL OTL OTL OTL OTL OTL")
+| DEVICE_PARAM_ARRAY(ar, int, ar_cnt, "1,2,3", 0444, "whatever, dude")
+| );
+
+ Note that, we're defining parameters under "dp_bus" namescope. All
+of above parameters are treated as they have "dp_bus." prefix. In
+other words, if a user wants to specify the @a parameter, it must be
+specified as "dp_bus.a".
+
+ So, needed data structures are in place now. All that's left to do
+is to use the appropriate hooks. First, we need to set paramset_def
+field of bus_type.
+
+| struct bus_type dp_bus_type = {
+| .name = "dp",
+| .match = dp_bus_match,
+| .paramset_def = &dp_dev_paramset_def
+| };
+
+ And, in dp_register_driver(), we hook up probe and remove to dp_probe
+and dp_remove.
+
+| int dp_register_driver(struct dp_driver *drv, struct module *mod)
+| {
+| drv->driver.bus = &dp_bus_type;
+| drv->driver.probe = dp_probe;
+| drv->driver.remove = dp_remove;
+| printk("dp_bus: registering driver \"%s\"\n", drv->driver.name);
+| return driver_register(&drv->driver);
+| }
+
+ dp_probe() looks like the folowing.
+
+| static int dp_probe(struct device *dev)
+| {
+| struct dp_driver *drv;
+| struct dp_bus_paramset *ps;
+|
+| drv = container_of(dev->driver, struct dp_driver, driver);
+| ps = dev->bus_paramset;
+|
+| /* Whatever the bus driver wanna do can come here. */
+|
+| return drv->probe(dev);
+| }
+
+ The driver model parses user specified parameter or the default
+parameter supplied with paramset_def and set dev->bus_paramset field
+to the result. The bus driver is free to read and modify the
+structure as needed. As dp_bus is a pseudo bus, it doesn't really
+have anything to do, but a real driver could tweak some bus features
+(e.g. PCIe QoS setting) for the device there.
+
+ Above are all the interesting parts of dp_bus implementation. Now,
+let's look at dp_class.
+
+
+ II. DP_CLASS
+
+ dp_class is a dummy class which doesn't do anything but accepting
+some parameters and getting devices registered to it. Consequently,
+it has a very simple interface.
+
+| extern struct class dp_class;
+| extern struct device_paramset_def dp_class_paramset_def;
+| struct dp_class_paramset;
+|
+| extern int dp_class_device_register(struct class_device *dev,
+| struct dp_class_paramset *params);
+| void dp_class_device_unregister(struct class_device *dev);
+
+ Note that dp_class_paramset_def is exported. This wasn't necessary
+for bus parameters but as device-class association is only known by
+the driver of a device, it must be able to access the paramset_defs of
+the classes it's going to register a device to. Any driver which
+wants to register with dp_class will pass dp_class_paramset_def to the
+driver-model using drv.paramset_defs field and pass the resulting
+paramset to dp_class_device_register().
+
+ The implementation of dp_class isn't very intriguing.
+dp_class_paramset_def is defined just like dp_bus_paramset_def. The
+only differences are that there's no static qualifier in front of
+DEFINE_DEVICE_PARAMSET() and dp_bus_paramset_def needs to be
+EXPORT_SYMBOL()'d as it's gonna be referenced by drivers living in
+other modules.
+
+
+III. DP_DRV
+
+ Okay, here's dp_drv, where everything comes together. dp_drv defines
+its own dp_drv_paramset_def just like dp_bus. dp_drv also defines an
+array of device_paramset_def's which contain pointers to both
+dp_drv_paramset_def and dp_class_paramset_def.
+
+| static struct device_paramset_def *paramset_defs[] = {
+| &dp_drv_paramset_def,
+| &dp_class_paramset_def,
+| NULL
+| };
+
+ And the dp_driver structure looks like the follwing.
+
+| static struct dp_driver my_drv = {
+| .driver.name = "babo",
+| .driver.owner = THIS_MODULE,
+| .probe = dp_drv_probe,
+| .remove = dp_drv_remove,
+| .driver.paramset_defs = paramset_defs,
+| };
+|
+| static int __init dp_drv_init(void)
+| {
+| return dp_register_driver(&my_drv);
+| }
+
+ Paramsets are accessed and passed to dp_class like the following.
+
+| static int dp_drv_probe(struct device *dev)
+| {
+| struct dp_drv_paramset *ps = dev->paramsets[0];
+| ...
+| ret = dp_class_device_register(priv->class, dev->paramsets[1]);
+| ...
+| }
+
+ Now everyone has its paramset and should be happy and hazy.
+
+ Complete source code for dp_bus, dp_class, dp_drv and dp_dev (dp_dev
+is for creating pseudo devices which attaches to dp_drv) is available
+at the following URL.
+
+ http://home-tj.org/devparam/dptest.tar.gz
+
+ Happy hacking.
dp_13_devparam_apply.patch
This is the 13th patch of 15 patches for devparam.
This patch hooks devparam into the driver-model. Devparam is
complete now.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/drivers/base/bus.c
===================================================================
--- linux-export.orig/drivers/base/bus.c 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/drivers/base/bus.c 2004-11-04 14:26:03.000000000 +0900
@@ -266,20 +266,30 @@ void device_bind_driver(struct device *
*/
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
+ int error;
+
if (drv->bus->match && !drv->bus->match(dev, drv))
return -ENODEV;
dev->driver = drv;
+
+ if ((error = devparam_set_params(dev)) != 0)
+ goto devparam_fail;
+
if (drv->probe) {
- int error = drv->probe(dev);
- if (error) {
- dev->driver = NULL;
- return error;
- }
+ error = drv->probe(dev);
+ if (error)
+ goto probe_fail;
}
device_bind_driver(dev);
return 0;
+
+ probe_fail:
+ devparam_release_params(dev);
+ devparam_fail:
+ dev->driver = NULL;
+ return error;
}
@@ -376,6 +386,7 @@ void device_release_driver(struct device
device_detach_shutdown(dev);
if (drv->remove)
drv->remove(dev);
+ devparam_release_params(dev);
dev->driver = NULL;
}
}
Index: linux-export/drivers/base/driver.c
===================================================================
--- linux-export.orig/drivers/base/driver.c 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/drivers/base/driver.c 2004-11-04 14:26:03.000000000 +0900
@@ -85,9 +85,14 @@ void put_driver(struct device_driver * d
*/
int driver_register(struct device_driver * drv)
{
+ int ret;
INIT_LIST_HEAD(&drv->devices);
init_MUTEX_LOCKED(&drv->unload_sem);
- return bus_add_driver(drv);
+ if ((ret = devparam_driver_init(drv)) < 0)
+ return ret;
+ if ((ret = bus_add_driver(drv)) < 0)
+ devparam_driver_release(drv);
+ return ret;
}
@@ -109,6 +114,7 @@ void driver_unregister(struct device_dri
bus_remove_driver(drv);
down(&drv->unload_sem);
up(&drv->unload_sem);
+ devparam_driver_release(drv);
}
/**
Index: linux-export/init/main.c
===================================================================
--- linux-export.orig/init/main.c 2004-11-04 14:25:59.000000000 +0900
+++ linux-export/init/main.c 2004-11-04 14:26:03.000000000 +0900
@@ -38,6 +38,7 @@
#include <linux/profile.h>
#include <linux/rcupdate.h>
#include <linux/moduleparam.h>
+#include <linux/deviceparam.h>
#include <linux/kallsyms.h>
#include <linux/writeback.h>
#include <linux/cpu.h>
@@ -286,29 +287,32 @@ __setup("quiet", quiet_kernel);
*/
static int __init unknown_bootoption(char *param, char *val, void *arg)
{
+ char *cp = NULL;
+
/* Change NUL term back to "=", to make "param" the whole string. */
if (val) {
/* param=val or param="val"? */
if (val == param+strlen(param)+1)
- val[-1] = '=';
+ cp = val - 1;
else if (val == param+strlen(param)+2) {
- val[-2] = '=';
+ cp = val - 2;
memmove(val-1, val, strlen(val)+1);
val--;
} else
BUG();
+ *cp = '=';
}
/* Handle obsolete-style parameters */
if (obsolete_checksetup(param))
return 0;
- /*
- * Preemptive maintenance for "why didn't my mispelled command
- * line work?"
- */
+ /* It might be a device parameter, pass it to deviceparam facility. */
if (strchr(param, '.') && (!val || strchr(param, '.') < val)) {
- printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param);
+ /* Restore NUL term. */
+ if (cp)
+ *cp = '\0';
+ devparam_maybe_bootopt(param, val);
return 0;
}
@@ -652,6 +656,8 @@ static void __init do_basic_setup(void)
sock_init();
do_initcalls();
+
+ devparam_finish_bootopts();
}
static void do_pre_smp_initcalls(void)
Index: linux-export/kernel/module.c
===================================================================
--- linux-export.orig/kernel/module.c 2004-11-04 14:25:59.000000000 +0900
+++ linux-export/kernel/module.c 2004-11-04 14:26:03.000000000 +0900
@@ -29,6 +29,7 @@
#include <linux/rcupdate.h>
#include <linux/cpu.h>
#include <linux/moduleparam.h>
+#include <linux/deviceparam.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/vermagic.h>
@@ -1696,6 +1697,10 @@ static struct module *load_module(void _
if (err < 0)
goto cleanup;
+ /* Set up device args vector */
+ if (devparam_module_init(mod) < 0)
+ goto arch_cleanup;
+
mod->args = args;
if (obsparmindex) {
err = obsolete_params(mod->name, mod->args,
@@ -1716,7 +1721,7 @@ static struct module *load_module(void _
sechdrs[setupindex].sh_addr,
sechdrs[setupindex].sh_size
/ sizeof(struct kernel_param),
- NULL, NULL);
+ devparam_unknown_modparam, mod);
}
err = mod_sysfs_setup(mod,
(struct kernel_param *)
@@ -1724,7 +1729,7 @@ static struct module *load_module(void _
sechdrs[setupindex].sh_size
/ sizeof(struct kernel_param));
if (err < 0)
- goto arch_cleanup;
+ goto devparam_done;
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
/* Get rid of temporary copy */
@@ -1733,6 +1738,8 @@ static struct module *load_module(void _
/* Done! */
return mod;
+ devparam_done:
+ devparam_module_done(mod);
arch_cleanup:
module_arch_cleanup(mod);
cleanup:
@@ -1804,6 +1811,10 @@ sys_init_module(void __user *umod,
/* Start the module */
if (mod->init != NULL)
ret = mod->init();
+
+ /* We're done with device params */
+ devparam_module_done(mod);
+
if (ret < 0) {
/* Init routine failed: abort. Try to protect us from
buggy refcounters. */
dp_08_module_param_empty_prefix.patch
This is the 8th patch of 15 patches for devparam.
MODULE_PARAM_PREFIX is changed to be "" instead of being empty for
kernel proper. The end result is the same for moduleparam, but it
helps devparam macros.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 11:04:09.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 11:04:09.000000000 +0900
@@ -8,7 +8,7 @@
/* You can override this manually, but generally this should match the
module name. */
#ifdef MODULE
-#define MODULE_PARAM_PREFIX /* empty */
+#define MODULE_PARAM_PREFIX ""
#else
#define MODULE_PARAM_PREFIX __stringify(KBUILD_MODNAME) "."
#endif
dp_12_devparam.patch
This is the 12th patch of 15 patches for devparam.
This patch adds needed data fields to module and device structures
and actually implements devparam. This patch doesn't hook devparam
into the driver model it's done in the next patch.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/drivers/base/Makefile
===================================================================
--- linux-export.orig/drivers/base/Makefile 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/drivers/base/Makefile 2004-11-04 14:48:43.000000000 +0900
@@ -2,7 +2,8 @@
obj-y := core.o sys.o interface.o bus.o \
driver.o class.o class_simple.o platform.o \
- cpu.o firmware.o init.o map.o dmapool.o
+ cpu.o firmware.o init.o map.o dmapool.o \
+ deviceparam.o
obj-y += power/
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
Index: linux-export/drivers/base/deviceparam.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-export/drivers/base/deviceparam.c 2004-11-04 14:48:43.000000000 +0900
@@ -0,0 +1,858 @@
+/*
+ * deviceparam.c - per-device bus/driver parameter
+ *
+ * Copyright (C) 2004 Tejun Heo <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/deviceparam.h>
+#include <linux/device.h>
+#include <linux/module.h>
+
+#if 0
+#define pdebug(fmt, args...) printk("[%-25s] " fmt, __FUNCTION__ , ##args)
+#else
+#define pdebug(fmt, args...)
+#endif
+
+#define MAX_DEVICE_BOOTOPTS 64
+
+static int nr_bootopts = 0;
+static __initdata char *bootopts[MAX_DEVICE_BOOTOPTS][2];
+
+#define for_each_setdef(which, setdef, drv) \
+ for ((which) = 0; \
+ ((which) < (drv)->nr_paramsets || ((setdef) = NULL, 0)) && \
+ ((setdef) = (drv)->paramset_defs[(which)], 1); (which)++)
+
+static int devparam_parse_modparams(struct device_driver *drv);
+
+/*
+ * devparam_vec
+ */
+static void vec_init(struct devparam_vec *vec, int elem_size)
+{
+ vec->ar = NULL;
+ vec->ar_len = 0;
+ vec->len = 0;
+ vec->elem_size = elem_size;
+}
+
+static int vec_set_len(struct devparam_vec *vec, int nlen)
+{
+ int i;
+
+ if (nlen <= vec->len) {
+ /* Shrink */
+ for (i = nlen; i < vec->len; i++) {
+ kfree(vec->ar[i]);
+ vec->ar[i] = NULL;
+ }
+ vec->len = nlen;
+ return 0;
+ }
+
+ /* Expand */
+ if (nlen > vec->ar_len) {
+ int ar_len = vec->ar_len ?: 16;
+ void **ar;
+ do {
+ ar_len *= 2;
+ BUG_ON(ar_len < 0);
+ } while (ar_len < nlen);
+
+ if ((ar = kmalloc(ar_len * sizeof(ar[0]), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ memcpy(ar, vec->ar, vec->ar_len * sizeof(ar[0]));
+ memset(ar + vec->ar_len, 0,
+ (ar_len - vec->ar_len) * sizeof(ar[0]));
+
+ kfree(vec->ar);
+ vec->ar = ar;
+ vec->ar_len = ar_len;
+ }
+
+ for (i = vec->len; i < nlen; i++) {
+ if ((vec->ar[i] = kmalloc(vec->elem_size, GFP_KERNEL)) == NULL)
+ goto unroll_out;
+ memset(vec->ar[i], 0, vec->elem_size);
+ }
+
+ vec->len = nlen;
+ return 0;
+
+ unroll_out:
+ while (--i >= vec->len)
+ kfree(vec->ar[i]);
+ return -ENOMEM;
+}
+
+static void * vec_elem(struct devparam_vec *vec, int idx)
+{
+ if (idx >= vec->len && vec_set_len(vec, idx + 1) < 0)
+ return NULL;
+ return vec->ar[idx];
+}
+
+static void vec_destroy(struct devparam_vec *vec)
+{
+ int i;
+ for (i = 0; i < vec->len; i++)
+ kfree(vec->ar[i]);
+ kfree(vec->ar);
+}
+
+
+/*
+ * Utility routines
+ */
+static struct device_paramset_def *
+get_setdef_by_idx(int *pidx, int *pwhich, struct device_driver *drv)
+{
+ int which, idx = *pidx;
+ struct device_paramset_def *setdef;
+
+ for_each_setdef(which, setdef, drv) {
+ if (idx >= setdef->nr_defs)
+ idx -= setdef->nr_defs;
+ else
+ break;
+ }
+
+ *pidx = idx;
+ *pwhich = which;
+ return setdef;
+}
+
+static int prepare_kparam(struct kernel_param *kparam,
+ struct device_param_def *def, void *paramset)
+{
+ const int *fixups;
+
+ *kparam = def->kparam;
+
+ if (def->arg_copy_size) {
+ if (!(kparam->arg = kmalloc(def->arg_copy_size, GFP_KERNEL)))
+ return -ENOMEM;
+ memcpy(kparam->arg, def->kparam.arg, def->arg_copy_size);
+ }
+
+ for (fixups = def->arg_fixups; fixups[1] != -1; fixups += 2) {
+ void *p = paramset + fixups[1];
+ if (fixups[0] != -1)
+ *(void **)(kparam->arg + fixups[0]) = p;
+ else
+ kparam->arg = p;
+ }
+
+ return 0;
+}
+
+static void release_kparam(struct kernel_param *kparam,
+ struct device_param_def *def)
+{
+ if (def->arg_copy_size)
+ kfree(kparam->arg);
+}
+
+static int call_get(struct device_param_def *def, char *buf, void *paramset)
+{
+ struct kernel_param kparam;
+ int ret;
+
+ if ((ret = prepare_kparam(&kparam, def, paramset)) == 0) {
+ ret = kparam.get(buf, &kparam);
+ pdebug("n=\"%s\" b=\"%s\" arg=%p set=%p ret=%d\n",
+ kparam.name, buf, kparam.arg, kparam.set, ret);
+ }
+ release_kparam(&kparam, def);
+
+ return ret;
+}
+
+static int call_set(struct device_param_def *def, char *val, void *paramset)
+{
+ struct kernel_param kparam;
+ int is_dfl, ret, set_ret;
+
+ is_dfl = val == NULL;
+
+ if (is_dfl) {
+ size_t size;
+ if (def->dfl == NULL)
+ return 0;
+ if (def->copy_dfl) {
+ size = strlen(def->dfl) + 1;
+ if ((val = kmalloc(size, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(val, def->dfl, size);
+ } else
+ val = (char *)def->dfl;
+ }
+
+ set_ret = 0;
+ if ((ret = prepare_kparam(&kparam, def, paramset)) == 0) {
+ ret = set_ret = kparam.set(val, &kparam);
+ pdebug("n=\"%s\" v=\"%s\" arg=%p set=%p is_dfl=%d ret=%d\n",
+ kparam.name, val, kparam.arg, kparam.set, is_dfl, ret);
+ }
+ release_kparam(&kparam, def);
+
+ if (is_dfl) {
+ if (set_ret < 0)
+ printk(KERN_ERR "Device params: default parameter `%s' "
+ "failed for parameter `%s' with error code %d, "
+ "please report to the maintainer\n",
+ def->dfl, kparam.name, set_ret);
+ if (def->copy_dfl)
+ kfree(val);
+ }
+
+ return ret;
+}
+
+static int parse_one_devparam(const char *full_param, char *param, char *val,
+ struct device_driver *drv, int **cursors,
+ struct device *dev, long **bitmaps)
+{
+ char *p, *ns, *no_ns = "";
+ struct device_paramset_def *setdef;
+ struct device_param_def *def;
+ int which, idx, ret;
+ void *ps;
+
+ ns = no_ns;
+ if ((p = strchr(param, '.')) != NULL) {
+ *p++ = '\0';
+ ns = param;
+ param = p;
+ }
+
+ idx = 0; def = NULL; /* to make gcc shut up */
+ for_each_setdef(which, setdef, drv) {
+ if (strcmp(setdef->namespace, ns))
+ continue;
+ for (idx = 0; idx < setdef->nr_defs; idx++) {
+ def = &setdef->defs[idx];
+ if (strcmp(def->kparam.name, param) == 0)
+ goto exit_loop;
+ }
+ }
+ exit_loop:
+ if (ns != no_ns)
+ *--param = '.';
+ if (setdef == NULL)
+ return -ENOENT;
+
+ /* Okay, we have a match */
+ if (dev == NULL) {
+ /* We're storing into one of the driver paramset
+ storage vectors. */
+ ps = vec_elem(&drv->paramset_vecs[which], cursors[which][idx]);
+ if (ps == NULL) {
+ printk(KERN_ERR
+ "Device params: Insufficient memory for "
+ "parameter `%s'\n", full_param);
+ return -ENOMEM;
+ }
+ pdebug("setting drv_vec, which=%d idx=%d cursor=%d\n",
+ which, idx, cursors[which][idx]);
+ } else {
+ /* Set device paramsets directly. */
+ ps = dev->paramsets[which];
+ pdebug("setting directly, which=%d\n", which);
+ }
+
+ ret = call_set(def, val, ps);
+
+ switch (ret) {
+ case 0:
+ if (dev == NULL)
+ cursors[which][idx]++;
+ else
+ set_bit(idx, bitmaps[which]);
+ break;
+ case -ENOSPC:
+ printk(KERN_ERR
+ "Device params: `%s' too large for parameter `%s'\n",
+ val ?: "", full_param);
+ break;
+ case -ERANGE:
+ printk(KERN_ERR
+ "Device params: `%s' out of range for parameter `%s'\n",
+ val ?: "", full_param);
+ break;
+ default:
+ printk(KERN_ERR
+ "Device params: `%s' invalid for parameter `%s'\n",
+ val ?: "", full_param);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Initialization routines
+ */
+int devparam_driver_init(struct device_driver *drv)
+{
+ int nr_paramsets, i, ret;
+ struct devparam_vec *vecs;
+
+ drv->nr_paramsets = nr_paramsets = 0;
+ drv->paramset_bitmap_len = 0;
+ drv->paramset_bitmap = NULL;
+ drv->paramset_vecs = vecs = NULL;
+
+ if (drv->paramset_defs)
+ while (drv->paramset_defs[nr_paramsets])
+ nr_paramsets++;
+ nr_paramsets += drv->bus && drv->bus->paramset_def;
+
+ if (nr_paramsets == 0)
+ return 0;
+
+ vecs = kmalloc(nr_paramsets * sizeof(vecs[0]), GFP_KERNEL);
+ if (vecs == NULL) {
+ printk(KERN_ERR "Failed to allocate paramset vectors "
+ "for driver `%s'\n", drv->name);
+ return -ENOMEM;
+ }
+
+ drv->nr_paramsets = nr_paramsets;
+ drv->paramset_vecs = vecs;
+
+ if (drv->bus && drv->bus->paramset_def) {
+ /* We cheat here and use the terminating NULL element
+ of the driver's paramset_defs if available or make
+ paramset_defs directly point to bus_paramset_def. */
+ if (nr_paramsets == 1)
+ drv->paramset_defs = &drv->bus->paramset_def;
+ else
+ drv->paramset_defs[nr_paramsets - 1] =
+ drv->bus->paramset_def;
+ }
+
+ for (i = 0; i < nr_paramsets; i++) {
+ struct device_paramset_def *setdef = drv->paramset_defs[i];
+
+ /* Theoretically, the setdef could be being used on
+ other processors while we're counting nr_defs, so
+ we cannot directly ++ setdef->nr_defs. */
+ if (setdef->nr_defs == -1) {
+ int nr_defs = 0;
+ while (setdef->defs[nr_defs].kparam.name)
+ nr_defs++;
+ setdef->nr_defs = nr_defs;
+ }
+
+ vec_init(&vecs[i], setdef->size);
+ }
+
+ /* Parse device parameters passed as boot options or module
+ parameters */
+ if ((ret = devparam_parse_modparams(drv)) < 0)
+ devparam_driver_release(drv);
+ return ret;
+}
+
+void devparam_driver_release(struct device_driver *drv)
+{
+ int i;
+
+ kfree(drv->paramset_bitmap);
+
+ for (i = 0; i < drv->nr_paramsets; i++)
+ vec_destroy(&drv->paramset_vecs[i]);
+ kfree(drv->paramset_vecs);
+
+ /* Be nice and restore drv->paramset_defs. */
+ if (drv->bus && drv->bus->paramset_def) {
+ if (drv->nr_paramsets == 1)
+ drv->paramset_defs = NULL;
+ else
+ drv->paramset_defs[drv->nr_paramsets - 1] = NULL;
+ }
+}
+
+/*
+ * Device bootopts
+ */
+int __init devparam_maybe_bootopt(char *param, char *val)
+{
+ if (nr_bootopts >= MAX_DEVICE_BOOTOPTS) {
+ printk(KERN_ERR
+ "Too many device bootopts `%s': ignoring\n", param);
+ return -ENOSPC;
+ }
+
+ bootopts[nr_bootopts][0] = param;
+ bootopts[nr_bootopts][1] = val;
+ nr_bootopts++;
+
+ return 0;
+}
+
+void __init devparam_finish_bootopts(void)
+{
+ int i;
+ for (i = 0; i < nr_bootopts; i++)
+ if (bootopts[i][0])
+ printk(KERN_ERR "Unknown boot option `%s': ignoring\n",
+ bootopts[i][0]);
+ nr_bootopts = 0;
+}
+
+/*
+ * Module parameters
+ */
+#ifdef CONFIG_MODULES
+
+int devparam_module_init(struct module *mod)
+{
+ vec_init(&mod->param_vec, 2 * sizeof(char *));
+ return 0;
+}
+
+int devparam_unknown_modparam(char *name, char *val, void *arg)
+{
+ struct module *mod = arg;
+ char **param;
+
+ param = vec_elem(&mod->param_vec, mod->param_vec.len);
+ if (param == NULL) {
+ printk(KERN_ERR
+ "Device params: Insufficient memory for `%s'\n", name);
+ return -ENOMEM;
+ }
+
+ param[0] = name;
+ param[1] = val;
+
+ return 0;
+}
+
+void devparam_module_done(struct module *mod)
+{
+ struct devparam_vec *vec = &mod->param_vec;
+ int i;
+
+ for (i = 0; i < vec->len; i++) {
+ char **param = vec_elem(vec, i);
+ if (param[0])
+ printk(KERN_ERR
+ "Device params: Unknown parameter `%s'\n",
+ param[0]);
+ }
+
+ vec_destroy(vec);
+}
+
+#endif /* CONFIG_MODULES */
+
+struct modparams_set_arg {
+ char *param;
+ struct device_driver *drv;
+ int **cursors;
+};
+
+static int __init_or_module
+modparams_set(const char *val, struct kernel_param *kp)
+{
+ struct modparams_set_arg *arg = kp->arg;
+
+ return parse_one_devparam(kp->name, arg->param, (char *)val,
+ arg->drv, arg->cursors, NULL, NULL);
+}
+
+static int __init_or_module
+parse_modparams_ar(void *params, int nr_params,
+ char **(*read_fn)(void *params, int idx),
+ struct device_driver *drv)
+{
+ struct device_paramset_def *setdef;
+ int which, **cursors, i, j, len, max_len, ret, err;
+ size_t size;
+
+ /* Allocate cursors */
+ err = -ENOMEM;
+
+ size = drv->nr_paramsets * sizeof(cursors[0]);
+ if (!(cursors = kmalloc(size, GFP_KERNEL)))
+ goto out;
+ memset(cursors, 0, size);
+
+ for_each_setdef(which, setdef, drv) {
+ size = setdef->nr_defs * sizeof(cursors[0][0]);
+ if ((cursors[which] = kmalloc(size, GFP_KERNEL)) == NULL)
+ goto out;
+ memset(cursors[which], 0, size);
+ }
+
+ /* Parse */
+ for (i = 0; i < nr_params; i++) {
+ char **param, *p;
+ struct modparams_set_arg arg;
+ int nr;
+
+ param = read_fn(params, i);
+ if (param[0] == NULL)
+ continue;
+
+ pdebug("parsing %s=\"%s\"\n", param[0], param[1]);
+
+ if (drv->owner == NULL) {
+ if ((p = strchr(param[0], '.')) == NULL)
+ continue;
+ *p = '\0';
+ if (strcmp(param[0], drv->name) != 0) {
+ *p = '.';
+ continue;
+ }
+ *p++ = '.';
+ } else
+ p = param[0];
+
+ arg.param = p;
+ arg.drv = drv;
+ arg.cursors = cursors;
+
+ ret = param_array_delims(param[0], param[1], KPARAM_NO_RANGE,
+ 0, INT_MAX, &arg, 0,
+ modparams_set, &nr, ",");
+ if (ret != -ENOENT)
+ param[0] = NULL;
+ }
+
+ /* Finalize partial paramsets */
+ pdebug("Finalizing...\n");
+ max_len = 0;
+ for_each_setdef(which, setdef, drv) {
+ struct devparam_vec *vec = &drv->paramset_vecs[which];
+
+ for (len = 0, i = 0; i < setdef->nr_defs; i++)
+ len = max(len, cursors[which][i]);
+ max_len = max(len, max_len);
+
+ for (i = 0; i < setdef->nr_defs; i++) {
+ struct device_param_def *def = &setdef->defs[i];
+
+ if (def->dfl == NULL)
+ continue;
+
+ for (j = cursors[which][i]; j < len; j++) {
+ void *ps;
+
+ ps = vec_elem(vec, j);
+ if (ps == NULL)
+ goto out;
+
+ pdebug("setting which=%d idx=%d cursor=%d\n",
+ which, i, j);
+
+ if ((ret = call_set(def, NULL, ps)) < 0) {
+ err = ret;
+ goto out;
+ }
+ }
+ }
+
+ /* Trim vector */
+ vec_set_len(vec, len);
+ }
+
+ /* Create paramset bitmap */
+ pdebug("Creating paramset bitmap, max_len=%d\n", max_len);
+ if (max_len) {
+ unsigned long *bitmap;
+ int nbits = (max_len + BITS_PER_LONG-1) & ~(BITS_PER_LONG-1);
+
+ if ((bitmap = kmalloc(nbits / 8, GFP_KERNEL)) == NULL)
+ goto out;
+ memset(bitmap, 0, nbits / 8);
+
+ drv->paramset_bitmap = bitmap;
+ drv->paramset_bitmap_len = max_len;
+ }
+
+ err = 0;
+
+ out:
+ if (cursors) {
+ for (i = 0; i < drv->nr_paramsets; i++)
+ kfree(cursors[i]);
+ kfree(cursors);
+ }
+
+ return err;
+}
+
+static char ** __init read_bootopt(void *arg, int idx)
+{
+ char *(*params)[2] = arg;
+ return params[idx];
+}
+
+static char ** read_modparam(void *arg, int idx)
+{
+ return vec_elem(arg, idx);
+}
+
+static int devparam_parse_modparams(struct device_driver *drv)
+{
+ char **(*read_fn)(void *, int) = NULL;
+ void *params;
+ int len;
+
+ pdebug("parsing parameters for driver \"%s\", mod=%p\n",
+ drv->name, drv->owner);
+
+ if (drv->owner == NULL) {
+ read_fn = read_bootopt;
+ params = bootopts;
+ len = nr_bootopts;
+ } else {
+ read_fn = read_modparam;
+ params = &drv->owner->param_vec;
+ len = drv->owner->param_vec.len;
+ }
+
+ return parse_modparams_ar(params, len, read_fn, drv);
+}
+
+/*
+ * release/sysfs stuff
+ */
+#define kobj_to_dp(k) container_of((k), struct devparam_params, kobj)
+
+static void free_paramsets(void **paramsets, int nr)
+{
+ if (paramsets) {
+ int i;
+ for (i = 0; i < nr; i++)
+ kfree(paramsets[i]);
+ kfree(paramsets);
+ }
+}
+
+static void dp_release(struct kobject *kobj)
+{
+ struct devparam_params *dp = kobj_to_dp(kobj);
+
+ free_paramsets(dp->paramsets, dp->drv->nr_paramsets);
+ kfree(dp);
+}
+
+static ssize_t dp_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct devparam_params *dp = kobj_to_dp(kobj);
+ struct device_paramset_def *setdef;
+ int idx, which, ret;
+
+ idx = attr - dp->attrs;
+ setdef = get_setdef_by_idx(&idx, &which, dp->drv);
+
+ ret = call_get(&setdef->defs[idx], buf, dp->paramsets[which]);
+ if (ret > 0)
+ buf[ret++] = '\n';
+ return ret;
+}
+
+static ssize_t dp_store(struct kobject *kobj, struct attribute *attr,
+ const char *val, size_t len)
+{
+ struct devparam_params *dp = kobj_to_dp(kobj);
+ struct device_paramset_def *setdef;
+ int idx, which, ret;
+
+ idx = attr - dp->attrs;
+ setdef = get_setdef_by_idx(&idx, &which, dp->drv);
+
+ ret = call_set(&setdef->defs[idx], (char *)val, dp->paramsets[which]);
+ return ret == 0 ? len : ret;
+}
+
+static struct sysfs_ops dp_sysfs_ops = {
+ .show = dp_show,
+ .store = dp_store
+};
+
+static struct kobj_type dp_ktype = {
+ .release = dp_release,
+ .sysfs_ops = &dp_sysfs_ops
+};
+
+static void unregister_devparams(struct device *dev)
+{
+ struct devparam_params *dp = dev->params;
+ int i;
+
+ for (i = 0; i < dp->nr_attrs; i++)
+ if (dp->attrs[i].name)
+ sysfs_remove_file(&dp->kobj, &dp->attrs[i]);
+ kobject_unregister(&dp->kobj);
+}
+
+static int register_devparams(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ struct devparam_params *dp;
+ struct device_paramset_def *setdef;
+ int nr_attrs, idx, which, ret;
+ size_t size;
+
+ nr_attrs = INT_MAX;
+ get_setdef_by_idx(&nr_attrs, &which, drv);
+ nr_attrs = INT_MAX - nr_attrs;
+
+ size = sizeof(*dp) + nr_attrs * sizeof(dp->attrs[0]);
+ ret = -ENOMEM;
+ if ((dp = kmalloc(size, GFP_KERNEL)) == NULL)
+ goto free_out;
+ memset(dp, 0, size);
+
+ dev->params = dp;
+
+ if ((ret = kobject_set_name(&dp->kobj, "parameters")))
+ goto free_out;
+ dp->kobj.parent = &dev->kobj;
+ dp->kobj.ktype = &dp_ktype;
+ dp->drv = drv;
+ dp->paramsets = dev->paramsets;
+ dp->nr_attrs = nr_attrs;
+
+ if ((ret = kobject_register(&dp->kobj)))
+ goto free_out;
+
+ idx = 0;
+ for_each_setdef(which, setdef, drv) {
+ int i;
+ for (i = 0; i < setdef->nr_defs; i++) {
+ struct device_param_def *def = &setdef->defs[i];
+ struct attribute *attr = &dp->attrs[idx++];
+
+ if (def->kparam.perm == 0)
+ continue;
+
+ attr->name = (char *)def->kparam.name;
+ attr->owner = dev->driver->owner;
+ attr->mode = def->kparam.perm;
+
+ if ((ret = sysfs_create_file(&dp->kobj, attr))) {
+ attr->name = NULL;
+ goto unregister_out;
+ }
+ }
+ }
+
+ return 0;
+
+ free_out:
+ kfree(dp);
+ free_paramsets(dev->paramsets, drv->nr_paramsets);
+ return ret;
+
+ unregister_out:
+ unregister_devparams(dev);
+ return ret;
+}
+
+/*
+ * devparam_set_params()
+ */
+static int set_devparams_by_storedparams(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int which, idx, len;
+ struct device_paramset_def *setdef;
+
+ /* Determine device bootopt index */
+ len = drv->paramset_bitmap_len;
+ idx = find_first_zero_bit(drv->paramset_bitmap, len);
+
+ /* Allocate & copy paramsets */
+ for_each_setdef(which, setdef, drv) {
+ struct devparam_vec *vec = &drv->paramset_vecs[which];
+ void *ps = dev->paramsets[which];
+
+ if (idx < vec->len)
+ memcpy(ps, vec_elem(vec, idx), setdef->size);
+ else {
+ int i, ret;
+ for (i = 0; i < setdef->nr_defs; i++) {
+ ret = call_set(&setdef->defs[i], NULL, ps);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
+ if (idx < len) {
+ dev->paramset_idx = idx;
+ set_bit(idx, drv->paramset_bitmap);
+ }
+
+ pdebug("using param @ idx=%d (len=%d)\n", idx, len);
+
+ return 0;
+}
+
+int devparam_set_params(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ size_t size;
+ int which, ret;
+ struct device_paramset_def *setdef;
+
+ pdebug("invoked for %s\n", drv->name);
+
+ dev->paramsets = NULL;
+ dev->bus_paramset = NULL;
+ dev->paramset_idx = -1;
+
+ if (drv->nr_paramsets == 0)
+ return 0;
+
+ size = drv->nr_paramsets * sizeof(void *);
+ if ((dev->paramsets = kmalloc(size, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(dev->paramsets, 0, size);
+
+ for_each_setdef(which, setdef, drv) {
+ void *ps;
+ if ((ps = kmalloc(setdef->size, GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto free_out;
+ }
+ memset(ps, 0, setdef->size);
+ dev->paramsets[which] = ps;
+ }
+
+ if ((ret = set_devparams_by_storedparams(dev)) < 0)
+ goto free_out;
+
+ if (drv->bus && drv->bus->paramset_def)
+ dev->bus_paramset = dev->paramsets[drv->nr_paramsets-1];
+
+ return register_devparams(dev);
+
+ free_out:
+ free_paramsets(dev->paramsets, drv->nr_paramsets);
+ return ret;
+}
+
+void devparam_release_params(struct device *dev)
+{
+ pdebug("%s: dev->params=%p paramset_idx=%d\n",
+ dev->driver->name, dev->params, dev->paramset_idx);
+
+ if (dev->driver->nr_paramsets && dev->params) {
+ if (dev->paramset_idx >= 0)
+ clear_bit(dev->paramset_idx,
+ dev->driver->paramset_bitmap);
+ unregister_devparams(dev);
+ }
+}
Index: linux-export/include/linux/device.h
===================================================================
--- linux-export.orig/include/linux/device.h 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/include/linux/device.h 2004-11-04 14:48:43.000000000 +0900
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pm.h>
+#include <linux/deviceparam.h>
#include <asm/semaphore.h>
#include <asm/atomic.h>
@@ -57,6 +58,7 @@ struct bus_type {
struct bus_attribute * bus_attrs;
struct device_attribute * dev_attrs;
struct driver_attribute * drv_attrs;
+ struct device_paramset_def * paramset_def;
int (*match)(struct device * dev, struct device_driver * drv);
int (*hotplug) (struct device *dev, char **envp,
@@ -105,6 +107,13 @@ struct device_driver {
struct semaphore unload_sem;
struct kobject kobj;
struct list_head devices;
+ struct device_paramset_def ** paramset_defs;
+
+ /* The following fields are initialized automatically by
+ devparam_driver_init() when registering the driver */
+ int nr_paramsets, paramset_bitmap_len;
+ unsigned long * paramset_bitmap;
+ struct devparam_vec * paramset_vecs;
struct module * owner;
@@ -267,6 +276,12 @@ struct device {
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data (e.g. ACPI,
BIOS data relevant to device) */
+
+ void **paramsets; /* device paramsets */
+ void *bus_paramset; /* bus paramset */
+ int paramset_idx; /* devparam bookkeeping */
+ struct devparam_params *params; /* devparam sysfs subdirectory */
+
struct dev_pm_info power;
u32 power_state; /* Current operating state. In
ACPI-speak, this is D0-D3, D0
Index: linux-export/include/linux/deviceparam.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-export/include/linux/deviceparam.h 2004-11-04 14:48:43.000000000 +0900
@@ -0,0 +1,226 @@
+/*
+ * deviceparam.h - per-device bus/driver parameter
+ *
+ * Copyright (C) 2004 Tejun Heo <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Read Documentation/driver-model/devparam.txt for details.
+ */
+
+#ifndef __LINUX_DEVICEPARAM_H
+#define __LINUX_DEVICEPARAM_H
+
+#include <linux/moduleparam.h>
+#include <linux/kobject.h>
+
+/* Vector type used by devparam, exported due to its usage in struct module */
+struct devparam_vec {
+ void **ar;
+ int ar_len, len, elem_size;
+};
+
+/* Parameters structure for struct device */
+struct devparam_params {
+ struct kobject kobj; /* kobject for parameters subdir */
+ struct device_driver *drv;
+ void **paramsets;
+ int nr_attrs;
+ struct attribute attrs[];
+};
+
+/* Paramset definition related */
+struct device_paramset_def;
+
+struct device_param_def {
+ const struct kernel_param kparam;
+ const char *dfl;
+ const int copy_dfl, arg_copy_size;
+ const int arg_fixups[3 * 2]; /* enough for now */
+};
+
+struct device_paramset_def {
+ size_t size;
+ const char *namespace;
+ int nr_defs;
+ struct device_param_def defs[];
+};
+
+#define __devparam_cat1(a, b) a##b
+#define __devparam_cat(a, b) __devparam_cat1(a, b)
+#define __devparam_type __devparam_cat(__DEVPARAM_TYPE_, __LINE__)
+#define __devparam_data(n) __devparam_cat(__DEVPARAM_DATA_##n##_, __LINE__)
+#define __devparam_dataend __devparam_cat(__DEVPARAM_DATAEND_, __LINE__)
+
+/* For some reason, gcc aligns structures which contain other
+ structures to 32-byte boundary even when __alignof__() the strucure
+ is smaller than that. As we're gonna assemble paramset array
+ manually, we need to set alignment explicitly. Also, we put all
+ paramset array elements into .data.1 to avoid intervening variables
+ of different types (kparam_string, kparam_array for now). */
+#define __devparam_section __attribute__((section(".data.1")))
+#define __devparam_extra_section /* empty */
+#define __devparam_decl(n) \
+ static struct device_param_def n __devparam_section \
+ __attribute__((unused, aligned(__alignof__(sizeof(void *)))))
+
+#define DEFINE_DEVICE_PARAMSET_NS(Name, Type, Namespace, Defs...) \
+ struct device_paramset_def Name __devparam_section = { \
+ .size = sizeof(Type), \
+ .namespace = Namespace, \
+ .nr_defs = -1 \
+ }; \
+ typedef Type __devparam_type; \
+ Defs \
+ __devparam_decl(__devparam_dataend) = { \
+ .dfl = "end" \
+ }
+
+#define DEFINE_DEVICE_PARAMSET(Name, Type, Defs...) \
+ DEFINE_DEVICE_PARAMSET_NS(Name, Type, "", Defs)
+
+/* DEVICE_PARAM_CALL's */
+#define __DEVICE_PARAM_CALL(Name, Set, Get, Arg, Argcopysize, Min, Max, \
+ Dfl, Copydfl, Perm, Desc, Fixups...) \
+ __devparam_decl(__devparam_data(Name)) = { \
+ .kparam = { \
+ .name = #Name, \
+ .perm = Perm, \
+ .set = Set, \
+ .get = Get, \
+ .arg = Arg, \
+ .min = Min, \
+ .max = Max \
+ }, \
+ .dfl = Dfl, \
+ .copy_dfl = Copydfl, \
+ .arg_copy_size = Argcopysize, \
+ .arg_fixups = { Fixups } \
+ }; \
+ MODULE_DEVPARM_DESC(Name, Desc);
+
+#define DEVICE_PARAM_CALL_RANGED(Name, Set, Get, Field, Min, Max, Dfl, \
+ Perm, Desc) \
+ __DEVICE_PARAM_CALL(Name, Set, Get, NULL, 0, Min, Max, Dfl, 0, \
+ Perm, Desc, -1, offsetof(__devparam_type, Field), -1, -1)
+
+#define DEVICE_PARAM_CALL(Name, Set, Get, Field, Dfl, Perm, Desc) \
+ DEVICE_PARAM_CALL_RANGED(Name, Set, Get, Field, 1, 0, Dfl, Perm, Desc)
+
+/* Standard params */
+#define DEVICE_PARAM_NAMED_RANGED(Name, Field, Type, Min, Max, Dfl, Perm, Desc)\
+ param_check_##Type(__devparam_data(Name), \
+ &(((__devparam_type *)0)->Field)); \
+ DEVICE_PARAM_CALL_RANGED(Name, param_set_##Type, param_get_##Type,\
+ Field, Min, Max, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_RANGED(Name, Type, Min, Max, Dfl, Perm, Desc) \
+ DEVICE_PARAM_NAMED_RANGED(Name, Name, Type, Min, Max, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_NAMED(Name, Field, Type, Dfl, Perm, Desc) \
+ DEVICE_PARAM_NAMED_RANGED(Name, Field, Type, 1, 0, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM(Name, Type, Dfl, Perm, Desc) \
+ DEVICE_PARAM_NAMED(Name, Name, Type, Dfl, Perm, Desc)
+
+/* String */
+#define DEVICE_PARAM_STRING_NAMED(Name, Field, Len, Dfl, Perm, Desc) \
+ DEVICE_PARAM_CALL_RANGED(Name, param_set_copystring, param_get_string,\
+ Field, 0, Len, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_STRING(Name, Dfl, Perm, Desc) \
+ DEVICE_PARAM_STRING_NAMED(Name, Name, \
+ sizeof(((__devparam_type *)0)->Name), \
+ Dfl, Perm, Desc)
+
+/* Bit flag */
+#define __DEVICE_PARAM_FLAG(Name, Field, Flag, Dfl, Inv, Perm, Desc) \
+ param_check_uint(__devparam_data(Name), \
+ &(((__devparam_type *)0)->Field)); \
+ static struct kparam_flag __devparam_data(__param_flag_##Name) \
+ __devparam_extra_section = { 0, Flag, Inv }; \
+ __DEVICE_PARAM_CALL(Name, param_set_flag, param_get_flag, \
+ &__devparam_data(__param_flag_##Name), \
+ sizeof(struct kparam_flag), 1, 0, Dfl, 0, Perm, Desc, \
+ offsetof(struct kparam_flag, pflags), \
+ offsetof(__devparam_type, Field), -1, -1)
+
+#define DEVICE_PARAM_FLAG(Name, Field, Flag, Dfl, Perm, Desc) \
+ __DEVICE_PARAM_FLAG(Name, Field, Flag, Dfl, 0, Perm, Desc)
+
+#define DEVICE_PARAM_INVFLAG(Name, Field, Flag, Dfl, Perm, Desc) \
+ __DEVICE_PARAM_FLAG(Name, Field, Flag, Dfl, 1, Perm, Desc)
+
+/* Array */
+#define __DEVICE_PARAM_ARRAY(Name, ArrField, Type, NumOffset, Min, Max, \
+ Dfl, Perm, Desc) \
+ static struct kparam_array __devparam_data(__param_arr_##Name) \
+ __devparam_extra_section = { \
+ ARRAY_SIZE(((__devparam_type *)0)->ArrField), 0, \
+ param_set_##Type, param_get_##Type, \
+ sizeof(((__devparam_type *)0)->ArrField[0]), 0 \
+ }; \
+ __DEVICE_PARAM_CALL(Name, param_array_set, param_array_get, \
+ &__devparam_data(__param_arr_##Name), \
+ sizeof(struct kparam_array), Min, Max, Dfl, 1, Perm, Desc,\
+ offsetof(struct kparam_array, elem), \
+ offsetof(__devparam_type, ArrField), \
+ offsetof(struct kparam_array, num), \
+ NumOffset, -1, -1)
+
+#define DEVICE_PARAM_ARRAY_NAMED_RANGED(Name, ArrField, Type, NumField, \
+ Min, Max, Dfl, Perm, Desc) \
+ __DEVICE_PARAM_ARRAY(Name, ArrField, Type, \
+ offsetof(__devparam_type, NumField), \
+ Min, Max, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_ARRAY_RANGED(Name, Type, NumField, Min, Max, Dfl, \
+ Perm, Desc) \
+ DEVICE_PARAM_ARRAY_NAMED_RANGED(Name, Name, Type, NumField, \
+ Min, Max, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_ARRAY_NAMED(Name, ArrField, Type, NumField, Dfl, \
+ Perm, Desc) \
+ DEVICE_PARAM_ARRAY_NAMED_RANGED(Name, ArrField, Type, NumField, \
+ 1, 0, Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_ARRAY(Name, Type, NumField, Dfl, Perm, Desc) \
+ DEVICE_PARAM_ARRAY_NAMED(Name, Name, Type, NumField, Dfl, Perm, Desc)
+
+/* Array without len */
+
+#define DEVICE_PARAM_ARR_NAMED_RANGED(Name, ArrField, Type, Min, Max, \
+ Dfl, Perm, Desc) \
+ __DEVICE_PARAM_ARRAY(Name, ArrField, Type, -1, Min, Max, \
+ Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_ARR_RANGED(Name, Type, Min, Max, Dfl, Perm, Desc) \
+ DEVICE_PARAM_ARR_NAMED_RANGED(Name, Name, Type, Min, Max, \
+ Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_ARR_NAMED(Name, ArrField, Type, Dfl, Perm, Desc) \
+ DEVICE_PARAM_ARR_NAMED_RANGED(Name, ArrField, Type, 1, 0, \
+ Dfl, Perm, Desc)
+
+#define DEVICE_PARAM_ARR(Name, Type, Dfl, Perm, Desc) \
+ DEVICE_PARAM_ARR_NAMED(Name, Name, Type, Dfl, Perm, Desc)
+
+struct bus_type;
+struct device_driver;
+struct device;
+struct module;
+
+int devparam_driver_init(struct device_driver *drv);
+void devparam_driver_release(struct device_driver *drv);
+
+int devparam_maybe_bootopt(char *param, char *val);
+void devparam_finish_bootopts(void);
+
+int devparam_module_init(struct module *module);
+int devparam_unknown_modparam(char *name, char *val, void *arg);
+void devparam_module_done(struct module *module);
+
+int devparam_set_params(struct device *dev);
+void devparam_release_params(struct device *dev);
+
+#endif /*__LINUX_DEVICEPARAM_H*/
Index: linux-export/include/linux/module.h
===================================================================
--- linux-export.orig/include/linux/module.h 2004-11-04 10:25:58.000000000 +0900
+++ linux-export/include/linux/module.h 2004-11-04 14:48:43.000000000 +0900
@@ -18,6 +18,7 @@
#include <linux/stringify.h>
#include <linux/kobject.h>
#include <linux/moduleparam.h>
+#include <linux/deviceparam.h>
#include <asm/local.h>
#include <asm/module.h>
@@ -142,6 +143,9 @@ extern struct module __this_module;
#define MODULE_PARM_DESC(_parm, desc) \
__MODULE_INFO(parm, _parm, #_parm ":" desc)
+#define MODULE_DEVPARM_DESC(_parm, desc) \
+ __MODULE_INFO(devparm, _parm, #_parm ":" desc)
+
#define MODULE_DEVICE_TABLE(type,name) \
MODULE_GENERIC_TABLE(type##_device,name)
@@ -321,6 +325,9 @@ struct module
/* The command line arguments (may be mangled). People like
keeping pointers to this stuff */
char *args;
+
+ /* Module parameter vector, used by deviceparam */
+ struct devparam_vec param_vec;
};
/* FIXME: It'd be nice to isolate modules during init, too, so they
dp_10_module_param_arr.patch
This is the 10th patch of 15 patches for devparam.
The unsigned int * @nump of module_param_array is changed back to
unsigned int @num, and new sets of macros named module_param_arr*()
are added. These new macros don't take the num argument. This change
is made for two reasons
1. To be consistent with devparam macros. In devparam, we'll be
using field name of struct elements, so we won't be able to use
pointer argument.
2. It's more consistent with other moduleparam macros.
This patch only modifies moduleparam.h and doesn't modify the users
of the modified macros. The next patch takes care of that.
Signed-off-by: Tejun Heo <[email protected]>
Index: linux-export/include/linux/moduleparam.h
===================================================================
--- linux-export.orig/include/linux/moduleparam.h 2004-11-04 14:25:59.000000000 +0900
+++ linux-export/include/linux/moduleparam.h 2004-11-04 14:25:59.000000000 +0900
@@ -163,22 +163,39 @@ extern int param_set_invbool(const char
extern int param_get_invbool(char *buffer, struct kernel_param *kp);
#define param_check_invbool(name, p) __param_check(name, p, int)
-/* Comma-separated array: *nump is set to number they actually specified. */
-#define module_param_array_named_ranged(name, array, type, nump, min, max, perm)\
+/* Array fundamental function */
+#define __module_param_array(name, array, type, nump, min, max, perm) \
static struct kparam_array __param_arr_##name \
= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
sizeof(array[0]), array }; \
module_param_call_ranged(name, param_array_set, param_array_get,\
&__param_arr_##name, min, max, perm)
-#define module_param_array_ranged(name, type, nump, min, max, perm) \
- module_param_array_named_ranged(name, name, type, nump, min, max, perm)
+/* Comma-separated array: num is set to number they actually specified. */
+#define module_param_array_named_ranged(name, array, type, num, min, max, perm)\
+ __module_param_array(name, array, type, &(num), min, max, perm)
-#define module_param_array_named(name, array, type, nump, perm) \
- module_param_array_named_ranged(name, array, type, nump, 1, 0, perm)
+#define module_param_array_ranged(name, type, num, min, max, perm) \
+ module_param_array_named_ranged(name, name, type, num, min, max, perm)
-#define module_param_array(name, type, nump, perm) \
- module_param_array_named(name, name, type, nump, perm)
+#define module_param_array_named(name, array, type, num, perm) \
+ module_param_array_named_ranged(name, array, type, num, 1, 0, perm)
+
+#define module_param_array(name, type, num, perm) \
+ module_param_array_named(name, name, type, num, perm)
+
+/* Comma-separated array without len. */
+#define module_param_arr_named_ranged(name, array, type, min, max, perm)\
+ __module_param_array(name, array, type, NULL, min, max, perm)
+
+#define module_param_arr_ranged(name, type, min, max, perm) \
+ module_param_arr_named_ranged(name, name, type, min, max, perm)
+
+#define module_param_arr_named(name, array, type, perm) \
+ module_param_arr_named_ranged(name, array, type, 1, 0, perm)
+
+#define module_param_arr(name, type, perm) \
+ module_param_arr_named(name, name, type, perm)
extern int param_array_set(const char *val, struct kernel_param *kp);
extern int param_array_get(char *buffer, struct kernel_param *kp);
dp_11_module_param_arr_apply.patch
This is the 11th patch of 15 patches for devparam.
Applies module_param_array/arr() changes. As this patch is quite
large and mundane, I'll post only the URL here.
Signed-off-by: Tejun Heo <[email protected]>
http://home-tj.org/devparam/20041104/dp_11_module_param_arr_apply.patch