mirror of
https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
synced 2025-09-15 00:56:46 +10: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
|
Rules on what kind of patches are accepted, and which ones are not, into the
|
||||||
"-stable" tree:
|
"-stable" tree:
|
||||||
|
|
||||||
|
- It or an equivalent fix must already exist in Linus' tree (upstream).
|
||||||
- It must be obviously correct and tested.
|
- It must be obviously correct and tested.
|
||||||
- It cannot be bigger than 100 lines, with context.
|
- It cannot be bigger than 100 lines, with context.
|
||||||
- It must fix only one thing.
|
- It must follow the
|
||||||
- It must fix a real bug that bothers people (not a, "This could be a
|
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
|
||||||
problem..." type thing).
|
rules.
|
||||||
- It must fix a problem that causes a build error (but not for things
|
- It must either fix a real bug that bothers people or just add a device ID.
|
||||||
marked CONFIG_BROKEN), an oops, a hang, data corruption, a real
|
To elaborate on the former:
|
||||||
security issue, or some "oh, that's not good" issue. In short, something
|
|
||||||
critical.
|
- 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
|
- Serious issues as reported by a user of a distribution kernel may also
|
||||||
be considered if they fix a notable performance or interactivity issue.
|
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
|
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
|
regression they should only be submitted by a distribution kernel
|
||||||
maintainer and include an addendum linking to a bugzilla entry if it
|
maintainer and include an addendum linking to a bugzilla entry if it
|
||||||
exists and additional information on the user-visible impact.
|
exists and additional information on the user-visible impact.
|
||||||
- New device IDs and quirks are also accepted.
|
- No "This could be a problem..." type of things like a "theoretical race
|
||||||
- No "theoretical race condition" issues, unless an explanation of how the
|
condition", unless an explanation of how the bug can be exploited is also
|
||||||
race can be exploited is also provided.
|
provided.
|
||||||
- It cannot contain any "trivial" fixes in it (spelling changes,
|
- No "trivial" fixes without benefit for users (spelling changes, whitespace
|
||||||
whitespace cleanups, etc).
|
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).
|
|
||||||
|
|
||||||
|
|
||||||
Procedure for submitting patches to the -stable tree
|
Procedure for submitting patches to the -stable tree
|
||||||
@ -41,70 +40,48 @@ Procedure for submitting patches to the -stable tree
|
|||||||
process but should follow the procedures in
|
process but should follow the procedures in
|
||||||
:ref:`Documentation/process/security-bugs.rst <securitybugs>`.
|
: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:
|
||||||
|
|
||||||
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
|
.. code-block:: none
|
||||||
|
|
||||||
Cc: stable@vger.kernel.org
|
Cc: stable@vger.kernel.org
|
||||||
|
|
||||||
in the sign-off area. Once the patch is merged it will be applied to
|
in the sign-off area. Once the patch is mainlined it will be applied to the
|
||||||
the stable tree without anything else needing to be done by the author
|
stable tree without anything else needing to be done by the author or
|
||||||
or subsystem maintainer.
|
subsystem maintainer.
|
||||||
|
|
||||||
.. _option_2:
|
To sent additional instructions to the stable team, use a shell-style inline
|
||||||
|
comment:
|
||||||
|
|
||||||
Option 2
|
* To specify any additional patch prerequisites for cherry picking use the
|
||||||
********
|
|
||||||
|
|
||||||
After the patch has been merged to Linus' tree, 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
|
|
||||||
be applied to.
|
|
||||||
|
|
||||||
.. _option_3:
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
commit <sha1> upstream.
|
|
||||||
|
|
||||||
or alternatively:
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
[ 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:
|
following format in the sign-off area:
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
@ -124,8 +101,8 @@ The tag sequence has the meaning of:
|
|||||||
git cherry-pick fd21073
|
git cherry-pick fd21073
|
||||||
git cherry-pick <this commit>
|
git cherry-pick <this commit>
|
||||||
|
|
||||||
Also, some patches may have kernel version prerequisites. This can be
|
* For patches that may have kernel version prerequisites specify them using
|
||||||
specified in the following format in the sign-off area:
|
the following format in the sign-off area:
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
@ -139,13 +116,66 @@ The tag has the meaning of:
|
|||||||
|
|
||||||
For each "-stable" tree starting with the specified version.
|
For each "-stable" tree starting with the specified version.
|
||||||
|
|
||||||
Following the submission:
|
Note, such tagging is unnecessary if the stable team can derive the
|
||||||
|
appropriate versions from Fixes: tags.
|
||||||
|
|
||||||
- The sender will receive an ACK when the patch has been accepted into the
|
* 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
|
||||||
|
********
|
||||||
|
|
||||||
|
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 versions you wish it to
|
||||||
|
be applied to.
|
||||||
|
|
||||||
|
.. _option_3:
|
||||||
|
|
||||||
|
Option 3
|
||||||
|
********
|
||||||
|
|
||||||
|
Send the patch, after verifying that it follows the above rules, to
|
||||||
|
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
|
||||||
|
|
||||||
|
commit <sha1> upstream.
|
||||||
|
|
||||||
|
or alternatively:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
[ Upstream commit <sha1> ]
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
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
|
queue, or a NAK if the patch is rejected. This response might take a few
|
||||||
days, according to the developer's schedules.
|
days, according to the schedules of the stable team members.
|
||||||
- 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
|
Review cycle
|
||||||
@ -174,6 +204,7 @@ Review cycle
|
|||||||
security kernel team, and not go through the normal review cycle.
|
security kernel team, and not go through the normal review cycle.
|
||||||
Contact the kernel security team for more details on this procedure.
|
Contact the kernel security team for more details on this procedure.
|
||||||
|
|
||||||
|
|
||||||
Trees
|
Trees
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -45,7 +45,21 @@ static u64 prefetch_disable_bits;
|
|||||||
*/
|
*/
|
||||||
static unsigned int pseudo_lock_major;
|
static unsigned int pseudo_lock_major;
|
||||||
static unsigned long pseudo_lock_minor_avail = GENMASK(MINORBITS, 0);
|
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
|
* 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);
|
&pseudo_measure_fops);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = device_create(pseudo_lock_class, NULL,
|
dev = device_create(&pseudo_lock_class, NULL,
|
||||||
MKDEV(pseudo_lock_major, new_minor),
|
MKDEV(pseudo_lock_major, new_minor),
|
||||||
rdtgrp, "%s", rdtgrp->kn->name);
|
rdtgrp, "%s", rdtgrp->kn->name);
|
||||||
|
|
||||||
@ -1383,7 +1397,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_device:
|
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:
|
out_debugfs:
|
||||||
debugfs_remove_recursive(plr->debugfs_dir);
|
debugfs_remove_recursive(plr->debugfs_dir);
|
||||||
pseudo_lock_minor_release(new_minor);
|
pseudo_lock_minor_release(new_minor);
|
||||||
@ -1424,7 +1438,7 @@ void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp)
|
|||||||
|
|
||||||
pseudo_lock_cstates_relax(plr);
|
pseudo_lock_cstates_relax(plr);
|
||||||
debugfs_remove_recursive(rdtgrp->plr->debugfs_dir);
|
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);
|
pseudo_lock_minor_release(plr->minor);
|
||||||
|
|
||||||
free:
|
free:
|
||||||
@ -1560,16 +1574,6 @@ static const struct file_operations pseudo_lock_dev_fops = {
|
|||||||
.mmap = pseudo_lock_dev_mmap,
|
.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 rdt_pseudo_lock_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -1580,21 +1584,18 @@ int rdt_pseudo_lock_init(void)
|
|||||||
|
|
||||||
pseudo_lock_major = ret;
|
pseudo_lock_major = ret;
|
||||||
|
|
||||||
pseudo_lock_class = class_create("pseudo_lock");
|
ret = class_register(&pseudo_lock_class);
|
||||||
if (IS_ERR(pseudo_lock_class)) {
|
if (ret) {
|
||||||
ret = PTR_ERR(pseudo_lock_class);
|
|
||||||
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
|
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo_lock_class->devnode = pseudo_lock_devnode;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdt_pseudo_lock_release(void)
|
void rdt_pseudo_lock_release(void)
|
||||||
{
|
{
|
||||||
class_destroy(pseudo_lock_class);
|
class_unregister(&pseudo_lock_class);
|
||||||
pseudo_lock_class = NULL;
|
|
||||||
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
|
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
|
||||||
pseudo_lock_major = 0;
|
pseudo_lock_major = 0;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
|
|
||||||
static struct class *cpuid_class;
|
|
||||||
static enum cpuhp_state cpuhp_cpuid_state;
|
static enum cpuhp_state cpuhp_cpuid_state;
|
||||||
|
|
||||||
struct cpuid_regs_done {
|
struct cpuid_regs_done {
|
||||||
@ -124,26 +123,31 @@ static const struct file_operations cpuid_fops = {
|
|||||||
.open = cpuid_open,
|
.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)
|
static int cpuid_device_create(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct device *dev;
|
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);
|
"cpu%d", cpu);
|
||||||
return PTR_ERR_OR_ZERO(dev);
|
return PTR_ERR_OR_ZERO(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpuid_device_destroy(unsigned int cpu)
|
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;
|
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)
|
static int __init cpuid_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -154,12 +158,9 @@ static int __init cpuid_init(void)
|
|||||||
CPUID_MAJOR);
|
CPUID_MAJOR);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
cpuid_class = class_create("cpuid");
|
err = class_register(&cpuid_class);
|
||||||
if (IS_ERR(cpuid_class)) {
|
if (err)
|
||||||
err = PTR_ERR(cpuid_class);
|
|
||||||
goto out_chrdev;
|
goto out_chrdev;
|
||||||
}
|
|
||||||
cpuid_class->devnode = cpuid_devnode;
|
|
||||||
|
|
||||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/cpuid:online",
|
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/cpuid:online",
|
||||||
cpuid_device_create, cpuid_device_destroy);
|
cpuid_device_create, cpuid_device_destroy);
|
||||||
@ -170,7 +171,7 @@ static int __init cpuid_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_class:
|
out_class:
|
||||||
class_destroy(cpuid_class);
|
class_unregister(&cpuid_class);
|
||||||
out_chrdev:
|
out_chrdev:
|
||||||
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
|
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
|
||||||
return err;
|
return err;
|
||||||
@ -180,7 +181,7 @@ module_init(cpuid_init);
|
|||||||
static void __exit cpuid_exit(void)
|
static void __exit cpuid_exit(void)
|
||||||
{
|
{
|
||||||
cpuhp_remove_state(cpuhp_cpuid_state);
|
cpuhp_remove_state(cpuhp_cpuid_state);
|
||||||
class_destroy(cpuid_class);
|
class_unregister(&cpuid_class);
|
||||||
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
|
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
|
||||||
}
|
}
|
||||||
module_exit(cpuid_exit);
|
module_exit(cpuid_exit);
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
#include <asm/cpufeature.h>
|
#include <asm/cpufeature.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
|
|
||||||
static struct class *msr_class;
|
|
||||||
static enum cpuhp_state cpuhp_msr_state;
|
static enum cpuhp_state cpuhp_msr_state;
|
||||||
|
|
||||||
enum allow_write_msrs {
|
enum allow_write_msrs {
|
||||||
@ -235,26 +234,31 @@ static const struct file_operations msr_fops = {
|
|||||||
.compat_ioctl = msr_ioctl,
|
.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)
|
static int msr_device_create(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct device *dev;
|
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);
|
"msr%d", cpu);
|
||||||
return PTR_ERR_OR_ZERO(dev);
|
return PTR_ERR_OR_ZERO(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msr_device_destroy(unsigned int cpu)
|
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;
|
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)
|
static int __init msr_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -263,12 +267,9 @@ static int __init msr_init(void)
|
|||||||
pr_err("unable to get major %d for msr\n", MSR_MAJOR);
|
pr_err("unable to get major %d for msr\n", MSR_MAJOR);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
msr_class = class_create("msr");
|
err = class_register(&msr_class);
|
||||||
if (IS_ERR(msr_class)) {
|
if (err)
|
||||||
err = PTR_ERR(msr_class);
|
|
||||||
goto out_chrdev;
|
goto out_chrdev;
|
||||||
}
|
|
||||||
msr_class->devnode = msr_devnode;
|
|
||||||
|
|
||||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
|
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
|
||||||
msr_device_create, msr_device_destroy);
|
msr_device_create, msr_device_destroy);
|
||||||
@ -278,7 +279,7 @@ static int __init msr_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_class:
|
out_class:
|
||||||
class_destroy(msr_class);
|
class_unregister(&msr_class);
|
||||||
out_chrdev:
|
out_chrdev:
|
||||||
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
|
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
|
||||||
return err;
|
return err;
|
||||||
@ -288,7 +289,7 @@ module_init(msr_init);
|
|||||||
static void __exit msr_exit(void)
|
static void __exit msr_exit(void)
|
||||||
{
|
{
|
||||||
cpuhp_remove_state(cpuhp_msr_state);
|
cpuhp_remove_state(cpuhp_msr_state);
|
||||||
class_destroy(msr_class);
|
class_unregister(&msr_class);
|
||||||
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
|
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
|
||||||
}
|
}
|
||||||
module_exit(msr_exit)
|
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)
|
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);
|
software_node_notify_remove(dev);
|
||||||
|
|
||||||
if (platform_notify_remove)
|
acpi_device_notify_remove(dev);
|
||||||
platform_notify_remove(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3528,18 +3528,17 @@ int device_add(struct device *dev)
|
|||||||
* the name, and force the use of dev_name()
|
* the name, and force the use of dev_name()
|
||||||
*/
|
*/
|
||||||
if (dev->init_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;
|
dev->init_name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev_name(dev))
|
||||||
|
error = 0;
|
||||||
/* subsystems can specify simple device enumeration */
|
/* subsystems can specify simple device enumeration */
|
||||||
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
|
else if (dev->bus && dev->bus->dev_name)
|
||||||
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
|
error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
|
||||||
|
if (error)
|
||||||
if (!dev_name(dev)) {
|
|
||||||
error = -EINVAL;
|
|
||||||
goto name_error;
|
goto name_error;
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
|
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_platform_notify_remove(dev);
|
||||||
device_links_purge(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);
|
bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
|
||||||
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
|
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
|
||||||
glue_dir = get_glue_dir(dev);
|
glue_dir = get_glue_dir(dev);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <linux/cpufeature.h>
|
#include <linux/cpufeature.h>
|
||||||
#include <linux/tick.h>
|
#include <linux/tick.h>
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/sched/isolation.h>
|
#include <linux/sched/isolation.h>
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
@ -50,12 +51,30 @@ static int cpu_subsys_online(struct device *dev)
|
|||||||
int cpuid = dev->id;
|
int cpuid = dev->id;
|
||||||
int from_nid, to_nid;
|
int from_nid, to_nid;
|
||||||
int ret;
|
int ret;
|
||||||
|
int retries = 0;
|
||||||
|
|
||||||
from_nid = cpu_to_node(cpuid);
|
from_nid = cpu_to_node(cpuid);
|
||||||
if (from_nid == NUMA_NO_NODE)
|
if (from_nid == NUMA_NO_NODE)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
retry:
|
||||||
ret = cpu_device_up(dev);
|
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
|
* When hot adding memory to memoryless node and enabling a cpu
|
||||||
* on the node, node number of the cpu may internally change.
|
* on the node, node number of the cpu may internally change.
|
||||||
|
@ -693,6 +693,8 @@ re_probe:
|
|||||||
|
|
||||||
device_remove(dev);
|
device_remove(dev);
|
||||||
driver_sysfs_remove(dev);
|
driver_sysfs_remove(dev);
|
||||||
|
if (dev->bus && dev->bus->dma_cleanup)
|
||||||
|
dev->bus->dma_cleanup(dev);
|
||||||
device_unbind_cleanup(dev);
|
device_unbind_cleanup(dev);
|
||||||
|
|
||||||
goto re_probe;
|
goto re_probe;
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/hugetlb.h>
|
|
||||||
|
|
||||||
static struct bus_type node_subsys = {
|
static struct bus_type node_subsys = {
|
||||||
.name = "node",
|
.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.
|
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
|
config DRIVER_PE_KUNIT_TEST
|
||||||
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
|
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
|
||||||
depends on KUNIT=y
|
depends on KUNIT=y
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o
|
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
|
obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o
|
||||||
CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
|
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);
|
pdev = platform_device_alloc(name, id);
|
||||||
if (!pdev)
|
if (!pdev)
|
||||||
return NULL;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
if (nid != NUMA_NO_NODE)
|
if (nid != NUMA_NO_NODE)
|
||||||
set_dev_node(&pdev->dev, nid);
|
set_dev_node(&pdev->dev, nid);
|
||||||
|
@ -28,8 +28,13 @@
|
|||||||
DEFINE_IDR(dev_nums_idr);
|
DEFINE_IDR(dev_nums_idr);
|
||||||
static DEFINE_MUTEX(idr_lock);
|
static DEFINE_MUTEX(idr_lock);
|
||||||
|
|
||||||
struct class *tpm_class;
|
const struct class tpm_class = {
|
||||||
struct class *tpmrm_class;
|
.name = "tpm",
|
||||||
|
.shutdown_pre = tpm_class_shutdown,
|
||||||
|
};
|
||||||
|
const struct class tpmrm_class = {
|
||||||
|
.name = "tmprm",
|
||||||
|
};
|
||||||
dev_t tpm_devt;
|
dev_t tpm_devt;
|
||||||
|
|
||||||
static int tpm_request_locality(struct tpm_chip *chip)
|
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);
|
device_initialize(&chip->dev);
|
||||||
|
|
||||||
chip->dev.class = tpm_class;
|
chip->dev.class = &tpm_class;
|
||||||
chip->dev.release = tpm_dev_release;
|
chip->dev.release = tpm_dev_release;
|
||||||
chip->dev.parent = pdev;
|
chip->dev.parent = pdev;
|
||||||
chip->dev.groups = chip->groups;
|
chip->dev.groups = chip->groups;
|
||||||
|
@ -476,18 +476,15 @@ static int __init tpm_init(void)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
tpm_class = class_create("tpm");
|
rc = class_register(&tpm_class);
|
||||||
if (IS_ERR(tpm_class)) {
|
if (rc) {
|
||||||
pr_err("couldn't create tpm class\n");
|
pr_err("couldn't create tpm class\n");
|
||||||
return PTR_ERR(tpm_class);
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
tpm_class->shutdown_pre = tpm_class_shutdown;
|
rc = class_register(&tpmrm_class);
|
||||||
|
if (rc) {
|
||||||
tpmrm_class = class_create("tpmrm");
|
|
||||||
if (IS_ERR(tpmrm_class)) {
|
|
||||||
pr_err("couldn't create tpmrm class\n");
|
pr_err("couldn't create tpmrm class\n");
|
||||||
rc = PTR_ERR(tpmrm_class);
|
|
||||||
goto out_destroy_tpm_class;
|
goto out_destroy_tpm_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,9 +505,9 @@ static int __init tpm_init(void)
|
|||||||
out_unreg_chrdev:
|
out_unreg_chrdev:
|
||||||
unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
|
unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
|
||||||
out_destroy_tpmrm_class:
|
out_destroy_tpmrm_class:
|
||||||
class_destroy(tpmrm_class);
|
class_unregister(&tpmrm_class);
|
||||||
out_destroy_tpm_class:
|
out_destroy_tpm_class:
|
||||||
class_destroy(tpm_class);
|
class_unregister(&tpm_class);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -518,8 +515,8 @@ out_destroy_tpm_class:
|
|||||||
static void __exit tpm_exit(void)
|
static void __exit tpm_exit(void)
|
||||||
{
|
{
|
||||||
idr_destroy(&dev_nums_idr);
|
idr_destroy(&dev_nums_idr);
|
||||||
class_destroy(tpm_class);
|
class_unregister(&tpm_class);
|
||||||
class_destroy(tpmrm_class);
|
class_unregister(&tpmrm_class);
|
||||||
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
|
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
|
||||||
tpm_dev_common_exit();
|
tpm_dev_common_exit();
|
||||||
}
|
}
|
||||||
|
@ -230,8 +230,8 @@ enum tpm2_pt_props {
|
|||||||
* compiler warnings about stack frame size. */
|
* compiler warnings about stack frame size. */
|
||||||
#define TPM_MAX_RNG_DATA 128
|
#define TPM_MAX_RNG_DATA 128
|
||||||
|
|
||||||
extern struct class *tpm_class;
|
extern const struct class tpm_class;
|
||||||
extern struct class *tpmrm_class;
|
extern const struct class tpmrm_class;
|
||||||
extern dev_t tpm_devt;
|
extern dev_t tpm_devt;
|
||||||
extern const struct file_operations tpm_fops;
|
extern const struct file_operations tpm_fops;
|
||||||
extern const struct file_operations tpmrm_fops;
|
extern const struct file_operations tpmrm_fops;
|
||||||
|
@ -606,7 +606,7 @@ int tpm_devs_add(struct tpm_chip *chip)
|
|||||||
|
|
||||||
device_initialize(&chip->devs);
|
device_initialize(&chip->devs);
|
||||||
chip->devs.parent = chip->dev.parent;
|
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.
|
* Get extra reference on main device to hold on behalf of devs.
|
||||||
|
@ -23,8 +23,6 @@
|
|||||||
#include "hid-roccat-common.h"
|
#include "hid-roccat-common.h"
|
||||||
#include "hid-roccat-arvo.h"
|
#include "hid-roccat-arvo.h"
|
||||||
|
|
||||||
static struct class *arvo_class;
|
|
||||||
|
|
||||||
static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
|
static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
@ -268,6 +266,11 @@ static const struct attribute_group *arvo_groups[] = {
|
|||||||
NULL,
|
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,
|
static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
|
||||||
struct arvo_device *arvo)
|
struct arvo_device *arvo)
|
||||||
{
|
{
|
||||||
@ -309,7 +312,7 @@ static int arvo_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(arvo_class, hdev,
|
retval = roccat_connect(&arvo_class, hdev,
|
||||||
sizeof(struct arvo_roccat_report));
|
sizeof(struct arvo_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -433,21 +436,20 @@ static int __init arvo_init(void)
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
arvo_class = class_create("arvo");
|
retval = class_register(&arvo_class);
|
||||||
if (IS_ERR(arvo_class))
|
if (retval)
|
||||||
return PTR_ERR(arvo_class);
|
return retval;
|
||||||
arvo_class->dev_groups = arvo_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&arvo_driver);
|
retval = hid_register_driver(&arvo_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(arvo_class);
|
class_unregister(&arvo_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit arvo_exit(void)
|
static void __exit arvo_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&arvo_driver);
|
hid_unregister_driver(&arvo_driver);
|
||||||
class_destroy(arvo_class);
|
class_unregister(&arvo_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(arvo_init);
|
module_init(arvo_init);
|
||||||
|
@ -23,8 +23,6 @@
|
|||||||
#include "hid-roccat-common.h"
|
#include "hid-roccat-common.h"
|
||||||
#include "hid-roccat-isku.h"
|
#include "hid-roccat-isku.h"
|
||||||
|
|
||||||
static struct class *isku_class;
|
|
||||||
|
|
||||||
static void isku_profile_activated(struct isku_device *isku, uint new_profile)
|
static void isku_profile_activated(struct isku_device *isku, uint new_profile)
|
||||||
{
|
{
|
||||||
isku->actual_profile = new_profile;
|
isku->actual_profile = new_profile;
|
||||||
@ -248,6 +246,11 @@ static const struct attribute_group *isku_groups[] = {
|
|||||||
NULL,
|
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,
|
static int isku_init_isku_device_struct(struct usb_device *usb_dev,
|
||||||
struct isku_device *isku)
|
struct isku_device *isku)
|
||||||
{
|
{
|
||||||
@ -289,7 +292,7 @@ static int isku_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(isku_class, hdev,
|
retval = roccat_connect(&isku_class, hdev,
|
||||||
sizeof(struct isku_roccat_report));
|
sizeof(struct isku_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
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)
|
static int __init isku_init(void)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
isku_class = class_create("isku");
|
|
||||||
if (IS_ERR(isku_class))
|
retval = class_register(&isku_class);
|
||||||
return PTR_ERR(isku_class);
|
if (retval)
|
||||||
isku_class->dev_groups = isku_groups;
|
return retval;
|
||||||
|
|
||||||
retval = hid_register_driver(&isku_driver);
|
retval = hid_register_driver(&isku_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(isku_class);
|
class_unregister(&isku_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit isku_exit(void)
|
static void __exit isku_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&isku_driver);
|
hid_unregister_driver(&isku_driver);
|
||||||
class_destroy(isku_class);
|
class_unregister(&isku_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(isku_init);
|
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));
|
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)
|
static void kone_set_settings_checksum(struct kone_settings *settings)
|
||||||
{
|
{
|
||||||
uint16_t checksum = 0;
|
uint16_t checksum = 0;
|
||||||
@ -657,6 +654,12 @@ static const struct attribute_group *kone_groups[] = {
|
|||||||
NULL,
|
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,
|
static int kone_init_kone_device_struct(struct usb_device *usb_dev,
|
||||||
struct kone_device *kone)
|
struct kone_device *kone)
|
||||||
{
|
{
|
||||||
@ -712,7 +715,7 @@ static int kone_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(kone_class, hdev,
|
retval = roccat_connect(&kone_class, hdev,
|
||||||
sizeof(struct kone_roccat_report));
|
sizeof(struct kone_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -890,21 +893,20 @@ static int __init kone_init(void)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* class name has to be same as driver name */
|
/* class name has to be same as driver name */
|
||||||
kone_class = class_create("kone");
|
retval = class_register(&kone_class);
|
||||||
if (IS_ERR(kone_class))
|
if (retval)
|
||||||
return PTR_ERR(kone_class);
|
return retval;
|
||||||
kone_class->dev_groups = kone_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&kone_driver);
|
retval = hid_register_driver(&kone_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(kone_class);
|
class_unregister(&kone_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit kone_exit(void)
|
static void __exit kone_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&kone_driver);
|
hid_unregister_driver(&kone_driver);
|
||||||
class_destroy(kone_class);
|
class_unregister(&kone_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(kone_init);
|
module_init(kone_init);
|
||||||
|
@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
||||||
|
|
||||||
static struct class *koneplus_class;
|
|
||||||
|
|
||||||
static void koneplus_profile_activated(struct koneplus_device *koneplus,
|
static void koneplus_profile_activated(struct koneplus_device *koneplus,
|
||||||
uint new_profile)
|
uint new_profile)
|
||||||
{
|
{
|
||||||
@ -356,6 +354,11 @@ static const struct attribute_group *koneplus_groups[] = {
|
|||||||
NULL,
|
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,
|
static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
|
||||||
struct koneplus_device *koneplus)
|
struct koneplus_device *koneplus)
|
||||||
{
|
{
|
||||||
@ -394,7 +397,7 @@ static int koneplus_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(koneplus_class, hdev,
|
retval = roccat_connect(&koneplus_class, hdev,
|
||||||
sizeof(struct koneplus_roccat_report));
|
sizeof(struct koneplus_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -549,21 +552,20 @@ static int __init koneplus_init(void)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* class name has to be same as driver name */
|
/* class name has to be same as driver name */
|
||||||
koneplus_class = class_create("koneplus");
|
retval = class_register(&koneplus_class);
|
||||||
if (IS_ERR(koneplus_class))
|
if (retval)
|
||||||
return PTR_ERR(koneplus_class);
|
return retval;
|
||||||
koneplus_class->dev_groups = koneplus_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&koneplus_driver);
|
retval = hid_register_driver(&koneplus_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(koneplus_class);
|
class_unregister(&koneplus_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit koneplus_exit(void)
|
static void __exit koneplus_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&koneplus_driver);
|
hid_unregister_driver(&koneplus_driver);
|
||||||
class_destroy(koneplus_class);
|
class_unregister(&koneplus_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(koneplus_init);
|
module_init(koneplus_init);
|
||||||
|
@ -36,8 +36,6 @@ struct konepure_mouse_report_button {
|
|||||||
uint8_t unknown[2];
|
uint8_t unknown[2];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
static struct class *konepure_class;
|
|
||||||
|
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03);
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f);
|
||||||
@ -72,6 +70,11 @@ static const struct attribute_group *konepure_groups[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct class konepure_class = {
|
||||||
|
.name = "konepure",
|
||||||
|
.dev_groups = konepure_groups,
|
||||||
|
};
|
||||||
|
|
||||||
static int konepure_init_specials(struct hid_device *hdev)
|
static int konepure_init_specials(struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||||
@ -98,7 +101,7 @@ static int konepure_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(konepure_class, hdev,
|
retval = roccat_connect(&konepure_class, hdev,
|
||||||
sizeof(struct konepure_mouse_report_button));
|
sizeof(struct konepure_mouse_report_button));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -207,21 +210,20 @@ static int __init konepure_init(void)
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
konepure_class = class_create("konepure");
|
retval = class_register(&konepure_class);
|
||||||
if (IS_ERR(konepure_class))
|
if (retval)
|
||||||
return PTR_ERR(konepure_class);
|
return retval;
|
||||||
konepure_class->dev_groups = konepure_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&konepure_driver);
|
retval = hid_register_driver(&konepure_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(konepure_class);
|
class_unregister(&konepure_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit konepure_exit(void)
|
static void __exit konepure_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&konepure_driver);
|
hid_unregister_driver(&konepure_driver);
|
||||||
class_destroy(konepure_class);
|
class_unregister(&konepure_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(konepure_init);
|
module_init(konepure_init);
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
|
|
||||||
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
||||||
|
|
||||||
static struct class *kovaplus_class;
|
|
||||||
|
|
||||||
static uint kovaplus_convert_event_cpi(uint value)
|
static uint kovaplus_convert_event_cpi(uint value)
|
||||||
{
|
{
|
||||||
return (value == 7 ? 4 : (value == 4 ? 3 : value));
|
return (value == 7 ? 4 : (value == 4 ? 3 : value));
|
||||||
@ -409,6 +407,11 @@ static const struct attribute_group *kovaplus_groups[] = {
|
|||||||
NULL,
|
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,
|
static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
|
||||||
struct kovaplus_device *kovaplus)
|
struct kovaplus_device *kovaplus)
|
||||||
{
|
{
|
||||||
@ -463,7 +466,7 @@ static int kovaplus_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(kovaplus_class, hdev,
|
retval = roccat_connect(&kovaplus_class, hdev,
|
||||||
sizeof(struct kovaplus_roccat_report));
|
sizeof(struct kovaplus_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -638,21 +641,20 @@ static int __init kovaplus_init(void)
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
kovaplus_class = class_create("kovaplus");
|
retval = class_register(&kovaplus_class);
|
||||||
if (IS_ERR(kovaplus_class))
|
if (retval)
|
||||||
return PTR_ERR(kovaplus_class);
|
return retval;
|
||||||
kovaplus_class->dev_groups = kovaplus_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&kovaplus_driver);
|
retval = hid_register_driver(&kovaplus_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(kovaplus_class);
|
class_unregister(&kovaplus_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit kovaplus_exit(void)
|
static void __exit kovaplus_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&kovaplus_driver);
|
hid_unregister_driver(&kovaplus_driver);
|
||||||
class_destroy(kovaplus_class);
|
class_unregister(&kovaplus_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(kovaplus_init);
|
module_init(kovaplus_init);
|
||||||
|
@ -26,9 +26,6 @@
|
|||||||
|
|
||||||
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
|
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,
|
static void profile_activated(struct pyra_device *pyra,
|
||||||
unsigned int new_profile)
|
unsigned int new_profile)
|
||||||
{
|
{
|
||||||
@ -366,6 +363,12 @@ static const struct attribute_group *pyra_groups[] = {
|
|||||||
NULL,
|
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,
|
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
|
||||||
struct pyra_device *pyra)
|
struct pyra_device *pyra)
|
||||||
{
|
{
|
||||||
@ -413,7 +416,7 @@ static int pyra_init_specials(struct hid_device *hdev)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(pyra_class, hdev,
|
retval = roccat_connect(&pyra_class, hdev,
|
||||||
sizeof(struct pyra_roccat_report));
|
sizeof(struct pyra_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -585,21 +588,20 @@ static int __init pyra_init(void)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* class name has to be same as driver name */
|
/* class name has to be same as driver name */
|
||||||
pyra_class = class_create("pyra");
|
retval = class_register(&pyra_class);
|
||||||
if (IS_ERR(pyra_class))
|
if (retval)
|
||||||
return PTR_ERR(pyra_class);
|
return retval;
|
||||||
pyra_class->dev_groups = pyra_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&pyra_driver);
|
retval = hid_register_driver(&pyra_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(pyra_class);
|
class_unregister(&pyra_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit pyra_exit(void)
|
static void __exit pyra_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&pyra_driver);
|
hid_unregister_driver(&pyra_driver);
|
||||||
class_destroy(pyra_class);
|
class_unregister(&pyra_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(pyra_init);
|
module_init(pyra_init);
|
||||||
|
@ -28,8 +28,6 @@ struct ryos_report_special {
|
|||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
static struct class *ryos_class;
|
|
||||||
|
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03);
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d);
|
||||||
@ -80,6 +78,11 @@ static const struct attribute_group *ryos_groups[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct class ryos_class = {
|
||||||
|
.name = "ryos",
|
||||||
|
.dev_groups = ryos_groups,
|
||||||
|
};
|
||||||
|
|
||||||
static int ryos_init_specials(struct hid_device *hdev)
|
static int ryos_init_specials(struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
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;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(ryos_class, hdev,
|
retval = roccat_connect(&ryos_class, hdev,
|
||||||
sizeof(struct ryos_report_special));
|
sizeof(struct ryos_report_special));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -216,21 +219,20 @@ static int __init ryos_init(void)
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
ryos_class = class_create("ryos");
|
retval = class_register(&ryos_class);
|
||||||
if (IS_ERR(ryos_class))
|
if (retval)
|
||||||
return PTR_ERR(ryos_class);
|
return retval;
|
||||||
ryos_class->dev_groups = ryos_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&ryos_driver);
|
retval = hid_register_driver(&ryos_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(ryos_class);
|
class_unregister(&ryos_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit ryos_exit(void)
|
static void __exit ryos_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&ryos_driver);
|
hid_unregister_driver(&ryos_driver);
|
||||||
class_destroy(ryos_class);
|
class_unregister(&ryos_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(ryos_init);
|
module_init(ryos_init);
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
#include "hid-roccat-common.h"
|
#include "hid-roccat-common.h"
|
||||||
#include "hid-roccat-savu.h"
|
#include "hid-roccat-savu.h"
|
||||||
|
|
||||||
static struct class *savu_class;
|
|
||||||
|
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
|
||||||
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
|
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
|
||||||
@ -52,6 +50,11 @@ static const struct attribute_group *savu_groups[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct class savu_class = {
|
||||||
|
.name = "savu",
|
||||||
|
.dev_groups = savu_groups,
|
||||||
|
};
|
||||||
|
|
||||||
static int savu_init_specials(struct hid_device *hdev)
|
static int savu_init_specials(struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
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;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = roccat_connect(savu_class, hdev,
|
retval = roccat_connect(&savu_class, hdev,
|
||||||
sizeof(struct savu_roccat_report));
|
sizeof(struct savu_roccat_report));
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
hid_err(hdev, "couldn't init char dev\n");
|
hid_err(hdev, "couldn't init char dev\n");
|
||||||
@ -204,21 +207,20 @@ static int __init savu_init(void)
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
savu_class = class_create("savu");
|
retval = class_register(&savu_class);
|
||||||
if (IS_ERR(savu_class))
|
if (retval)
|
||||||
return PTR_ERR(savu_class);
|
return retval;
|
||||||
savu_class->dev_groups = savu_groups;
|
|
||||||
|
|
||||||
retval = hid_register_driver(&savu_driver);
|
retval = hid_register_driver(&savu_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
class_destroy(savu_class);
|
class_unregister(&savu_class);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit savu_exit(void)
|
static void __exit savu_exit(void)
|
||||||
{
|
{
|
||||||
hid_unregister_driver(&savu_driver);
|
hid_unregister_driver(&savu_driver);
|
||||||
class_destroy(savu_class);
|
class_unregister(&savu_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(savu_init);
|
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
|
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
|
||||||
* success, a negative error code on failure.
|
* 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;
|
unsigned int minor;
|
||||||
struct roccat_device *device;
|
struct roccat_device *device;
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
|
|
||||||
static int hidraw_major;
|
static int hidraw_major;
|
||||||
static struct cdev hidraw_cdev;
|
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 struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
|
||||||
static DECLARE_RWSEM(minors_rwsem);
|
static DECLARE_RWSEM(minors_rwsem);
|
||||||
|
|
||||||
@ -329,7 +331,7 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
|
|||||||
hid_hw_close(hidraw->hid);
|
hid_hw_close(hidraw->hid);
|
||||||
wake_up_interruptible(&hidraw->wait);
|
wake_up_interruptible(&hidraw->wait);
|
||||||
}
|
}
|
||||||
device_destroy(hidraw_class,
|
device_destroy(&hidraw_class,
|
||||||
MKDEV(hidraw_major, hidraw->minor));
|
MKDEV(hidraw_major, hidraw->minor));
|
||||||
} else {
|
} else {
|
||||||
--hidraw->open;
|
--hidraw->open;
|
||||||
@ -569,7 +571,7 @@ int hidraw_connect(struct hid_device *hid)
|
|||||||
goto out;
|
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);
|
NULL, "%s%d", "hidraw", minor);
|
||||||
|
|
||||||
if (IS_ERR(dev->dev)) {
|
if (IS_ERR(dev->dev)) {
|
||||||
@ -623,11 +625,9 @@ int __init hidraw_init(void)
|
|||||||
|
|
||||||
hidraw_major = MAJOR(dev_id);
|
hidraw_major = MAJOR(dev_id);
|
||||||
|
|
||||||
hidraw_class = class_create("hidraw");
|
result = class_register(&hidraw_class);
|
||||||
if (IS_ERR(hidraw_class)) {
|
if (result)
|
||||||
result = PTR_ERR(hidraw_class);
|
|
||||||
goto error_cdev;
|
goto error_cdev;
|
||||||
}
|
|
||||||
|
|
||||||
cdev_init(&hidraw_cdev, &hidraw_ops);
|
cdev_init(&hidraw_cdev, &hidraw_ops);
|
||||||
result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
|
result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
|
||||||
@ -639,7 +639,7 @@ out:
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
error_class:
|
error_class:
|
||||||
class_destroy(hidraw_class);
|
class_unregister(&hidraw_class);
|
||||||
error_cdev:
|
error_cdev:
|
||||||
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
|
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
|
||||||
goto out;
|
goto out;
|
||||||
@ -650,7 +650,7 @@ void hidraw_exit(void)
|
|||||||
dev_t dev_id = MKDEV(hidraw_major, 0);
|
dev_t dev_id = MKDEV(hidraw_major, 0);
|
||||||
|
|
||||||
cdev_del(&hidraw_cdev);
|
cdev_del(&hidraw_cdev);
|
||||||
class_destroy(hidraw_class);
|
class_unregister(&hidraw_class);
|
||||||
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
|
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);
|
rb_insert_color(&kn->rb, &kn->parent->dir.children);
|
||||||
|
|
||||||
/* successfully added, account subdir number */
|
/* successfully added, account subdir number */
|
||||||
|
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||||
if (kernfs_type(kn) == KERNFS_DIR)
|
if (kernfs_type(kn) == KERNFS_DIR)
|
||||||
kn->parent->dir.subdirs++;
|
kn->parent->dir.subdirs++;
|
||||||
kernfs_inc_rev(kn->parent);
|
kernfs_inc_rev(kn->parent);
|
||||||
|
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -408,9 +410,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn)
|
|||||||
if (RB_EMPTY_NODE(&kn->rb))
|
if (RB_EMPTY_NODE(&kn->rb))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||||
if (kernfs_type(kn) == KERNFS_DIR)
|
if (kernfs_type(kn) == KERNFS_DIR)
|
||||||
kn->parent->dir.subdirs--;
|
kn->parent->dir.subdirs--;
|
||||||
kernfs_inc_rev(kn->parent);
|
kernfs_inc_rev(kn->parent);
|
||||||
|
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
|
||||||
|
|
||||||
rb_erase(&kn->rb, &kn->parent->dir.children);
|
rb_erase(&kn->rb, &kn->parent->dir.children);
|
||||||
RB_CLEAR_NODE(&kn->rb);
|
RB_CLEAR_NODE(&kn->rb);
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/exportfs.h>
|
#include <linux/exportfs.h>
|
||||||
|
#include <linux/uuid.h>
|
||||||
|
#include <linux/statfs.h>
|
||||||
|
|
||||||
#include "kernfs-internal.h"
|
#include "kernfs-internal.h"
|
||||||
|
|
||||||
@ -45,8 +47,15 @@ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
|
|||||||
return 0;
|
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 = {
|
const struct super_operations kernfs_sops = {
|
||||||
.statfs = simple_statfs,
|
.statfs = kernfs_statfs,
|
||||||
.drop_inode = generic_delete_inode,
|
.drop_inode = generic_delete_inode,
|
||||||
.evict_inode = kernfs_evict_inode,
|
.evict_inode = kernfs_evict_inode,
|
||||||
|
|
||||||
@ -351,6 +360,8 @@ int kernfs_get_tree(struct fs_context *fc)
|
|||||||
}
|
}
|
||||||
sb->s_flags |= SB_ACTIVE;
|
sb->s_flags |= SB_ACTIVE;
|
||||||
|
|
||||||
|
uuid_gen(&sb->s_uuid);
|
||||||
|
|
||||||
down_write(&root->kernfs_supers_rwsem);
|
down_write(&root->kernfs_supers_rwsem);
|
||||||
list_add(&info->node, &info->root->supers);
|
list_add(&info->node, &info->root->supers);
|
||||||
up_write(&root->kernfs_supers_rwsem);
|
up_write(&root->kernfs_supers_rwsem);
|
||||||
|
@ -274,4 +274,6 @@ do { \
|
|||||||
WARN_ONCE(condition, "%s %s: " format, \
|
WARN_ONCE(condition, "%s %s: " format, \
|
||||||
dev_driver_string(dev), dev_name(dev), ## arg)
|
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_ */
|
#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_pause(void);
|
||||||
void device_links_supplier_sync_state_resume(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. */
|
/* Create alias, so I can be autoloaded. */
|
||||||
#define MODULE_ALIAS_CHARDEV(major,minor) \
|
#define MODULE_ALIAS_CHARDEV(major,minor) \
|
||||||
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
|
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#ifdef __KERNEL__
|
#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);
|
int report_size);
|
||||||
void roccat_disconnect(int minor);
|
void roccat_disconnect(int minor);
|
||||||
int roccat_report_event(int minor, u8 const *data);
|
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)
|
const struct iattr *iattr)
|
||||||
{ return -ENOSYS; }
|
{ 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 void kernfs_notify(struct kernfs_node *kn) { }
|
||||||
|
|
||||||
static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
|
static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
|
||||||
|
@ -69,14 +69,16 @@ struct kobject {
|
|||||||
const struct kobj_type *ktype;
|
const struct kobj_type *ktype;
|
||||||
struct kernfs_node *sd; /* sysfs directory entry */
|
struct kernfs_node *sd; /* sysfs directory entry */
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
|
|
||||||
struct delayed_work release;
|
|
||||||
#endif
|
|
||||||
unsigned int state_initialized:1;
|
unsigned int state_initialized:1;
|
||||||
unsigned int state_in_sysfs:1;
|
unsigned int state_in_sysfs:1;
|
||||||
unsigned int state_add_uevent_sent:1;
|
unsigned int state_add_uevent_sent:1;
|
||||||
unsigned int state_remove_uevent_sent:1;
|
unsigned int state_remove_uevent_sent:1;
|
||||||
unsigned int uevent_suppress: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, ...);
|
__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);
|
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)
|
static int create_dir(struct kobject *kobj)
|
||||||
{
|
{
|
||||||
const struct kobj_type *ktype = get_ktype(kobj);
|
const struct kobj_type *ktype = get_ktype(kobj);
|
||||||
@ -66,13 +74,11 @@ static int create_dir(struct kobject *kobj)
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (ktype) {
|
|
||||||
error = sysfs_create_groups(kobj, ktype->default_groups);
|
error = sysfs_create_groups(kobj, ktype->default_groups);
|
||||||
if (error) {
|
if (error) {
|
||||||
sysfs_remove_dir(kobj);
|
sysfs_remove_dir(kobj);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @kobj->sd may be deleted by an ancestor going away. Hold an
|
* @kobj->sd may be deleted by an ancestor going away. Hold an
|
||||||
@ -86,8 +92,7 @@ static int create_dir(struct kobject *kobj)
|
|||||||
*/
|
*/
|
||||||
ops = kobj_child_ns_ops(kobj);
|
ops = kobj_child_ns_ops(kobj);
|
||||||
if (ops) {
|
if (ops) {
|
||||||
BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
|
BUG_ON(!kobj_ns_type_is_valid(ops->type));
|
||||||
BUG_ON(ops->type >= KOBJ_NS_TYPES);
|
|
||||||
BUG_ON(!kobj_ns_type_registered(ops->type));
|
BUG_ON(!kobj_ns_type_registered(ops->type));
|
||||||
|
|
||||||
sysfs_enable_ns(kobj->sd);
|
sysfs_enable_ns(kobj->sd);
|
||||||
@ -584,7 +589,6 @@ static void __kobject_del(struct kobject *kobj)
|
|||||||
sd = kobj->sd;
|
sd = kobj->sd;
|
||||||
ktype = get_ktype(kobj);
|
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" */
|
/* send "remove" if the caller did not do it but sent "add" */
|
||||||
@ -662,10 +666,6 @@ static void kobject_cleanup(struct kobject *kobj)
|
|||||||
pr_debug("'%s' (%p): %s, parent %p\n",
|
pr_debug("'%s' (%p): %s, parent %p\n",
|
||||||
kobject_name(kobj), kobj, __func__, kobj->parent);
|
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 */
|
/* remove from sysfs if the caller did not do it */
|
||||||
if (kobj->state_in_sysfs) {
|
if (kobj->state_in_sysfs) {
|
||||||
pr_debug("'%s' (%p): auto cleanup kobject_del\n",
|
pr_debug("'%s' (%p): auto cleanup kobject_del\n",
|
||||||
@ -676,10 +676,13 @@ static void kobject_cleanup(struct kobject *kobj)
|
|||||||
parent = NULL;
|
parent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t && t->release) {
|
if (t->release) {
|
||||||
pr_debug("'%s' (%p): calling ktype release\n",
|
pr_debug("'%s' (%p): calling ktype release\n",
|
||||||
kobject_name(kobj), kobj);
|
kobject_name(kobj), kobj);
|
||||||
t->release(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 */
|
/* free name if we allocated it */
|
||||||
@ -854,6 +857,11 @@ int kset_register(struct kset *k)
|
|||||||
if (!k)
|
if (!k)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!k->kobj.ktype) {
|
||||||
|
pr_err("must have a ktype to be initialized properly!\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
kset_init(k);
|
kset_init(k);
|
||||||
err = kobject_add_internal(&k->kobj);
|
err = kobject_add_internal(&k->kobj);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -1017,11 +1025,7 @@ int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
|
|||||||
spin_lock(&kobj_ns_type_lock);
|
spin_lock(&kobj_ns_type_lock);
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (type >= KOBJ_NS_TYPES)
|
if (!kobj_ns_type_is_valid(type))
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = -EINVAL;
|
|
||||||
if (type <= KOBJ_NS_TYPE_NONE)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
@ -1041,7 +1045,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type)
|
|||||||
int registered = 0;
|
int registered = 0;
|
||||||
|
|
||||||
spin_lock(&kobj_ns_type_lock);
|
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;
|
registered = kobj_ns_ops_tbl[type] != NULL;
|
||||||
spin_unlock(&kobj_ns_type_lock);
|
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;
|
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);
|
ops = parent->ktype->child_ns_type(parent);
|
||||||
|
|
||||||
return ops;
|
return ops;
|
||||||
@ -1068,8 +1072,7 @@ bool kobj_ns_current_may_mount(enum kobj_ns_type type)
|
|||||||
bool may_mount = true;
|
bool may_mount = true;
|
||||||
|
|
||||||
spin_lock(&kobj_ns_type_lock);
|
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])
|
|
||||||
may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
|
may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
|
||||||
spin_unlock(&kobj_ns_type_lock);
|
spin_unlock(&kobj_ns_type_lock);
|
||||||
|
|
||||||
@ -1081,8 +1084,7 @@ void *kobj_ns_grab_current(enum kobj_ns_type type)
|
|||||||
void *ns = NULL;
|
void *ns = NULL;
|
||||||
|
|
||||||
spin_lock(&kobj_ns_type_lock);
|
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])
|
|
||||||
ns = kobj_ns_ops_tbl[type]->grab_current_ns();
|
ns = kobj_ns_ops_tbl[type]->grab_current_ns();
|
||||||
spin_unlock(&kobj_ns_type_lock);
|
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;
|
const void *ns = NULL;
|
||||||
|
|
||||||
spin_lock(&kobj_ns_type_lock);
|
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])
|
|
||||||
ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
|
ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
|
||||||
spin_unlock(&kobj_ns_type_lock);
|
spin_unlock(&kobj_ns_type_lock);
|
||||||
|
|
||||||
@ -1108,8 +1109,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
|
|||||||
const void *ns = NULL;
|
const void *ns = NULL;
|
||||||
|
|
||||||
spin_lock(&kobj_ns_type_lock);
|
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])
|
|
||||||
ns = kobj_ns_ops_tbl[type]->initial_ns();
|
ns = kobj_ns_ops_tbl[type]->initial_ns();
|
||||||
spin_unlock(&kobj_ns_type_lock);
|
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)
|
void kobj_ns_drop(enum kobj_ns_type type, void *ns)
|
||||||
{
|
{
|
||||||
spin_lock(&kobj_ns_type_lock);
|
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] && kobj_ns_ops_tbl[type]->drop_ns)
|
||||||
kobj_ns_ops_tbl[type]->drop_ns(ns);
|
kobj_ns_ops_tbl[type]->drop_ns(ns);
|
||||||
spin_unlock(&kobj_ns_type_lock);
|
spin_unlock(&kobj_ns_type_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user