mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
Driver core changes for 6.6-rc1
Here is a small set of driver core updates and additions for 6.6-rc1. Included in here are: - stable kernel documentation updates - class structure const work from Ivan on various subsystems - kernfs tweaks - driver core tests! - kobject sanity cleanups - kobject structure reordering to save space - driver core error code handling fixups - other minor driver core cleanups All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZPH77Q8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylZMACePk8SitfaJc6FfFf5I7YK7Nq0V8MAn0nUjgsR i8NcNpu/Yv4HGrDgTdh/ =PJbk -----END PGP SIGNATURE----- Merge tag 'driver-core-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is a small set of driver core updates and additions for 6.6-rc1. Included in here are: - stable kernel documentation updates - class structure const work from Ivan on various subsystems - kernfs tweaks - driver core tests! - kobject sanity cleanups - kobject structure reordering to save space - driver core error code handling fixups - other minor driver core cleanups All of these have been in linux-next for a while with no reported problems" * tag 'driver-core-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (32 commits) driver core: Call in reversed order in device_platform_notify_remove() driver core: Return proper error code when dev_set_name() fails kobject: Remove redundant checks for whether ktype is NULL kobject: Add sanity check for kset->kobj.ktype in kset_register() drivers: base: test: Add missing MODULE_* macros to root device tests drivers: base: test: Add missing MODULE_* macros for platform devices tests drivers: base: Free devm resources when unregistering a device drivers: base: Add basic devm tests for platform devices drivers: base: Add basic devm tests for root devices kernfs: fix missing kernfs_iattr_rwsem locking docs: stable-kernel-rules: mention that regressions must be prevented docs: stable-kernel-rules: fine-tune various details docs: stable-kernel-rules: make the examples for option 1 a proper list docs: stable-kernel-rules: move text around to improve flow docs: stable-kernel-rules: improve structure by changing headlines base/node: Remove duplicated include kernfs: attach uuid for every kernfs and report it in fsid kernfs: add stub helper for kernfs_generic_poll() x86/resctrl: make pseudo_lock_class a static const structure x86/MSR: make msr_class a static const structure ...
This commit is contained in:
commit
28a4f91f5f
@ -6,30 +6,29 @@ Everything you ever wanted to know about Linux -stable releases
|
||||
Rules on what kind of patches are accepted, and which ones are not, into the
|
||||
"-stable" tree:
|
||||
|
||||
- It or an equivalent fix must already exist in Linus' tree (upstream).
|
||||
- It must be obviously correct and tested.
|
||||
- It cannot be bigger than 100 lines, with context.
|
||||
- It must fix only one thing.
|
||||
- It must fix a real bug that bothers people (not a, "This could be a
|
||||
problem..." type thing).
|
||||
- It must fix a problem that causes a build error (but not for things
|
||||
marked CONFIG_BROKEN), an oops, a hang, data corruption, a real
|
||||
security issue, or some "oh, that's not good" issue. In short, something
|
||||
critical.
|
||||
- Serious issues as reported by a user of a distribution kernel may also
|
||||
be considered if they fix a notable performance or interactivity issue.
|
||||
As these fixes are not as obvious and have a higher risk of a subtle
|
||||
regression they should only be submitted by a distribution kernel
|
||||
maintainer and include an addendum linking to a bugzilla entry if it
|
||||
exists and additional information on the user-visible impact.
|
||||
- New device IDs and quirks are also accepted.
|
||||
- No "theoretical race condition" issues, unless an explanation of how the
|
||||
race can be exploited is also provided.
|
||||
- It cannot contain any "trivial" fixes in it (spelling changes,
|
||||
whitespace cleanups, etc).
|
||||
- It must follow the
|
||||
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
|
||||
rules.
|
||||
- It or an equivalent fix must already exist in Linus' tree (upstream).
|
||||
- It must either fix a real bug that bothers people or just add a device ID.
|
||||
To elaborate on the former:
|
||||
|
||||
- It fixes a problem like an oops, a hang, data corruption, a real security
|
||||
issue, a hardware quirk, a build error (but not for things marked
|
||||
CONFIG_BROKEN), or some "oh, that's not good" issue.
|
||||
- Serious issues as reported by a user of a distribution kernel may also
|
||||
be considered if they fix a notable performance or interactivity issue.
|
||||
As these fixes are not as obvious and have a higher risk of a subtle
|
||||
regression they should only be submitted by a distribution kernel
|
||||
maintainer and include an addendum linking to a bugzilla entry if it
|
||||
exists and additional information on the user-visible impact.
|
||||
- No "This could be a problem..." type of things like a "theoretical race
|
||||
condition", unless an explanation of how the bug can be exploited is also
|
||||
provided.
|
||||
- No "trivial" fixes without benefit for users (spelling changes, whitespace
|
||||
cleanups, etc).
|
||||
|
||||
|
||||
Procedure for submitting patches to the -stable tree
|
||||
@ -41,32 +40,106 @@ Procedure for submitting patches to the -stable tree
|
||||
process but should follow the procedures in
|
||||
:ref:`Documentation/process/security-bugs.rst <securitybugs>`.
|
||||
|
||||
For all other submissions, choose one of the following procedures
|
||||
-----------------------------------------------------------------
|
||||
There are three options to submit a change to -stable trees:
|
||||
|
||||
1. Add a 'stable tag' to the description of a patch you then submit for
|
||||
mainline inclusion.
|
||||
2. Ask the stable team to pick up a patch already mainlined.
|
||||
3. Submit a patch to the stable team that is equivalent to a change already
|
||||
mainlined.
|
||||
|
||||
The sections below describe each of the options in more detail.
|
||||
|
||||
:ref:`option_1` is **strongly** preferred, it is the easiest and most common.
|
||||
:ref:`option_2` is mainly meant for changes where backporting was not considered
|
||||
at the time of submission. :ref:`option_3` is an alternative to the two earlier
|
||||
options for cases where a mainlined patch needs adjustments to apply in older
|
||||
series (for example due to API changes).
|
||||
|
||||
When using option 2 or 3 you can ask for your change to be included in specific
|
||||
stable series. When doing so, ensure the fix or an equivalent is applicable,
|
||||
submitted, or already present in all newer stable trees still supported. This is
|
||||
meant to prevent regressions that users might later encounter on updating, if
|
||||
e.g. a fix merged for 5.19-rc1 would be backported to 5.10.y, but not to 5.15.y.
|
||||
|
||||
.. _option_1:
|
||||
|
||||
Option 1
|
||||
********
|
||||
|
||||
To have the patch automatically included in the stable tree, add the tag
|
||||
To have a patch you submit for mainline inclusion later automatically picked up
|
||||
for stable trees, add the tag
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
|
||||
in the sign-off area. Once the patch is merged it will be applied to
|
||||
the stable tree without anything else needing to be done by the author
|
||||
or subsystem maintainer.
|
||||
in the sign-off area. Once the patch is mainlined it will be applied to the
|
||||
stable tree without anything else needing to be done by the author or
|
||||
subsystem maintainer.
|
||||
|
||||
To sent additional instructions to the stable team, use a shell-style inline
|
||||
comment:
|
||||
|
||||
* To specify any additional patch prerequisites for cherry picking use the
|
||||
following format in the sign-off area:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x
|
||||
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||
|
||||
The tag sequence has the meaning of:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
git cherry-pick a1f84a3
|
||||
git cherry-pick 1b9508f
|
||||
git cherry-pick fd21073
|
||||
git cherry-pick <this commit>
|
||||
|
||||
* For patches that may have kernel version prerequisites specify them using
|
||||
the following format in the sign-off area:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x
|
||||
|
||||
The tag has the meaning of:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
git cherry-pick <this commit>
|
||||
|
||||
For each "-stable" tree starting with the specified version.
|
||||
|
||||
Note, such tagging is unnecessary if the stable team can derive the
|
||||
appropriate versions from Fixes: tags.
|
||||
|
||||
* To delay pick up of patches, use the following format:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: <stable@vger.kernel.org> # after 4 weeks in mainline
|
||||
|
||||
* For any other requests, just add a note to the stable tag. This for example
|
||||
can be used to point out known problems:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: <stable@vger.kernel.org> # see patch description, needs adjustments for <= 6.3
|
||||
|
||||
.. _option_2:
|
||||
|
||||
Option 2
|
||||
********
|
||||
|
||||
After the patch has been merged to Linus' tree, send an email to
|
||||
If the patch already has been merged to mainline, send an email to
|
||||
stable@vger.kernel.org containing the subject of the patch, the commit ID,
|
||||
why you think it should be applied, and what kernel version you wish it to
|
||||
why you think it should be applied, and what kernel versions you wish it to
|
||||
be applied to.
|
||||
|
||||
.. _option_3:
|
||||
@ -75,23 +148,9 @@ Option 3
|
||||
********
|
||||
|
||||
Send the patch, after verifying that it follows the above rules, to
|
||||
stable@vger.kernel.org. You must note the upstream commit ID in the
|
||||
changelog of your submission, as well as the kernel version you wish
|
||||
it to be applied to.
|
||||
|
||||
:ref:`option_1` is **strongly** preferred, is the easiest and most common.
|
||||
:ref:`option_2` and :ref:`option_3` are more useful if the patch isn't deemed
|
||||
worthy at the time it is applied to a public git tree (for instance, because
|
||||
it deserves more regression testing first). :ref:`option_3` is especially
|
||||
useful if the original upstream patch needs to be backported (for example
|
||||
the backport needs some special handling due to e.g. API changes).
|
||||
|
||||
Note that for :ref:`option_3`, if the patch deviates from the original
|
||||
upstream patch (for example because it had to be backported) this must be very
|
||||
clearly documented and justified in the patch description.
|
||||
|
||||
The upstream commit ID must be specified with a separate line above the commit
|
||||
text, like this:
|
||||
stable@vger.kernel.org and mention the kernel versions you wish it to be applied
|
||||
to. When doing so, you must note the upstream commit ID in the changelog of your
|
||||
submission with a separate line above the commit text, like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
@ -103,49 +162,20 @@ or alternatively:
|
||||
|
||||
[ Upstream commit <sha1> ]
|
||||
|
||||
Additionally, some patches submitted via :ref:`option_1` may have additional
|
||||
patch prerequisites which can be cherry-picked. This can be specified in the
|
||||
following format in the sign-off area:
|
||||
If the submitted patch deviates from the original upstream patch (for example
|
||||
because it had to be adjusted for the older API), this must be very clearly
|
||||
documented and justified in the patch description.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x
|
||||
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||
Following the submission
|
||||
------------------------
|
||||
|
||||
The tag sequence has the meaning of:
|
||||
The sender will receive an ACK when the patch has been accepted into the
|
||||
queue, or a NAK if the patch is rejected. This response might take a few
|
||||
days, according to the schedules of the stable team members.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
git cherry-pick a1f84a3
|
||||
git cherry-pick 1b9508f
|
||||
git cherry-pick fd21073
|
||||
git cherry-pick <this commit>
|
||||
|
||||
Also, some patches may have kernel version prerequisites. This can be
|
||||
specified in the following format in the sign-off area:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x
|
||||
|
||||
The tag has the meaning of:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
git cherry-pick <this commit>
|
||||
|
||||
For each "-stable" tree starting with the specified version.
|
||||
|
||||
Following the submission:
|
||||
|
||||
- The sender will receive an ACK when the patch has been accepted into the
|
||||
queue, or a NAK if the patch is rejected. This response might take a few
|
||||
days, according to the developer's schedules.
|
||||
- If accepted, the patch will be added to the -stable queue, for review by
|
||||
other developers and by the relevant subsystem maintainer.
|
||||
If accepted, the patch will be added to the -stable queue, for review by other
|
||||
developers and by the relevant subsystem maintainer.
|
||||
|
||||
|
||||
Review cycle
|
||||
@ -174,6 +204,7 @@ Review cycle
|
||||
security kernel team, and not go through the normal review cycle.
|
||||
Contact the kernel security team for more details on this procedure.
|
||||
|
||||
|
||||
Trees
|
||||
-----
|
||||
|
||||
|
@ -45,7 +45,21 @@ static u64 prefetch_disable_bits;
|
||||
*/
|
||||
static unsigned int pseudo_lock_major;
|
||||
static unsigned long pseudo_lock_minor_avail = GENMASK(MINORBITS, 0);
|
||||
static struct class *pseudo_lock_class;
|
||||
|
||||
static char *pseudo_lock_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
const struct rdtgroup *rdtgrp;
|
||||
|
||||
rdtgrp = dev_get_drvdata(dev);
|
||||
if (mode)
|
||||
*mode = 0600;
|
||||
return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdtgrp->kn->name);
|
||||
}
|
||||
|
||||
static const struct class pseudo_lock_class = {
|
||||
.name = "pseudo_lock",
|
||||
.devnode = pseudo_lock_devnode,
|
||||
};
|
||||
|
||||
/**
|
||||
* get_prefetch_disable_bits - prefetch disable bits of supported platforms
|
||||
@ -1353,7 +1367,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
|
||||
&pseudo_measure_fops);
|
||||
}
|
||||
|
||||
dev = device_create(pseudo_lock_class, NULL,
|
||||
dev = device_create(&pseudo_lock_class, NULL,
|
||||
MKDEV(pseudo_lock_major, new_minor),
|
||||
rdtgrp, "%s", rdtgrp->kn->name);
|
||||
|
||||
@ -1383,7 +1397,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
|
||||
goto out;
|
||||
|
||||
out_device:
|
||||
device_destroy(pseudo_lock_class, MKDEV(pseudo_lock_major, new_minor));
|
||||
device_destroy(&pseudo_lock_class, MKDEV(pseudo_lock_major, new_minor));
|
||||
out_debugfs:
|
||||
debugfs_remove_recursive(plr->debugfs_dir);
|
||||
pseudo_lock_minor_release(new_minor);
|
||||
@ -1424,7 +1438,7 @@ void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp)
|
||||
|
||||
pseudo_lock_cstates_relax(plr);
|
||||
debugfs_remove_recursive(rdtgrp->plr->debugfs_dir);
|
||||
device_destroy(pseudo_lock_class, MKDEV(pseudo_lock_major, plr->minor));
|
||||
device_destroy(&pseudo_lock_class, MKDEV(pseudo_lock_major, plr->minor));
|
||||
pseudo_lock_minor_release(plr->minor);
|
||||
|
||||
free:
|
||||
@ -1560,16 +1574,6 @@ static const struct file_operations pseudo_lock_dev_fops = {
|
||||
.mmap = pseudo_lock_dev_mmap,
|
||||
};
|
||||
|
||||
static char *pseudo_lock_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
const struct rdtgroup *rdtgrp;
|
||||
|
||||
rdtgrp = dev_get_drvdata(dev);
|
||||
if (mode)
|
||||
*mode = 0600;
|
||||
return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdtgrp->kn->name);
|
||||
}
|
||||
|
||||
int rdt_pseudo_lock_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -1580,21 +1584,18 @@ int rdt_pseudo_lock_init(void)
|
||||
|
||||
pseudo_lock_major = ret;
|
||||
|
||||
pseudo_lock_class = class_create("pseudo_lock");
|
||||
if (IS_ERR(pseudo_lock_class)) {
|
||||
ret = PTR_ERR(pseudo_lock_class);
|
||||
ret = class_register(&pseudo_lock_class);
|
||||
if (ret) {
|
||||
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pseudo_lock_class->devnode = pseudo_lock_devnode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rdt_pseudo_lock_release(void)
|
||||
{
|
||||
class_destroy(pseudo_lock_class);
|
||||
pseudo_lock_class = NULL;
|
||||
class_unregister(&pseudo_lock_class);
|
||||
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
|
||||
pseudo_lock_major = 0;
|
||||
}
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include <asm/processor.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
static struct class *cpuid_class;
|
||||
static enum cpuhp_state cpuhp_cpuid_state;
|
||||
|
||||
struct cpuid_regs_done {
|
||||
@ -124,26 +123,31 @@ static const struct file_operations cpuid_fops = {
|
||||
.open = cpuid_open,
|
||||
};
|
||||
|
||||
static char *cpuid_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
|
||||
}
|
||||
|
||||
static const struct class cpuid_class = {
|
||||
.name = "cpuid",
|
||||
.devnode = cpuid_devnode,
|
||||
};
|
||||
|
||||
static int cpuid_device_create(unsigned int cpu)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL,
|
||||
dev = device_create(&cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL,
|
||||
"cpu%d", cpu);
|
||||
return PTR_ERR_OR_ZERO(dev);
|
||||
}
|
||||
|
||||
static int cpuid_device_destroy(unsigned int cpu)
|
||||
{
|
||||
device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
|
||||
device_destroy(&cpuid_class, MKDEV(CPUID_MAJOR, cpu));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *cpuid_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
|
||||
}
|
||||
|
||||
static int __init cpuid_init(void)
|
||||
{
|
||||
int err;
|
||||
@ -154,12 +158,9 @@ static int __init cpuid_init(void)
|
||||
CPUID_MAJOR);
|
||||
return -EBUSY;
|
||||
}
|
||||
cpuid_class = class_create("cpuid");
|
||||
if (IS_ERR(cpuid_class)) {
|
||||
err = PTR_ERR(cpuid_class);
|
||||
err = class_register(&cpuid_class);
|
||||
if (err)
|
||||
goto out_chrdev;
|
||||
}
|
||||
cpuid_class->devnode = cpuid_devnode;
|
||||
|
||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/cpuid:online",
|
||||
cpuid_device_create, cpuid_device_destroy);
|
||||
@ -170,7 +171,7 @@ static int __init cpuid_init(void)
|
||||
return 0;
|
||||
|
||||
out_class:
|
||||
class_destroy(cpuid_class);
|
||||
class_unregister(&cpuid_class);
|
||||
out_chrdev:
|
||||
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
|
||||
return err;
|
||||
@ -180,7 +181,7 @@ module_init(cpuid_init);
|
||||
static void __exit cpuid_exit(void)
|
||||
{
|
||||
cpuhp_remove_state(cpuhp_cpuid_state);
|
||||
class_destroy(cpuid_class);
|
||||
class_unregister(&cpuid_class);
|
||||
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
|
||||
}
|
||||
module_exit(cpuid_exit);
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
static struct class *msr_class;
|
||||
static enum cpuhp_state cpuhp_msr_state;
|
||||
|
||||
enum allow_write_msrs {
|
||||
@ -235,26 +234,31 @@ static const struct file_operations msr_fops = {
|
||||
.compat_ioctl = msr_ioctl,
|
||||
};
|
||||
|
||||
static char *msr_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
|
||||
}
|
||||
|
||||
static const struct class msr_class = {
|
||||
.name = "msr",
|
||||
.devnode = msr_devnode,
|
||||
};
|
||||
|
||||
static int msr_device_create(unsigned int cpu)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
|
||||
dev = device_create(&msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
|
||||
"msr%d", cpu);
|
||||
return PTR_ERR_OR_ZERO(dev);
|
||||
}
|
||||
|
||||
static int msr_device_destroy(unsigned int cpu)
|
||||
{
|
||||
device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
|
||||
device_destroy(&msr_class, MKDEV(MSR_MAJOR, cpu));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *msr_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
|
||||
}
|
||||
|
||||
static int __init msr_init(void)
|
||||
{
|
||||
int err;
|
||||
@ -263,12 +267,9 @@ static int __init msr_init(void)
|
||||
pr_err("unable to get major %d for msr\n", MSR_MAJOR);
|
||||
return -EBUSY;
|
||||
}
|
||||
msr_class = class_create("msr");
|
||||
if (IS_ERR(msr_class)) {
|
||||
err = PTR_ERR(msr_class);
|
||||
err = class_register(&msr_class);
|
||||
if (err)
|
||||
goto out_chrdev;
|
||||
}
|
||||
msr_class->devnode = msr_devnode;
|
||||
|
||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
|
||||
msr_device_create, msr_device_destroy);
|
||||
@ -278,7 +279,7 @@ static int __init msr_init(void)
|
||||
return 0;
|
||||
|
||||
out_class:
|
||||
class_destroy(msr_class);
|
||||
class_unregister(&msr_class);
|
||||
out_chrdev:
|
||||
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
|
||||
return err;
|
||||
@ -288,7 +289,7 @@ module_init(msr_init);
|
||||
static void __exit msr_exit(void)
|
||||
{
|
||||
cpuhp_remove_state(cpuhp_msr_state);
|
||||
class_destroy(msr_class);
|
||||
class_unregister(&msr_class);
|
||||
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
|
||||
}
|
||||
module_exit(msr_exit)
|
||||
|
@ -2306,12 +2306,12 @@ static void device_platform_notify(struct device *dev)
|
||||
|
||||
static void device_platform_notify_remove(struct device *dev)
|
||||
{
|
||||
acpi_device_notify_remove(dev);
|
||||
if (platform_notify_remove)
|
||||
platform_notify_remove(dev);
|
||||
|
||||
software_node_notify_remove(dev);
|
||||
|
||||
if (platform_notify_remove)
|
||||
platform_notify_remove(dev);
|
||||
acpi_device_notify_remove(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3528,18 +3528,17 @@ int device_add(struct device *dev)
|
||||
* the name, and force the use of dev_name()
|
||||
*/
|
||||
if (dev->init_name) {
|
||||
dev_set_name(dev, "%s", dev->init_name);
|
||||
error = dev_set_name(dev, "%s", dev->init_name);
|
||||
dev->init_name = NULL;
|
||||
}
|
||||
|
||||
if (dev_name(dev))
|
||||
error = 0;
|
||||
/* subsystems can specify simple device enumeration */
|
||||
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
|
||||
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
|
||||
|
||||
if (!dev_name(dev)) {
|
||||
error = -EINVAL;
|
||||
else if (dev->bus && dev->bus->dev_name)
|
||||
error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
|
||||
if (error)
|
||||
goto name_error;
|
||||
}
|
||||
|
||||
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
|
||||
|
||||
@ -3815,6 +3814,17 @@ void device_del(struct device *dev)
|
||||
device_platform_notify_remove(dev);
|
||||
device_links_purge(dev);
|
||||
|
||||
/*
|
||||
* If a device does not have a driver attached, we need to clean
|
||||
* up any managed resources. We do this in device_release(), but
|
||||
* it's never called (and we leak the device) if a managed
|
||||
* resource holds a reference to the device. So release all
|
||||
* managed resources here, like we do in driver_detach(). We
|
||||
* still need to do so again in device_release() in case someone
|
||||
* adds a new resource after this point, though.
|
||||
*/
|
||||
devres_release_all(dev);
|
||||
|
||||
bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
|
||||
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
|
||||
glue_dir = get_glue_dir(dev);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
|
||||
#include "base.h"
|
||||
@ -50,12 +51,30 @@ static int cpu_subsys_online(struct device *dev)
|
||||
int cpuid = dev->id;
|
||||
int from_nid, to_nid;
|
||||
int ret;
|
||||
int retries = 0;
|
||||
|
||||
from_nid = cpu_to_node(cpuid);
|
||||
if (from_nid == NUMA_NO_NODE)
|
||||
return -ENODEV;
|
||||
|
||||
retry:
|
||||
ret = cpu_device_up(dev);
|
||||
|
||||
/*
|
||||
* If -EBUSY is returned, it is likely that hotplug is temporarily
|
||||
* disabled when cpu_hotplug_disable() was called. This condition is
|
||||
* transient. So we retry after waiting for an exponentially
|
||||
* increasing delay up to a total of at least 620ms as some PCI
|
||||
* device initialization can take quite a while.
|
||||
*/
|
||||
if (ret == -EBUSY) {
|
||||
retries++;
|
||||
if (retries > 5)
|
||||
return ret;
|
||||
msleep(10 * (1 << retries));
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* When hot adding memory to memoryless node and enabling a cpu
|
||||
* on the node, node number of the cpu may internally change.
|
||||
|
@ -693,6 +693,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
|
||||
device_remove(dev);
|
||||
driver_sysfs_remove(dev);
|
||||
if (dev->bus && dev->bus->dma_cleanup)
|
||||
dev->bus->dma_cleanup(dev);
|
||||
device_unbind_cleanup(dev);
|
||||
|
||||
goto re_probe;
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/hugetlb.h>
|
||||
|
||||
static struct bus_type node_subsys = {
|
||||
.name = "node",
|
||||
|
2
drivers/base/test/.kunitconfig
Normal file
2
drivers/base/test/.kunitconfig
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_DM_KUNIT_TEST=y
|
@ -9,6 +9,10 @@ config TEST_ASYNC_DRIVER_PROBE
|
||||
|
||||
If unsure say N.
|
||||
|
||||
config DM_KUNIT_TEST
|
||||
tristate "KUnit Tests for the device model" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
|
||||
config DRIVER_PE_KUNIT_TEST
|
||||
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT=y
|
||||
|
@ -1,5 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o
|
||||
|
||||
obj-$(CONFIG_DM_KUNIT_TEST) += root-device-test.o
|
||||
obj-$(CONFIG_DM_KUNIT_TEST) += platform-device-test.o
|
||||
|
||||
obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o
|
||||
CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
|
||||
|
224
drivers/base/test/platform-device-test.c
Normal file
224
drivers/base/test/platform-device-test.c
Normal file
@ -0,0 +1,224 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <kunit/resource.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DEVICE_NAME "test"
|
||||
|
||||
struct test_priv {
|
||||
bool probe_done;
|
||||
bool release_done;
|
||||
wait_queue_head_t probe_wq;
|
||||
wait_queue_head_t release_wq;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int platform_device_devm_init(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
||||
init_waitqueue_head(&priv->probe_wq);
|
||||
init_waitqueue_head(&priv->release_wq);
|
||||
|
||||
test->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devm_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
static void devm_put_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
put_device(priv->dev);
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
#define RELEASE_TIMEOUT_MS 100
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, non-probed device will run its
|
||||
* device-managed actions when unregistered.
|
||||
*/
|
||||
static void platform_device_devm_register_unregister_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, non-probed device will run its
|
||||
* device-managed actions when unregistered, even if someone still holds
|
||||
* a reference to it.
|
||||
*/
|
||||
static void platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
|
||||
get_device(priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
static int fake_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct test_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
priv->probe_done = true;
|
||||
wake_up_interruptible(&priv->probe_wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver fake_driver = {
|
||||
.probe = fake_probe,
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, probed device will run its device-managed
|
||||
* actions when unregistered.
|
||||
*/
|
||||
static void probed_platform_device_devm_register_unregister_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&fake_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_ASSERT_GT(test, ret, 0);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
|
||||
platform_driver_unregister(&fake_driver);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, probed device will run its device-managed
|
||||
* actions when unregistered, even if someone still holds a reference to
|
||||
* it.
|
||||
*/
|
||||
static void probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&fake_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_ASSERT_GT(test, ret, 0);
|
||||
|
||||
get_device(priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
|
||||
platform_driver_unregister(&fake_driver);
|
||||
}
|
||||
|
||||
static struct kunit_case platform_device_devm_tests[] = {
|
||||
KUNIT_CASE(platform_device_devm_register_unregister_test),
|
||||
KUNIT_CASE(platform_device_devm_register_get_unregister_with_devm_test),
|
||||
KUNIT_CASE(probed_platform_device_devm_register_unregister_test),
|
||||
KUNIT_CASE(probed_platform_device_devm_register_get_unregister_with_devm_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite platform_device_devm_test_suite = {
|
||||
.name = "platform-device-devm",
|
||||
.init = platform_device_devm_init,
|
||||
.test_cases = platform_device_devm_tests,
|
||||
};
|
||||
|
||||
kunit_test_suite(platform_device_devm_test_suite);
|
||||
|
||||
MODULE_DESCRIPTION("Test module for platform devices");
|
||||
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
112
drivers/base/test/root-device-test.c
Normal file
112
drivers/base/test/root-device-test.c
Normal file
@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright 2023 Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
#include <kunit/resource.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#define DEVICE_NAME "test"
|
||||
|
||||
struct test_priv {
|
||||
bool probe_done;
|
||||
bool release_done;
|
||||
wait_queue_head_t release_wq;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int root_device_devm_init(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
||||
init_waitqueue_head(&priv->release_wq);
|
||||
|
||||
test->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devm_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
#define RELEASE_TIMEOUT_MS 100
|
||||
|
||||
/*
|
||||
* Tests that a bus-less, non-probed device will run its device-managed
|
||||
* actions when unregistered.
|
||||
*/
|
||||
static void root_device_devm_register_unregister_test(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
priv->dev = root_device_register(DEVICE_NAME);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
root_device_unregister(priv->dev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
static void devm_put_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
put_device(priv->dev);
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that a bus-less, non-probed device will run its device-managed
|
||||
* actions when unregistered, even if someone still holds a reference to
|
||||
* it.
|
||||
*/
|
||||
static void root_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
priv->dev = root_device_register(DEVICE_NAME);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
|
||||
|
||||
get_device(priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
root_device_unregister(priv->dev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
static struct kunit_case root_device_devm_tests[] = {
|
||||
KUNIT_CASE(root_device_devm_register_unregister_test),
|
||||
KUNIT_CASE(root_device_devm_register_get_unregister_with_devm_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite root_device_devm_test_suite = {
|
||||
.name = "root-device-devm",
|
||||
.init = root_device_devm_init,
|
||||
.test_cases = root_device_devm_tests,
|
||||
};
|
||||
|
||||
kunit_test_suite(root_device_devm_test_suite);
|
||||
|
||||
MODULE_DESCRIPTION("Test module for root devices");
|
||||
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
@ -84,7 +84,7 @@ test_platform_device_register_node(char *name, int id, int nid)
|
||||
|
||||
pdev = platform_device_alloc(name, id);
|
||||
if (!pdev)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (nid != NUMA_NO_NODE)
|
||||
set_dev_node(&pdev->dev, nid);
|
||||
|
@ -28,8 +28,13 @@
|
||||
DEFINE_IDR(dev_nums_idr);
|
||||
static DEFINE_MUTEX(idr_lock);
|
||||
|
||||
struct class *tpm_class;
|
||||
struct class *tpmrm_class;
|
||||
const struct class tpm_class = {
|
||||
.name = "tpm",
|
||||
.shutdown_pre = tpm_class_shutdown,
|
||||
};
|
||||
const struct class tpmrm_class = {
|
||||
.name = "tmprm",
|
||||
};
|
||||
dev_t tpm_devt;
|
||||
|
||||
static int tpm_request_locality(struct tpm_chip *chip)
|
||||
@ -336,7 +341,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
|
||||
|
||||
device_initialize(&chip->dev);
|
||||
|
||||
chip->dev.class = tpm_class;
|
||||
chip->dev.class = &tpm_class;
|
||||
chip->dev.release = tpm_dev_release;
|
||||
chip->dev.parent = pdev;
|
||||
chip->dev.groups = chip->groups;
|
||||
|
@ -476,18 +476,15 @@ static int __init tpm_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
tpm_class = class_create("tpm");
|
||||
if (IS_ERR(tpm_class)) {
|
||||
rc = class_register(&tpm_class);
|
||||
if (rc) {
|
||||
pr_err("couldn't create tpm class\n");
|
||||
return PTR_ERR(tpm_class);
|
||||
return rc;
|
||||
}
|
||||
|
||||
tpm_class->shutdown_pre = tpm_class_shutdown;
|
||||
|
||||
tpmrm_class = class_create("tpmrm");
|
||||
if (IS_ERR(tpmrm_class)) {
|
||||
rc = class_register(&tpmrm_class);
|
||||
if (rc) {
|
||||
pr_err("couldn't create tpmrm class\n");
|
||||
rc = PTR_ERR(tpmrm_class);
|
||||
goto out_destroy_tpm_class;
|
||||
}
|
||||
|
||||
@ -508,9 +505,9 @@ static int __init tpm_init(void)
|
||||
out_unreg_chrdev:
|
||||
unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
|
||||
out_destroy_tpmrm_class:
|
||||
class_destroy(tpmrm_class);
|
||||
class_unregister(&tpmrm_class);
|
||||
out_destroy_tpm_class:
|
||||
class_destroy(tpm_class);
|
||||
class_unregister(&tpm_class);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -518,8 +515,8 @@ static int __init tpm_init(void)
|
||||
static void __exit tpm_exit(void)
|
||||
{
|
||||
idr_destroy(&dev_nums_idr);
|
||||
class_destroy(tpm_class);
|
||||
class_destroy(tpmrm_class);
|
||||
class_unregister(&tpm_class);
|
||||
class_unregister(&tpmrm_class);
|
||||
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
|
||||
tpm_dev_common_exit();
|
||||
}
|
||||
|
@ -230,8 +230,8 @@ enum tpm2_pt_props {
|
||||
* compiler warnings about stack frame size. */
|
||||
#define TPM_MAX_RNG_DATA 128
|
||||
|
||||
extern struct class *tpm_class;
|
||||
extern struct class *tpmrm_class;
|
||||
extern const struct class tpm_class;
|
||||
extern const struct class tpmrm_class;
|
||||
extern dev_t tpm_devt;
|
||||
extern const struct file_operations tpm_fops;
|
||||
extern const struct file_operations tpmrm_fops;
|
||||
|
@ -606,7 +606,7 @@ int tpm_devs_add(struct tpm_chip *chip)
|
||||
|
||||
device_initialize(&chip->devs);
|
||||
chip->devs.parent = chip->dev.parent;
|
||||
chip->devs.class = tpmrm_class;
|
||||
chip->devs.class = &tpmrm_class;
|
||||
|
||||
/*
|
||||
* Get extra reference on main device to hold on behalf of devs.
|
||||
|
@ -23,8 +23,6 @@
|
||||
#include "hid-roccat-common.h"
|
||||
#include "hid-roccat-arvo.h"
|
||||
|
||||
static struct class *arvo_class;
|
||||
|
||||
static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -268,6 +266,11 @@ static const struct attribute_group *arvo_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class arvo_class = {
|
||||
.name = "arvo",
|
||||
.dev_groups = arvo_groups,
|
||||
};
|
||||
|
||||
static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
|
||||
struct arvo_device *arvo)
|
||||
{
|
||||
@ -309,7 +312,7 @@ static int arvo_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(arvo_class, hdev,
|
||||
retval = roccat_connect(&arvo_class, hdev,
|
||||
sizeof(struct arvo_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
@ -433,21 +436,20 @@ static int __init arvo_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
arvo_class = class_create("arvo");
|
||||
if (IS_ERR(arvo_class))
|
||||
return PTR_ERR(arvo_class);
|
||||
arvo_class->dev_groups = arvo_groups;
|
||||
retval = class_register(&arvo_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&arvo_driver);
|
||||
if (retval)
|
||||
class_destroy(arvo_class);
|
||||
class_unregister(&arvo_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit arvo_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&arvo_driver);
|
||||
class_destroy(arvo_class);
|
||||
class_unregister(&arvo_class);
|
||||
}
|
||||
|
||||
module_init(arvo_init);
|
||||
|
@ -23,8 +23,6 @@
|
||||
#include "hid-roccat-common.h"
|
||||
#include "hid-roccat-isku.h"
|
||||
|
||||
static struct class *isku_class;
|
||||
|
||||
static void isku_profile_activated(struct isku_device *isku, uint new_profile)
|
||||
{
|
||||
isku->actual_profile = new_profile;
|
||||
@ -248,6 +246,11 @@ static const struct attribute_group *isku_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class isku_class = {
|
||||
.name = "isku",
|
||||
.dev_groups = isku_groups,
|
||||
};
|
||||
|
||||
static int isku_init_isku_device_struct(struct usb_device *usb_dev,
|
||||
struct isku_device *isku)
|
||||
{
|
||||
@ -289,7 +292,7 @@ static int isku_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(isku_class, hdev,
|
||||
retval = roccat_connect(&isku_class, hdev,
|
||||
sizeof(struct isku_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
@ -435,21 +438,21 @@ static struct hid_driver isku_driver = {
|
||||
static int __init isku_init(void)
|
||||
{
|
||||
int retval;
|
||||
isku_class = class_create("isku");
|
||||
if (IS_ERR(isku_class))
|
||||
return PTR_ERR(isku_class);
|
||||
isku_class->dev_groups = isku_groups;
|
||||
|
||||
retval = class_register(&isku_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&isku_driver);
|
||||
if (retval)
|
||||
class_destroy(isku_class);
|
||||
class_unregister(&isku_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit isku_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&isku_driver);
|
||||
class_destroy(isku_class);
|
||||
class_unregister(&isku_class);
|
||||
}
|
||||
|
||||
module_init(isku_init);
|
||||
|
@ -89,9 +89,6 @@ static int kone_send(struct usb_device *usb_dev, uint usb_command,
|
||||
return ((len < 0) ? len : ((len != size) ? -EIO : 0));
|
||||
}
|
||||
|
||||
/* kone_class is used for creating sysfs attributes via roccat char device */
|
||||
static struct class *kone_class;
|
||||
|
||||
static void kone_set_settings_checksum(struct kone_settings *settings)
|
||||
{
|
||||
uint16_t checksum = 0;
|
||||
@ -657,6 +654,12 @@ static const struct attribute_group *kone_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* kone_class is used for creating sysfs attributes via roccat char device */
|
||||
static const struct class kone_class = {
|
||||
.name = "kone",
|
||||
.dev_groups = kone_groups,
|
||||
};
|
||||
|
||||
static int kone_init_kone_device_struct(struct usb_device *usb_dev,
|
||||
struct kone_device *kone)
|
||||
{
|
||||
@ -712,8 +715,8 @@ static int kone_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(kone_class, hdev,
|
||||
sizeof(struct kone_roccat_report));
|
||||
retval = roccat_connect(&kone_class, hdev,
|
||||
sizeof(struct kone_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
/* be tolerant about not getting chrdev */
|
||||
@ -890,21 +893,20 @@ static int __init kone_init(void)
|
||||
int retval;
|
||||
|
||||
/* class name has to be same as driver name */
|
||||
kone_class = class_create("kone");
|
||||
if (IS_ERR(kone_class))
|
||||
return PTR_ERR(kone_class);
|
||||
kone_class->dev_groups = kone_groups;
|
||||
retval = class_register(&kone_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&kone_driver);
|
||||
if (retval)
|
||||
class_destroy(kone_class);
|
||||
class_unregister(&kone_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit kone_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&kone_driver);
|
||||
class_destroy(kone_class);
|
||||
class_unregister(&kone_class);
|
||||
}
|
||||
|
||||
module_init(kone_init);
|
||||
|
@ -26,8 +26,6 @@
|
||||
|
||||
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
||||
|
||||
static struct class *koneplus_class;
|
||||
|
||||
static void koneplus_profile_activated(struct koneplus_device *koneplus,
|
||||
uint new_profile)
|
||||
{
|
||||
@ -356,6 +354,11 @@ static const struct attribute_group *koneplus_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class koneplus_class = {
|
||||
.name = "koneplus",
|
||||
.dev_groups = koneplus_groups,
|
||||
};
|
||||
|
||||
static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
|
||||
struct koneplus_device *koneplus)
|
||||
{
|
||||
@ -394,8 +397,8 @@ static int koneplus_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(koneplus_class, hdev,
|
||||
sizeof(struct koneplus_roccat_report));
|
||||
retval = roccat_connect(&koneplus_class, hdev,
|
||||
sizeof(struct koneplus_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
} else {
|
||||
@ -549,21 +552,20 @@ static int __init koneplus_init(void)
|
||||
int retval;
|
||||
|
||||
/* class name has to be same as driver name */
|
||||
koneplus_class = class_create("koneplus");
|
||||
if (IS_ERR(koneplus_class))
|
||||
return PTR_ERR(koneplus_class);
|
||||
koneplus_class->dev_groups = koneplus_groups;
|
||||
retval = class_register(&koneplus_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&koneplus_driver);
|
||||
if (retval)
|
||||
class_destroy(koneplus_class);
|
||||
class_unregister(&koneplus_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit koneplus_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&koneplus_driver);
|
||||
class_destroy(koneplus_class);
|
||||
class_unregister(&koneplus_class);
|
||||
}
|
||||
|
||||
module_init(koneplus_init);
|
||||
|
@ -36,8 +36,6 @@ struct konepure_mouse_report_button {
|
||||
uint8_t unknown[2];
|
||||
} __packed;
|
||||
|
||||
static struct class *konepure_class;
|
||||
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03);
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f);
|
||||
@ -72,6 +70,11 @@ static const struct attribute_group *konepure_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class konepure_class = {
|
||||
.name = "konepure",
|
||||
.dev_groups = konepure_groups,
|
||||
};
|
||||
|
||||
static int konepure_init_specials(struct hid_device *hdev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
@ -98,8 +101,8 @@ static int konepure_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(konepure_class, hdev,
|
||||
sizeof(struct konepure_mouse_report_button));
|
||||
retval = roccat_connect(&konepure_class, hdev,
|
||||
sizeof(struct konepure_mouse_report_button));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
} else {
|
||||
@ -207,21 +210,20 @@ static int __init konepure_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
konepure_class = class_create("konepure");
|
||||
if (IS_ERR(konepure_class))
|
||||
return PTR_ERR(konepure_class);
|
||||
konepure_class->dev_groups = konepure_groups;
|
||||
retval = class_register(&konepure_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&konepure_driver);
|
||||
if (retval)
|
||||
class_destroy(konepure_class);
|
||||
class_unregister(&konepure_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit konepure_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&konepure_driver);
|
||||
class_destroy(konepure_class);
|
||||
class_unregister(&konepure_class);
|
||||
}
|
||||
|
||||
module_init(konepure_init);
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
||||
|
||||
static struct class *kovaplus_class;
|
||||
|
||||
static uint kovaplus_convert_event_cpi(uint value)
|
||||
{
|
||||
return (value == 7 ? 4 : (value == 4 ? 3 : value));
|
||||
@ -409,6 +407,11 @@ static const struct attribute_group *kovaplus_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class kovaplus_class = {
|
||||
.name = "kovaplus",
|
||||
.dev_groups = kovaplus_groups,
|
||||
};
|
||||
|
||||
static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
|
||||
struct kovaplus_device *kovaplus)
|
||||
{
|
||||
@ -463,8 +466,8 @@ static int kovaplus_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(kovaplus_class, hdev,
|
||||
sizeof(struct kovaplus_roccat_report));
|
||||
retval = roccat_connect(&kovaplus_class, hdev,
|
||||
sizeof(struct kovaplus_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
} else {
|
||||
@ -638,21 +641,20 @@ static int __init kovaplus_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
kovaplus_class = class_create("kovaplus");
|
||||
if (IS_ERR(kovaplus_class))
|
||||
return PTR_ERR(kovaplus_class);
|
||||
kovaplus_class->dev_groups = kovaplus_groups;
|
||||
retval = class_register(&kovaplus_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&kovaplus_driver);
|
||||
if (retval)
|
||||
class_destroy(kovaplus_class);
|
||||
class_unregister(&kovaplus_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit kovaplus_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&kovaplus_driver);
|
||||
class_destroy(kovaplus_class);
|
||||
class_unregister(&kovaplus_class);
|
||||
}
|
||||
|
||||
module_init(kovaplus_init);
|
||||
|
@ -26,9 +26,6 @@
|
||||
|
||||
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
||||
|
||||
/* pyra_class is used for creating sysfs attributes via roccat char device */
|
||||
static struct class *pyra_class;
|
||||
|
||||
static void profile_activated(struct pyra_device *pyra,
|
||||
unsigned int new_profile)
|
||||
{
|
||||
@ -366,6 +363,12 @@ static const struct attribute_group *pyra_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* pyra_class is used for creating sysfs attributes via roccat char device */
|
||||
static const struct class pyra_class = {
|
||||
.name = "pyra",
|
||||
.dev_groups = pyra_groups,
|
||||
};
|
||||
|
||||
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
|
||||
struct pyra_device *pyra)
|
||||
{
|
||||
@ -413,7 +416,7 @@ static int pyra_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(pyra_class, hdev,
|
||||
retval = roccat_connect(&pyra_class, hdev,
|
||||
sizeof(struct pyra_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
@ -585,21 +588,20 @@ static int __init pyra_init(void)
|
||||
int retval;
|
||||
|
||||
/* class name has to be same as driver name */
|
||||
pyra_class = class_create("pyra");
|
||||
if (IS_ERR(pyra_class))
|
||||
return PTR_ERR(pyra_class);
|
||||
pyra_class->dev_groups = pyra_groups;
|
||||
retval = class_register(&pyra_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&pyra_driver);
|
||||
if (retval)
|
||||
class_destroy(pyra_class);
|
||||
class_unregister(&pyra_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit pyra_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&pyra_driver);
|
||||
class_destroy(pyra_class);
|
||||
class_unregister(&pyra_class);
|
||||
}
|
||||
|
||||
module_init(pyra_init);
|
||||
|
@ -28,8 +28,6 @@ struct ryos_report_special {
|
||||
uint8_t data[4];
|
||||
} __packed;
|
||||
|
||||
static struct class *ryos_class;
|
||||
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03);
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d);
|
||||
@ -80,6 +78,11 @@ static const struct attribute_group *ryos_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class ryos_class = {
|
||||
.name = "ryos",
|
||||
.dev_groups = ryos_groups,
|
||||
};
|
||||
|
||||
static int ryos_init_specials(struct hid_device *hdev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
@ -106,7 +109,7 @@ static int ryos_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(ryos_class, hdev,
|
||||
retval = roccat_connect(&ryos_class, hdev,
|
||||
sizeof(struct ryos_report_special));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
@ -216,21 +219,20 @@ static int __init ryos_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
ryos_class = class_create("ryos");
|
||||
if (IS_ERR(ryos_class))
|
||||
return PTR_ERR(ryos_class);
|
||||
ryos_class->dev_groups = ryos_groups;
|
||||
retval = class_register(&ryos_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&ryos_driver);
|
||||
if (retval)
|
||||
class_destroy(ryos_class);
|
||||
class_unregister(&ryos_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit ryos_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&ryos_driver);
|
||||
class_destroy(ryos_class);
|
||||
class_unregister(&ryos_class);
|
||||
}
|
||||
|
||||
module_init(ryos_init);
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include "hid-roccat-common.h"
|
||||
#include "hid-roccat-savu.h"
|
||||
|
||||
static struct class *savu_class;
|
||||
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
|
||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
|
||||
@ -52,6 +50,11 @@ static const struct attribute_group *savu_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct class savu_class = {
|
||||
.name = "savu",
|
||||
.dev_groups = savu_groups,
|
||||
};
|
||||
|
||||
static int savu_init_specials(struct hid_device *hdev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
@ -78,7 +81,7 @@ static int savu_init_specials(struct hid_device *hdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(savu_class, hdev,
|
||||
retval = roccat_connect(&savu_class, hdev,
|
||||
sizeof(struct savu_roccat_report));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
@ -204,21 +207,20 @@ static int __init savu_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
savu_class = class_create("savu");
|
||||
if (IS_ERR(savu_class))
|
||||
return PTR_ERR(savu_class);
|
||||
savu_class->dev_groups = savu_groups;
|
||||
retval = class_register(&savu_class);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = hid_register_driver(&savu_driver);
|
||||
if (retval)
|
||||
class_destroy(savu_class);
|
||||
class_unregister(&savu_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit savu_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&savu_driver);
|
||||
class_destroy(savu_class);
|
||||
class_unregister(&savu_class);
|
||||
}
|
||||
|
||||
module_init(savu_init);
|
||||
|
@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
|
||||
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
|
||||
* success, a negative error code on failure.
|
||||
*/
|
||||
int roccat_connect(struct class *klass, struct hid_device *hid, int report_size)
|
||||
int roccat_connect(const struct class *klass, struct hid_device *hid, int report_size)
|
||||
{
|
||||
unsigned int minor;
|
||||
struct roccat_device *device;
|
||||
|
@ -32,7 +32,9 @@
|
||||
|
||||
static int hidraw_major;
|
||||
static struct cdev hidraw_cdev;
|
||||
static struct class *hidraw_class;
|
||||
static const struct class hidraw_class = {
|
||||
.name = "hidraw",
|
||||
};
|
||||
static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
|
||||
static DECLARE_RWSEM(minors_rwsem);
|
||||
|
||||
@ -329,7 +331,7 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
|
||||
hid_hw_close(hidraw->hid);
|
||||
wake_up_interruptible(&hidraw->wait);
|
||||
}
|
||||
device_destroy(hidraw_class,
|
||||
device_destroy(&hidraw_class,
|
||||
MKDEV(hidraw_major, hidraw->minor));
|
||||
} else {
|
||||
--hidraw->open;
|
||||
@ -569,7 +571,7 @@ int hidraw_connect(struct hid_device *hid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
|
||||
dev->dev = device_create(&hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
|
||||
NULL, "%s%d", "hidraw", minor);
|
||||
|
||||
if (IS_ERR(dev->dev)) {
|
||||
@ -623,11 +625,9 @@ int __init hidraw_init(void)
|
||||
|
||||
hidraw_major = MAJOR(dev_id);
|
||||
|
||||
hidraw_class = class_create("hidraw");
|
||||
if (IS_ERR(hidraw_class)) {
|
||||
result = PTR_ERR(hidraw_class);
|
||||
result = class_register(&hidraw_class);
|
||||
if (result)
|
||||
goto error_cdev;
|
||||
}
|
||||
|
||||
cdev_init(&hidraw_cdev, &hidraw_ops);
|
||||
result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
|
||||
@ -639,7 +639,7 @@ int __init hidraw_init(void)
|
||||
return result;
|
||||
|
||||
error_class:
|
||||
class_destroy(hidraw_class);
|
||||
class_unregister(&hidraw_class);
|
||||
error_cdev:
|
||||
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
|
||||
goto out;
|
||||
@ -650,7 +650,7 @@ void hidraw_exit(void)
|
||||
dev_t dev_id = MKDEV(hidraw_major, 0);
|
||||
|
||||
cdev_del(&hidraw_cdev);
|
||||
class_destroy(hidraw_class);
|
||||
class_unregister(&hidraw_class);
|
||||
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
|
||||
|
||||
}
|
||||
|
@ -383,9 +383,11 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
|
||||
rb_insert_color(&kn->rb, &kn->parent->dir.children);
|
||||
|
||||
/* successfully added, account subdir number */
|
||||
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||
if (kernfs_type(kn) == KERNFS_DIR)
|
||||
kn->parent->dir.subdirs++;
|
||||
kernfs_inc_rev(kn->parent);
|
||||
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -408,9 +410,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn)
|
||||
if (RB_EMPTY_NODE(&kn->rb))
|
||||
return false;
|
||||
|
||||
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||
if (kernfs_type(kn) == KERNFS_DIR)
|
||||
kn->parent->dir.subdirs--;
|
||||
kernfs_inc_rev(kn->parent);
|
||||
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||
|
||||
rb_erase(&kn->rb, &kn->parent->dir.children);
|
||||
RB_CLEAR_NODE(&kn->rb);
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <linux/namei.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/statfs.h>
|
||||
|
||||
#include "kernfs-internal.h"
|
||||
|
||||
@ -45,8 +47,15 @@ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kernfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
simple_statfs(dentry, buf);
|
||||
buf->f_fsid = uuid_to_fsid(dentry->d_sb->s_uuid.b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct super_operations kernfs_sops = {
|
||||
.statfs = simple_statfs,
|
||||
.statfs = kernfs_statfs,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.evict_inode = kernfs_evict_inode,
|
||||
|
||||
@ -351,6 +360,8 @@ int kernfs_get_tree(struct fs_context *fc)
|
||||
}
|
||||
sb->s_flags |= SB_ACTIVE;
|
||||
|
||||
uuid_gen(&sb->s_uuid);
|
||||
|
||||
down_write(&root->kernfs_supers_rwsem);
|
||||
list_add(&info->node, &info->root->supers);
|
||||
up_write(&root->kernfs_supers_rwsem);
|
||||
|
@ -274,4 +274,6 @@ do { \
|
||||
WARN_ONCE(condition, "%s %s: " format, \
|
||||
dev_driver_string(dev), dev_name(dev), ## arg)
|
||||
|
||||
__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...);
|
||||
|
||||
#endif /* _DEVICE_PRINTK_H_ */
|
||||
|
@ -1249,8 +1249,6 @@ void device_link_remove(void *consumer, struct device *supplier);
|
||||
void device_links_supplier_sync_state_pause(void);
|
||||
void device_links_supplier_sync_state_resume(void);
|
||||
|
||||
__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...);
|
||||
|
||||
/* Create alias, so I can be autoloaded. */
|
||||
#define MODULE_ALIAS_CHARDEV(major,minor) \
|
||||
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
int roccat_connect(struct class *klass, struct hid_device *hid,
|
||||
int roccat_connect(const struct class *klass, struct hid_device *hid,
|
||||
int report_size);
|
||||
void roccat_disconnect(int minor);
|
||||
int roccat_report_event(int minor, u8 const *data);
|
||||
|
@ -550,6 +550,10 @@ static inline int kernfs_setattr(struct kernfs_node *kn,
|
||||
const struct iattr *iattr)
|
||||
{ return -ENOSYS; }
|
||||
|
||||
static inline __poll_t kernfs_generic_poll(struct kernfs_open_file *of,
|
||||
struct poll_table_struct *pt)
|
||||
{ return -ENOSYS; }
|
||||
|
||||
static inline void kernfs_notify(struct kernfs_node *kn) { }
|
||||
|
||||
static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
|
||||
|
@ -69,14 +69,16 @@ struct kobject {
|
||||
const struct kobj_type *ktype;
|
||||
struct kernfs_node *sd; /* sysfs directory entry */
|
||||
struct kref kref;
|
||||
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
|
||||
struct delayed_work release;
|
||||
#endif
|
||||
|
||||
unsigned int state_initialized:1;
|
||||
unsigned int state_in_sysfs:1;
|
||||
unsigned int state_add_uevent_sent:1;
|
||||
unsigned int state_remove_uevent_sent:1;
|
||||
unsigned int uevent_suppress:1;
|
||||
|
||||
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
|
||||
struct delayed_work release;
|
||||
#endif
|
||||
};
|
||||
|
||||
__printf(2, 3) int kobject_set_name(struct kobject *kobj, const char *name, ...);
|
||||
|
@ -56,6 +56,14 @@ void kobject_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid)
|
||||
kobj->ktype->get_ownership(kobj, uid, gid);
|
||||
}
|
||||
|
||||
static bool kobj_ns_type_is_valid(enum kobj_ns_type type)
|
||||
{
|
||||
if ((type <= KOBJ_NS_TYPE_NONE) || (type >= KOBJ_NS_TYPES))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int create_dir(struct kobject *kobj)
|
||||
{
|
||||
const struct kobj_type *ktype = get_ktype(kobj);
|
||||
@ -66,12 +74,10 @@ static int create_dir(struct kobject *kobj)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (ktype) {
|
||||
error = sysfs_create_groups(kobj, ktype->default_groups);
|
||||
if (error) {
|
||||
sysfs_remove_dir(kobj);
|
||||
return error;
|
||||
}
|
||||
error = sysfs_create_groups(kobj, ktype->default_groups);
|
||||
if (error) {
|
||||
sysfs_remove_dir(kobj);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -86,8 +92,7 @@ static int create_dir(struct kobject *kobj)
|
||||
*/
|
||||
ops = kobj_child_ns_ops(kobj);
|
||||
if (ops) {
|
||||
BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
|
||||
BUG_ON(ops->type >= KOBJ_NS_TYPES);
|
||||
BUG_ON(!kobj_ns_type_is_valid(ops->type));
|
||||
BUG_ON(!kobj_ns_type_registered(ops->type));
|
||||
|
||||
sysfs_enable_ns(kobj->sd);
|
||||
@ -584,8 +589,7 @@ static void __kobject_del(struct kobject *kobj)
|
||||
sd = kobj->sd;
|
||||
ktype = get_ktype(kobj);
|
||||
|
||||
if (ktype)
|
||||
sysfs_remove_groups(kobj, ktype->default_groups);
|
||||
sysfs_remove_groups(kobj, ktype->default_groups);
|
||||
|
||||
/* send "remove" if the caller did not do it but sent "add" */
|
||||
if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
|
||||
@ -662,10 +666,6 @@ static void kobject_cleanup(struct kobject *kobj)
|
||||
pr_debug("'%s' (%p): %s, parent %p\n",
|
||||
kobject_name(kobj), kobj, __func__, kobj->parent);
|
||||
|
||||
if (t && !t->release)
|
||||
pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
|
||||
kobject_name(kobj), kobj);
|
||||
|
||||
/* remove from sysfs if the caller did not do it */
|
||||
if (kobj->state_in_sysfs) {
|
||||
pr_debug("'%s' (%p): auto cleanup kobject_del\n",
|
||||
@ -676,10 +676,13 @@ static void kobject_cleanup(struct kobject *kobj)
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
if (t && t->release) {
|
||||
if (t->release) {
|
||||
pr_debug("'%s' (%p): calling ktype release\n",
|
||||
kobject_name(kobj), kobj);
|
||||
t->release(kobj);
|
||||
} else {
|
||||
pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
|
||||
kobject_name(kobj), kobj);
|
||||
}
|
||||
|
||||
/* free name if we allocated it */
|
||||
@ -854,6 +857,11 @@ int kset_register(struct kset *k)
|
||||
if (!k)
|
||||
return -EINVAL;
|
||||
|
||||
if (!k->kobj.ktype) {
|
||||
pr_err("must have a ktype to be initialized properly!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kset_init(k);
|
||||
err = kobject_add_internal(&k->kobj);
|
||||
if (err) {
|
||||
@ -1017,11 +1025,7 @@ int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
|
||||
error = -EINVAL;
|
||||
if (type >= KOBJ_NS_TYPES)
|
||||
goto out;
|
||||
|
||||
error = -EINVAL;
|
||||
if (type <= KOBJ_NS_TYPE_NONE)
|
||||
if (!kobj_ns_type_is_valid(type))
|
||||
goto out;
|
||||
|
||||
error = -EBUSY;
|
||||
@ -1041,7 +1045,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type)
|
||||
int registered = 0;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES))
|
||||
if (kobj_ns_type_is_valid(type))
|
||||
registered = kobj_ns_ops_tbl[type] != NULL;
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
@ -1052,7 +1056,7 @@ const struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *pa
|
||||
{
|
||||
const struct kobj_ns_type_operations *ops = NULL;
|
||||
|
||||
if (parent && parent->ktype && parent->ktype->child_ns_type)
|
||||
if (parent && parent->ktype->child_ns_type)
|
||||
ops = parent->ktype->child_ns_type(parent);
|
||||
|
||||
return ops;
|
||||
@ -1068,8 +1072,7 @@ bool kobj_ns_current_may_mount(enum kobj_ns_type type)
|
||||
bool may_mount = true;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
|
||||
may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
@ -1081,8 +1084,7 @@ void *kobj_ns_grab_current(enum kobj_ns_type type)
|
||||
void *ns = NULL;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
|
||||
ns = kobj_ns_ops_tbl[type]->grab_current_ns();
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
@ -1095,8 +1097,7 @@ const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk)
|
||||
const void *ns = NULL;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
|
||||
ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
@ -1108,8 +1109,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
|
||||
const void *ns = NULL;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
|
||||
ns = kobj_ns_ops_tbl[type]->initial_ns();
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
@ -1119,7 +1119,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
|
||||
void kobj_ns_drop(enum kobj_ns_type type, void *ns)
|
||||
{
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
if (kobj_ns_type_is_valid(type) &&
|
||||
kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns)
|
||||
kobj_ns_ops_tbl[type]->drop_ns(ns);
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user