Merge branch 'linus' into perfcounters/core
Merge reason: need the upstream facility added by: 7f1e2ca: hrtimer: fix rq->lock inversion (again) Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Коммит
6c009ecef8
|
@ -259,7 +259,7 @@ X!Earch/x86/kernel/mca_32.c
|
|||
!Eblock/blk-tag.c
|
||||
!Iblock/blk-tag.c
|
||||
!Eblock/blk-integrity.c
|
||||
!Iblock/blktrace.c
|
||||
!Ikernel/trace/blktrace.c
|
||||
!Iblock/genhd.c
|
||||
!Eblock/genhd.c
|
||||
</chapter>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Maintained by Alan Cox <device@lanana.org>
|
||||
|
||||
Last revised: 29 November 2006
|
||||
Last revised: 6th April 2009
|
||||
|
||||
This list is the Linux Device List, the official registry of allocated
|
||||
device numbers and /dev directory nodes for the Linux operating
|
||||
|
|
|
@ -354,7 +354,8 @@ Who: Krzysztof Piotr Oledzki <ole@ans.pl>
|
|||
|
||||
---------------------------
|
||||
|
||||
What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client()
|
||||
What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client(),
|
||||
i2c_adapter->client_register(), i2c_adapter->client_unregister
|
||||
When: 2.6.30
|
||||
Check: i2c_attach_client i2c_detach_client
|
||||
Why: Deprecated by the new (standard) device driver binding model. Use
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
Kernel NFS Server Statistics
|
||||
============================
|
||||
|
||||
This document describes the format and semantics of the statistics
|
||||
which the kernel NFS server makes available to userspace. These
|
||||
statistics are available in several text form pseudo files, each of
|
||||
which is described separately below.
|
||||
|
||||
In most cases you don't need to know these formats, as the nfsstat(8)
|
||||
program from the nfs-utils distribution provides a helpful command-line
|
||||
interface for extracting and printing them.
|
||||
|
||||
All the files described here are formatted as a sequence of text lines,
|
||||
separated by newline '\n' characters. Lines beginning with a hash
|
||||
'#' character are comments intended for humans and should be ignored
|
||||
by parsing routines. All other lines contain a sequence of fields
|
||||
separated by whitespace.
|
||||
|
||||
/proc/fs/nfsd/pool_stats
|
||||
------------------------
|
||||
|
||||
This file is available in kernels from 2.6.30 onwards, if the
|
||||
/proc/fs/nfsd filesystem is mounted (it almost always should be).
|
||||
|
||||
The first line is a comment which describes the fields present in
|
||||
all the other lines. The other lines present the following data as
|
||||
a sequence of unsigned decimal numeric fields. One line is shown
|
||||
for each NFS thread pool.
|
||||
|
||||
All counters are 64 bits wide and wrap naturally. There is no way
|
||||
to zero these counters, instead applications should do their own
|
||||
rate conversion.
|
||||
|
||||
pool
|
||||
The id number of the NFS thread pool to which this line applies.
|
||||
This number does not change.
|
||||
|
||||
Thread pool ids are a contiguous set of small integers starting
|
||||
at zero. The maximum value depends on the thread pool mode, but
|
||||
currently cannot be larger than the number of CPUs in the system.
|
||||
Note that in the default case there will be a single thread pool
|
||||
which contains all the nfsd threads and all the CPUs in the system,
|
||||
and thus this file will have a single line with a pool id of "0".
|
||||
|
||||
packets-arrived
|
||||
Counts how many NFS packets have arrived. More precisely, this
|
||||
is the number of times that the network stack has notified the
|
||||
sunrpc server layer that new data may be available on a transport
|
||||
(e.g. an NFS or UDP socket or an NFS/RDMA endpoint).
|
||||
|
||||
Depending on the NFS workload patterns and various network stack
|
||||
effects (such as Large Receive Offload) which can combine packets
|
||||
on the wire, this may be either more or less than the number
|
||||
of NFS calls received (which statistic is available elsewhere).
|
||||
However this is a more accurate and less workload-dependent measure
|
||||
of how much CPU load is being placed on the sunrpc server layer
|
||||
due to NFS network traffic.
|
||||
|
||||
sockets-enqueued
|
||||
Counts how many times an NFS transport is enqueued to wait for
|
||||
an nfsd thread to service it, i.e. no nfsd thread was considered
|
||||
available.
|
||||
|
||||
The circumstance this statistic tracks indicates that there was NFS
|
||||
network-facing work to be done but it couldn't be done immediately,
|
||||
thus introducing a small delay in servicing NFS calls. The ideal
|
||||
rate of change for this counter is zero; significantly non-zero
|
||||
values may indicate a performance limitation.
|
||||
|
||||
This can happen either because there are too few nfsd threads in the
|
||||
thread pool for the NFS workload (the workload is thread-limited),
|
||||
or because the NFS workload needs more CPU time than is available in
|
||||
the thread pool (the workload is CPU-limited). In the former case,
|
||||
configuring more nfsd threads will probably improve the performance
|
||||
of the NFS workload. In the latter case, the sunrpc server layer is
|
||||
already choosing not to wake idle nfsd threads because there are too
|
||||
many nfsd threads which want to run but cannot, so configuring more
|
||||
nfsd threads will make no difference whatsoever. The overloads-avoided
|
||||
statistic (see below) can be used to distinguish these cases.
|
||||
|
||||
threads-woken
|
||||
Counts how many times an idle nfsd thread is woken to try to
|
||||
receive some data from an NFS transport.
|
||||
|
||||
This statistic tracks the circumstance where incoming
|
||||
network-facing NFS work is being handled quickly, which is a good
|
||||
thing. The ideal rate of change for this counter will be close
|
||||
to but less than the rate of change of the packets-arrived counter.
|
||||
|
||||
overloads-avoided
|
||||
Counts how many times the sunrpc server layer chose not to wake an
|
||||
nfsd thread, despite the presence of idle nfsd threads, because
|
||||
too many nfsd threads had been recently woken but could not get
|
||||
enough CPU time to actually run.
|
||||
|
||||
This statistic counts a circumstance where the sunrpc layer
|
||||
heuristically avoids overloading the CPU scheduler with too many
|
||||
runnable nfsd threads. The ideal rate of change for this counter
|
||||
is zero. Significant non-zero values indicate that the workload
|
||||
is CPU limited. Usually this is associated with heavy CPU usage
|
||||
on all the CPUs in the nfsd thread pool.
|
||||
|
||||
If a sustained large overloads-avoided rate is detected on a pool,
|
||||
the top(1) utility should be used to check for the following
|
||||
pattern of CPU usage on all the CPUs associated with the given
|
||||
nfsd thread pool.
|
||||
|
||||
- %us ~= 0 (as you're *NOT* running applications on your NFS server)
|
||||
|
||||
- %wa ~= 0
|
||||
|
||||
- %id ~= 0
|
||||
|
||||
- %sy + %hi + %si ~= 100
|
||||
|
||||
If this pattern is seen, configuring more nfsd threads will *not*
|
||||
improve the performance of the workload. If this patten is not
|
||||
seen, then something more subtle is wrong.
|
||||
|
||||
threads-timedout
|
||||
Counts how many times an nfsd thread triggered an idle timeout,
|
||||
i.e. was not woken to handle any incoming network packets for
|
||||
some time.
|
||||
|
||||
This statistic counts a circumstance where there are more nfsd
|
||||
threads configured than can be used by the NFS workload. This is
|
||||
a clue that the number of nfsd threads can be reduced without
|
||||
affecting performance. Unfortunately, it's only a clue and not
|
||||
a strong indication, for a couple of reasons:
|
||||
|
||||
- Currently the rate at which the counter is incremented is quite
|
||||
slow; the idle timeout is 60 minutes. Unless the NFS workload
|
||||
remains constant for hours at a time, this counter is unlikely
|
||||
to be providing information that is still useful.
|
||||
|
||||
- It is usually a wise policy to provide some slack,
|
||||
i.e. configure a few more nfsds than are currently needed,
|
||||
to allow for future spikes in load.
|
||||
|
||||
|
||||
Note that incoming packets on NFS transports will be dealt with in
|
||||
one of three ways. An nfsd thread can be woken (threads-woken counts
|
||||
this case), or the transport can be enqueued for later attention
|
||||
(sockets-enqueued counts this case), or the packet can be temporarily
|
||||
deferred because the transport is currently being used by an nfsd
|
||||
thread. This last case is not very interesting and is not explicitly
|
||||
counted, but can be inferred from the other counters thus:
|
||||
|
||||
packets-deferred = packets-arrived - ( sockets-enqueued + threads-woken )
|
||||
|
||||
|
||||
More
|
||||
----
|
||||
Descriptions of the other statistics file should go here.
|
||||
|
||||
|
||||
Greg Banks <gnb@sgi.com>
|
||||
26 Mar 2009
|
|
@ -0,0 +1,161 @@
|
|||
NFSv4.1 Server Implementation
|
||||
|
||||
Server support for minorversion 1 can be controlled using the
|
||||
/proc/fs/nfsd/versions control file. The string output returned
|
||||
by reading this file will contain either "+4.1" or "-4.1"
|
||||
correspondingly.
|
||||
|
||||
Currently, server support for minorversion 1 is disabled by default.
|
||||
It can be enabled at run time by writing the string "+4.1" to
|
||||
the /proc/fs/nfsd/versions control file. Note that to write this
|
||||
control file, the nfsd service must be taken down. Use your user-mode
|
||||
nfs-utils to set this up; see rpc.nfsd(8)
|
||||
|
||||
The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based
|
||||
on the latest NFSv4.1 Internet Draft:
|
||||
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-29
|
||||
|
||||
From the many new features in NFSv4.1 the current implementation
|
||||
focuses on the mandatory-to-implement NFSv4.1 Sessions, providing
|
||||
"exactly once" semantics and better control and throttling of the
|
||||
resources allocated for each client.
|
||||
|
||||
Other NFSv4.1 features, Parallel NFS operations in particular,
|
||||
are still under development out of tree.
|
||||
See http://wiki.linux-nfs.org/wiki/index.php/PNFS_prototype_design
|
||||
for more information.
|
||||
|
||||
The table below, taken from the NFSv4.1 document, lists
|
||||
the operations that are mandatory to implement (REQ), optional
|
||||
(OPT), and NFSv4.0 operations that are required not to implement (MNI)
|
||||
in minor version 1. The first column indicates the operations that
|
||||
are not supported yet by the linux server implementation.
|
||||
|
||||
The OPTIONAL features identified and their abbreviations are as follows:
|
||||
pNFS Parallel NFS
|
||||
FDELG File Delegations
|
||||
DDELG Directory Delegations
|
||||
|
||||
The following abbreviations indicate the linux server implementation status.
|
||||
I Implemented NFSv4.1 operations.
|
||||
NS Not Supported.
|
||||
NS* unimplemented optional feature.
|
||||
P pNFS features implemented out of tree.
|
||||
PNS pNFS features that are not supported yet (out of tree).
|
||||
|
||||
Operations
|
||||
|
||||
+----------------------+------------+--------------+----------------+
|
||||
| Operation | REQ, REC, | Feature | Definition |
|
||||
| | OPT, or | (REQ, REC, | |
|
||||
| | MNI | or OPT) | |
|
||||
+----------------------+------------+--------------+----------------+
|
||||
| ACCESS | REQ | | Section 18.1 |
|
||||
NS | BACKCHANNEL_CTL | REQ | | Section 18.33 |
|
||||
NS | BIND_CONN_TO_SESSION | REQ | | Section 18.34 |
|
||||
| CLOSE | REQ | | Section 18.2 |
|
||||
| COMMIT | REQ | | Section 18.3 |
|
||||
| CREATE | REQ | | Section 18.4 |
|
||||
I | CREATE_SESSION | REQ | | Section 18.36 |
|
||||
NS*| DELEGPURGE | OPT | FDELG (REQ) | Section 18.5 |
|
||||
| DELEGRETURN | OPT | FDELG, | Section 18.6 |
|
||||
| | | DDELG, pNFS | |
|
||||
| | | (REQ) | |
|
||||
NS | DESTROY_CLIENTID | REQ | | Section 18.50 |
|
||||
I | DESTROY_SESSION | REQ | | Section 18.37 |
|
||||
I | EXCHANGE_ID | REQ | | Section 18.35 |
|
||||
NS | FREE_STATEID | REQ | | Section 18.38 |
|
||||
| GETATTR | REQ | | Section 18.7 |
|
||||
P | GETDEVICEINFO | OPT | pNFS (REQ) | Section 18.40 |
|
||||
P | GETDEVICELIST | OPT | pNFS (OPT) | Section 18.41 |
|
||||
| GETFH | REQ | | Section 18.8 |
|
||||
NS*| GET_DIR_DELEGATION | OPT | DDELG (REQ) | Section 18.39 |
|
||||
P | LAYOUTCOMMIT | OPT | pNFS (REQ) | Section 18.42 |
|
||||
P | LAYOUTGET | OPT | pNFS (REQ) | Section 18.43 |
|
||||
P | LAYOUTRETURN | OPT | pNFS (REQ) | Section 18.44 |
|
||||
| LINK | OPT | | Section 18.9 |
|
||||
| LOCK | REQ | | Section 18.10 |
|
||||
| LOCKT | REQ | | Section 18.11 |
|
||||
| LOCKU | REQ | | Section 18.12 |
|
||||
| LOOKUP | REQ | | Section 18.13 |
|
||||
| LOOKUPP | REQ | | Section 18.14 |
|
||||
| NVERIFY | REQ | | Section 18.15 |
|
||||
| OPEN | REQ | | Section 18.16 |
|
||||
NS*| OPENATTR | OPT | | Section 18.17 |
|
||||
| OPEN_CONFIRM | MNI | | N/A |
|
||||
| OPEN_DOWNGRADE | REQ | | Section 18.18 |
|
||||
| PUTFH | REQ | | Section 18.19 |
|
||||
| PUTPUBFH | REQ | | Section 18.20 |
|
||||
| PUTROOTFH | REQ | | Section 18.21 |
|
||||
| READ | REQ | | Section 18.22 |
|
||||
| READDIR | REQ | | Section 18.23 |
|
||||
| READLINK | OPT | | Section 18.24 |
|
||||
NS | RECLAIM_COMPLETE | REQ | | Section 18.51 |
|
||||
| RELEASE_LOCKOWNER | MNI | | N/A |
|
||||
| REMOVE | REQ | | Section 18.25 |
|
||||
| RENAME | REQ | | Section 18.26 |
|
||||
| RENEW | MNI | | N/A |
|
||||
| RESTOREFH | REQ | | Section 18.27 |
|
||||
| SAVEFH | REQ | | Section 18.28 |
|
||||
| SECINFO | REQ | | Section 18.29 |
|
||||
NS | SECINFO_NO_NAME | REC | pNFS files | Section 18.45, |
|
||||
| | | layout (REQ) | Section 13.12 |
|
||||
I | SEQUENCE | REQ | | Section 18.46 |
|
||||
| SETATTR | REQ | | Section 18.30 |
|
||||
| SETCLIENTID | MNI | | N/A |
|
||||
| SETCLIENTID_CONFIRM | MNI | | N/A |
|
||||
NS | SET_SSV | REQ | | Section 18.47 |
|
||||
NS | TEST_STATEID | REQ | | Section 18.48 |
|
||||
| VERIFY | REQ | | Section 18.31 |
|
||||
NS*| WANT_DELEGATION | OPT | FDELG (OPT) | Section 18.49 |
|
||||
| WRITE | REQ | | Section 18.32 |
|
||||
|
||||
Callback Operations
|
||||
|
||||
+-------------------------+-----------+-------------+---------------+
|
||||
| Operation | REQ, REC, | Feature | Definition |
|
||||
| | OPT, or | (REQ, REC, | |
|
||||
| | MNI | or OPT) | |
|
||||
+-------------------------+-----------+-------------+---------------+
|
||||
| CB_GETATTR | OPT | FDELG (REQ) | Section 20.1 |
|
||||
P | CB_LAYOUTRECALL | OPT | pNFS (REQ) | Section 20.3 |
|
||||
NS*| CB_NOTIFY | OPT | DDELG (REQ) | Section 20.4 |
|
||||
P | CB_NOTIFY_DEVICEID | OPT | pNFS (OPT) | Section 20.12 |
|
||||
NS*| CB_NOTIFY_LOCK | OPT | | Section 20.11 |
|
||||
NS*| CB_PUSH_DELEG | OPT | FDELG (OPT) | Section 20.5 |
|
||||
| CB_RECALL | OPT | FDELG, | Section 20.2 |
|
||||
| | | DDELG, pNFS | |
|
||||
| | | (REQ) | |
|
||||
NS*| CB_RECALL_ANY | OPT | FDELG, | Section 20.6 |
|
||||
| | | DDELG, pNFS | |
|
||||
| | | (REQ) | |
|
||||
NS | CB_RECALL_SLOT | REQ | | Section 20.8 |
|
||||
NS*| CB_RECALLABLE_OBJ_AVAIL | OPT | DDELG, pNFS | Section 20.7 |
|
||||
| | | (REQ) | |
|
||||
I | CB_SEQUENCE | OPT | FDELG, | Section 20.9 |
|
||||
| | | DDELG, pNFS | |
|
||||
| | | (REQ) | |
|
||||
NS*| CB_WANTS_CANCELLED | OPT | FDELG, | Section 20.10 |
|
||||
| | | DDELG, pNFS | |
|
||||
| | | (REQ) | |
|
||||
+-------------------------+-----------+-------------+---------------+
|
||||
|
||||
Implementation notes:
|
||||
|
||||
EXCHANGE_ID:
|
||||
* only SP4_NONE state protection supported
|
||||
* implementation ids are ignored
|
||||
|
||||
CREATE_SESSION:
|
||||
* backchannel attributes are ignored
|
||||
* backchannel security parameters are ignored
|
||||
|
||||
SEQUENCE:
|
||||
* no support for dynamic slot table renegotiation (optional)
|
||||
|
||||
nfsv4.1 COMPOUND rules:
|
||||
The following cases aren't supported yet:
|
||||
* Enforcing of NFS4ERR_NOT_ONLY_OP for: BIND_CONN_TO_SESSION, CREATE_SESSION,
|
||||
DESTROY_CLIENTID, DESTROY_SESSION, EXCHANGE_ID.
|
||||
* DESTROY_SESSION MUST be the final operation in the COMPOUND request.
|
||||
|
|
@ -153,60 +153,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
1,0: use 1st APIC table
|
||||
default: 0
|
||||
|
||||
acpi_sleep= [HW,ACPI] Sleep options
|
||||
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
|
||||
old_ordering, s4_nonvs }
|
||||
See Documentation/power/video.txt for information on
|
||||
s3_bios and s3_mode.
|
||||
s3_beep is for debugging; it makes the PC's speaker beep
|
||||
as soon as the kernel's real-mode entry point is called.
|
||||
s4_nohwsig prevents ACPI hardware signature from being
|
||||
used during resume from hibernation.
|
||||
old_ordering causes the ACPI 1.0 ordering of the _PTS
|
||||
control method, with respect to putting devices into
|
||||
low power states, to be enforced (the ACPI 2.0 ordering
|
||||
of _PTS is used by default).
|
||||
s4_nonvs prevents the kernel from saving/restoring the
|
||||
ACPI NVS memory during hibernation.
|
||||
|
||||
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
|
||||
Format: { level | edge | high | low }
|
||||
|
||||
acpi_irq_balance [HW,ACPI]
|
||||
ACPI will balance active IRQs
|
||||
default in APIC mode
|
||||
|
||||
acpi_irq_nobalance [HW,ACPI]
|
||||
ACPI will not move active IRQs (default)
|
||||
default in PIC mode
|
||||
|
||||
acpi_irq_pci= [HW,ACPI] If irq_balance, clear listed IRQs for
|
||||
use by PCI
|
||||
Format: <irq>,<irq>...
|
||||
|
||||
acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
|
||||
Format: <irq>,<irq>...
|
||||
|
||||
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
|
||||
|
||||
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
|
||||
Format: To spoof as Windows 98: ="Microsoft Windows"
|
||||
|
||||
acpi_osi= [HW,ACPI] Modify list of supported OS interface strings
|
||||
acpi_osi="string1" # add string1 -- only one string
|
||||
acpi_osi="!string2" # remove built-in string2
|
||||
acpi_osi= # disable all strings
|
||||
|
||||
acpi_serialize [HW,ACPI] force serialization of AML methods
|
||||
|
||||
acpi_skip_timer_override [HW,ACPI]
|
||||
Recognize and ignore IRQ0/pin2 Interrupt Override.
|
||||
For broken nForce2 BIOS resulting in XT-PIC timer.
|
||||
acpi_use_timer_override [HW,ACPI]
|
||||
Use timer override. For some broken Nvidia NF5 boards
|
||||
that require a timer override, but don't have
|
||||
HPET
|
||||
|
||||
acpi_backlight= [HW,ACPI]
|
||||
acpi_backlight=vendor
|
||||
acpi_backlight=video
|
||||
|
@ -214,11 +160,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
(e.g. thinkpad_acpi, sony_acpi, etc.) instead
|
||||
of the ACPI video.ko driver.
|
||||
|
||||
acpi_display_output= [HW,ACPI]
|
||||
acpi_display_output=vendor
|
||||
acpi_display_output=video
|
||||
See above.
|
||||
|
||||
acpi.debug_layer= [HW,ACPI,ACPI_DEBUG]
|
||||
acpi.debug_level= [HW,ACPI,ACPI_DEBUG]
|
||||
Format: <int>
|
||||
|
@ -247,6 +188,41 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
unusable. The "log_buf_len" parameter may be useful
|
||||
if you need to capture more output.
|
||||
|
||||
acpi_display_output= [HW,ACPI]
|
||||
acpi_display_output=vendor
|
||||
acpi_display_output=video
|
||||
See above.
|
||||
|
||||
acpi_irq_balance [HW,ACPI]
|
||||
ACPI will balance active IRQs
|
||||
default in APIC mode
|
||||
|
||||
acpi_irq_nobalance [HW,ACPI]
|
||||
ACPI will not move active IRQs (default)
|
||||
default in PIC mode
|
||||
|
||||
acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
|
||||
Format: <irq>,<irq>...
|
||||
|
||||
acpi_irq_pci= [HW,ACPI] If irq_balance, clear listed IRQs for
|
||||
use by PCI
|
||||
Format: <irq>,<irq>...
|
||||
|
||||
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
|
||||
|
||||
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
|
||||
Format: To spoof as Windows 98: ="Microsoft Windows"
|
||||
|
||||
acpi_osi= [HW,ACPI] Modify list of supported OS interface strings
|
||||
acpi_osi="string1" # add string1 -- only one string
|
||||
acpi_osi="!string2" # remove built-in string2
|
||||
acpi_osi= # disable all strings
|
||||
|
||||
acpi_pm_good [X86-32,X86-64]
|
||||
Override the pmtimer bug detection: force the kernel
|
||||
to assume that this machine's pmtimer latches its value
|
||||
and always returns good values.
|
||||
|
||||
acpi.power_nocheck= [HW,ACPI]
|
||||
Format: 1/0 enable/disable the check of power state.
|
||||
On some bogus BIOS the _PSC object/_STA object of
|
||||
|
@ -255,11 +231,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
power state again in power transition.
|
||||
1 : disable the power state check
|
||||
|
||||
acpi_pm_good [X86-32,X86-64]
|
||||
Override the pmtimer bug detection: force the kernel
|
||||
to assume that this machine's pmtimer latches its value
|
||||
and always returns good values.
|
||||
|
||||
acpi_enforce_resources= [ACPI]
|
||||
{ strict | lax | no }
|
||||
Check for resource conflicts between native drivers
|
||||
|
@ -276,22 +247,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
no: ACPI OperationRegions are not marked as reserved,
|
||||
no further checks are performed.
|
||||
|
||||
agp= [AGP]
|
||||
{ off | try_unsupported }
|
||||
off: disable AGP support
|
||||
try_unsupported: try to drive unsupported chipsets
|
||||
(may crash computer or cause data corruption)
|
||||
|
||||
enable_timer_pin_1 [i386,x86-64]
|
||||
Enable PIN 1 of APIC timer
|
||||
Can be useful to work around chipset bugs
|
||||
(in particular on some ATI chipsets).
|
||||
The kernel tries to set a reasonable default.
|
||||
|
||||
disable_timer_pin_1 [i386,x86-64]
|
||||
Disable PIN 1 of APIC timer
|
||||
Can be useful to work around chipset bugs.
|
||||
|
||||
ad1848= [HW,OSS]
|
||||
Format: <io>,<irq>,<dma>,<dma2>,<type>
|
||||
|
||||
|
@ -305,6 +260,12 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq>
|
||||
See also header of sound/oss/aedsp16.c.
|
||||
|
||||
agp= [AGP]
|
||||
{ off | try_unsupported }
|
||||
off: disable AGP support
|
||||
try_unsupported: try to drive unsupported chipsets
|
||||
(may crash computer or cause data corruption)
|
||||
|
||||
aha152x= [HW,SCSI]
|
||||
See Documentation/scsi/aha152x.txt.
|
||||
|
||||
|
@ -432,12 +393,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
possible to determine what the correct size should be.
|
||||
This option provides an override for these situations.
|
||||
|
||||
security= [SECURITY] Choose a security module to enable at boot.
|
||||
If this boot parameter is not specified, only the first
|
||||
security module asking for security registration will be
|
||||
loaded. An invalid security module name will be treated
|
||||
as if no module has been chosen.
|
||||
|
||||
capability.disable=
|
||||
[SECURITY] Disable capabilities. This would normally
|
||||
be used only if an alternative security model is to be
|
||||
|
@ -509,24 +464,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Range: 0 - 8192
|
||||
Default: 64
|
||||
|
||||
dma_debug=off If the kernel is compiled with DMA_API_DEBUG support
|
||||
this option disables the debugging code at boot.
|
||||
|
||||
dma_debug_entries=<number>
|
||||
This option allows to tune the number of preallocated
|
||||
entries for DMA-API debugging code. One entry is
|
||||
required per DMA-API allocation. Use this if the
|
||||
DMA-API debugging code disables itself because the
|
||||
architectural default is too low.
|
||||
|
||||
hpet= [X86-32,HPET] option to control HPET usage
|
||||
Format: { enable (default) | disable | force |
|
||||
verbose }
|
||||
disable: disable HPET and use PIT instead
|
||||
force: allow force enabled of undocumented chips (ICH4,
|
||||
VIA, nVidia)
|
||||
verbose: show contents of HPET registers during setup
|
||||
|
||||
com20020= [HW,NET] ARCnet - COM20020 chipset
|
||||
Format:
|
||||
<io>[,<irq>[,<nodeID>[,<backplane>[,<ckp>[,<timeout>]]]]]
|
||||
|
@ -570,23 +507,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
console=brl,ttyS0
|
||||
For now, only VisioBraille is supported.
|
||||
|
||||
earlycon= [KNL] Output early console device and options.
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
Start an early, polled-mode console on the 8250/16550
|
||||
UART at the specified I/O port or MMIO address.
|
||||
The options are the same as for ttyS, above.
|
||||
|
||||
no_console_suspend
|
||||
[HW] Never suspend the console
|
||||
Disable suspending of consoles during suspend and
|
||||
hibernate operations. Once disabled, debugging
|
||||
messages can reach various consoles while the rest
|
||||
of the system is being put to sleep (ie, while
|
||||
debugging driver suspend/resume hooks). This may
|
||||
not work reliably with all consoles, but is known
|
||||
to work with serial and VGA consoles.
|
||||
|
||||
coredump_filter=
|
||||
[KNL] Change the default value for
|
||||
/proc/<pid>/coredump_filter.
|
||||
|
@ -643,30 +563,13 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Format: <area>[,<node>]
|
||||
See also Documentation/networking/decnet.txt.
|
||||
|
||||
vt.default_blu= [VT]
|
||||
Format: <blue0>,<blue1>,<blue2>,...,<blue15>
|
||||
Change the default blue palette of the console.
|
||||
This is a 16-member array composed of values
|
||||
ranging from 0-255.
|
||||
|
||||
vt.default_grn= [VT]
|
||||
Format: <green0>,<green1>,<green2>,...,<green15>
|
||||
Change the default green palette of the console.
|
||||
This is a 16-member array composed of values
|
||||
ranging from 0-255.
|
||||
|
||||
vt.default_red= [VT]
|
||||
Format: <red0>,<red1>,<red2>,...,<red15>
|
||||
Change the default red palette of the console.
|
||||
This is a 16-member array composed of values
|
||||
ranging from 0-255.
|
||||
|
||||
vt.default_utf8=
|
||||
[VT]
|
||||
Format=<0|1>
|
||||
Set system-wide default UTF-8 mode for all tty's.
|
||||
Default is 1, i.e. UTF-8 mode is enabled for all
|
||||
newly opened terminals.
|
||||
default_hugepagesz=
|
||||
[same as hugepagesz=] The size of the default
|
||||
HugeTLB page size. This is the size represented by
|
||||
the legacy /proc/ hugepages APIs, used for SHM, and
|
||||
default size when mounting hugetlbfs filesystems.
|
||||
Defaults to the default architecture's huge page size
|
||||
if not specified.
|
||||
|
||||
dhash_entries= [KNL]
|
||||
Set number of hash buckets for dentry cache.
|
||||
|
@ -679,27 +582,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Documentation/serial/digiepca.txt.
|
||||
|
||||
disable_mtrr_cleanup [X86]
|
||||
enable_mtrr_cleanup [X86]
|
||||
The kernel tries to adjust MTRR layout from continuous
|
||||
to discrete, to make X server driver able to add WB
|
||||
entry later. This parameter enables/disables that.
|
||||
|
||||
mtrr_chunk_size=nn[KMG] [X86]
|
||||
used for mtrr cleanup. It is largest continous chunk
|
||||
that could hold holes aka. UC entries.
|
||||
|
||||
mtrr_gran_size=nn[KMG] [X86]
|
||||
Used for mtrr cleanup. It is granularity of mtrr block.
|
||||
Default is 1.
|
||||
Large value could prevent small alignment from
|
||||
using up MTRRs.
|
||||
|
||||
mtrr_spare_reg_nr=n [X86]
|
||||
Format: <integer>
|
||||
Range: 0,7 : spare reg number
|
||||
Default : 1
|
||||
Used for mtrr cleanup. It is spare mtrr entries number.
|
||||
Set to 2 or more if your graphical card needs more.
|
||||
entry later. This parameter disables that.
|
||||
|
||||
disable_mtrr_trim [X86, Intel and AMD only]
|
||||
By default the kernel will trim any uncacheable
|
||||
|
@ -707,12 +592,38 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
MTRR settings. This parameter disables that behavior,
|
||||
possibly causing your machine to run very slowly.
|
||||
|
||||
disable_timer_pin_1 [i386,x86-64]
|
||||
Disable PIN 1 of APIC timer
|
||||
Can be useful to work around chipset bugs.
|
||||
|
||||
dmasound= [HW,OSS] Sound subsystem buffers
|
||||
|
||||
dma_debug=off If the kernel is compiled with DMA_API_DEBUG support,
|
||||
this option disables the debugging code at boot.
|
||||
|
||||
dma_debug_entries=<number>
|
||||
This option allows to tune the number of preallocated
|
||||
entries for DMA-API debugging code. One entry is
|
||||
required per DMA-API allocation. Use this if the
|
||||
DMA-API debugging code disables itself because the
|
||||
architectural default is too low.
|
||||
|
||||
dscc4.setup= [NET]
|
||||
|
||||
dtc3181e= [HW,SCSI]
|
||||
|
||||
dynamic_printk Enables pr_debug()/dev_dbg() calls if
|
||||
CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled.
|
||||
These can also be switched on/off via
|
||||
<debugfs>/dynamic_printk/modules
|
||||
|
||||
earlycon= [KNL] Output early console device and options.
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
Start an early, polled-mode console on the 8250/16550
|
||||
UART at the specified I/O port or MMIO address.
|
||||
The options are the same as for ttyS, above.
|
||||
|
||||
earlyprintk= [X86-32,X86-64,SH,BLACKFIN]
|
||||
earlyprintk=vga
|
||||
earlyprintk=serial[,ttySn[,baudrate]]
|
||||
|
@ -754,6 +665,17 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
pass this option to capture kernel.
|
||||
See Documentation/kdump/kdump.txt for details.
|
||||
|
||||
enable_mtrr_cleanup [X86]
|
||||
The kernel tries to adjust MTRR layout from continuous
|
||||
to discrete, to make X server driver able to add WB
|
||||
entry later. This parameter enables that.
|
||||
|
||||
enable_timer_pin_1 [i386,x86-64]
|
||||
Enable PIN 1 of APIC timer
|
||||
Can be useful to work around chipset bugs
|
||||
(in particular on some ATI chipsets).
|
||||
The kernel tries to set a reasonable default.
|
||||
|
||||
enforcing [SELINUX] Set initial enforcing status.
|
||||
Format: {"0" | "1"}
|
||||
See security/selinux/Kconfig help text.
|
||||
|
@ -841,6 +763,16 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
hisax= [HW,ISDN]
|
||||
See Documentation/isdn/README.HiSax.
|
||||
|
||||
hlt [BUGS=ARM,SH]
|
||||
|
||||
hpet= [X86-32,HPET] option to control HPET usage
|
||||
Format: { enable (default) | disable | force |
|
||||
verbose }
|
||||
disable: disable HPET and use PIT instead
|
||||
force: allow force enabled of undocumented chips (ICH4,
|
||||
VIA, nVidia)
|
||||
verbose: show contents of HPET registers during setup
|
||||
|
||||
hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot.
|
||||
hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages.
|
||||
On x86-64 and powerpc, this option can be specified
|
||||
|
@ -850,15 +782,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
(when the CPU supports the "pdpe1gb" cpuinfo flag)
|
||||
Note that 1GB pages can only be allocated at boot time
|
||||
using hugepages= and not freed afterwards.
|
||||
default_hugepagesz=
|
||||
[same as hugepagesz=] The size of the default
|
||||
HugeTLB page size. This is the size represented by
|
||||
the legacy /proc/ hugepages APIs, used for SHM, and
|
||||
default size when mounting hugetlbfs filesystems.
|
||||
Defaults to the default architecture's huge page size
|
||||
if not specified.
|
||||
|
||||
hlt [BUGS=ARM,SH]
|
||||
|
||||
hvc_iucv= [S390] Number of z/VM IUCV hypervisor console (HVC)
|
||||
terminal devices. Valid values: 0..8
|
||||
|
@ -919,6 +842,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed
|
||||
See Documentation/ide/ide.txt.
|
||||
|
||||
ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
|
||||
Claim all unknown PCI IDE storage controllers.
|
||||
|
||||
idle= [X86]
|
||||
Format: idle=poll, idle=mwait, idle=halt, idle=nomwait
|
||||
Poll forces a polling idle loop that can slightly
|
||||
|
@ -934,9 +860,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
In such case C2/C3 won't be used again.
|
||||
idle=nomwait: Disable mwait for CPU C-states
|
||||
|
||||
ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
|
||||
Claim all unknown PCI IDE storage controllers.
|
||||
|
||||
ignore_loglevel [KNL]
|
||||
Ignore loglevel setting - this will print /all/
|
||||
kernel messages to the console. Useful for debugging.
|
||||
|
@ -970,25 +893,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
|
||||
Format: <irq>
|
||||
|
||||
inttest= [IA64]
|
||||
|
||||
iomem= Disable strict checking of access to MMIO memory
|
||||
strict regions from userspace.
|
||||
relaxed
|
||||
|
||||
iommu= [x86]
|
||||
off
|
||||
force
|
||||
noforce
|
||||
biomerge
|
||||
panic
|
||||
nopanic
|
||||
merge
|
||||
nomerge
|
||||
forcesac
|
||||
soft
|
||||
|
||||
|
||||
intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option
|
||||
on
|
||||
Enable intel iommu driver.
|
||||
|
@ -1012,6 +916,28 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
result in a hardware IOTLB flush operation as opposed
|
||||
to batching them for performance.
|
||||
|
||||
inttest= [IA64]
|
||||
|
||||
iomem= Disable strict checking of access to MMIO memory
|
||||
strict regions from userspace.
|
||||
relaxed
|
||||
|
||||
iommu= [x86]
|
||||
off
|
||||
force
|
||||
noforce
|
||||
biomerge
|
||||
panic
|
||||
nopanic
|
||||
merge
|
||||
nomerge
|
||||
forcesac
|
||||
soft
|
||||
|
||||
io7= [HW] IO7 for Marvel based alpha systems
|
||||
See comment before marvel_specify_io7 in
|
||||
arch/alpha/kernel/core_marvel.c.
|
||||
|
||||
io_delay= [X86-32,X86-64] I/O delay method
|
||||
0x80
|
||||
Standard port 0x80 based delay
|
||||
|
@ -1022,10 +948,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
none
|
||||
No delay
|
||||
|
||||
io7= [HW] IO7 for Marvel based alpha systems
|
||||
See comment before marvel_specify_io7 in
|
||||
arch/alpha/kernel/core_marvel.c.
|
||||
|
||||
ip= [IP_PNP]
|
||||
See Documentation/filesystems/nfsroot.txt.
|
||||
|
||||
|
@ -1036,12 +958,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
ips= [HW,SCSI] Adaptec / IBM ServeRAID controller
|
||||
See header of drivers/scsi/ips.c.
|
||||
|
||||
ports= [IP_VS_FTP] IPVS ftp helper module
|
||||
Default is 21.
|
||||
Up to 8 (IP_VS_APP_MAX_PORTS) ports
|
||||
may be specified.
|
||||
Format: <port>,<port>....
|
||||
|
||||
irqfixup [HW]
|
||||
When an interrupt is not handled search all handlers
|
||||
for it. Intended to get systems with badly broken
|
||||
|
@ -1082,6 +998,8 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
js= [HW,JOY] Analog joystick
|
||||
See Documentation/input/joystick.txt.
|
||||
|
||||
keepinitrd [HW,ARM]
|
||||
|
||||
kernelcore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter
|
||||
specifies the amount of memory usable by the kernel
|
||||
for non-movable allocations. The requested amount is
|
||||
|
@ -1107,21 +1025,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
higher than default (KMEMTRACE_N_SUBBUFS in code) if
|
||||
you experience buffer overruns.
|
||||
|
||||
movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter
|
||||
is similar to kernelcore except it specifies the
|
||||
amount of memory used for migratable allocations.
|
||||
If both kernelcore and movablecore is specified,
|
||||
then kernelcore will be at *least* the specified
|
||||
value but may be more. If movablecore on its own
|
||||
is specified, the administrator must be careful
|
||||
that the amount of memory usable for all allocations
|
||||
is not too small.
|
||||
|
||||
keepinitrd [HW,ARM]
|
||||
|
||||
kstack=N [X86-32,X86-64] Print N words from the kernel stack
|
||||
in oops dumps.
|
||||
|
||||
kgdboc= [HW] kgdb over consoles.
|
||||
Requires a tty driver that supports console polling.
|
||||
(only serial suported for now)
|
||||
|
@ -1131,6 +1034,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Configure the RouterBoard 532 series on-chip
|
||||
Ethernet adapter MAC address.
|
||||
|
||||
kstack=N [X86-32,X86-64] Print N words from the kernel stack
|
||||
in oops dumps.
|
||||
|
||||
l2cr= [PPC]
|
||||
|
||||
l3cr= [PPC]
|
||||
|
@ -1276,9 +1182,8 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
(machvec) in a generic kernel.
|
||||
Example: machvec=hpzx1_swiotlb
|
||||
|
||||
max_loop= [LOOP] Maximum number of loopback devices that can
|
||||
be mounted
|
||||
Format: <1-256>
|
||||
max_addr=nn[KMG] [KNL,BOOT,ia64] All physical memory greater
|
||||
than or equal to this physical address is ignored.
|
||||
|
||||
maxcpus= [SMP] Maximum number of processors that an SMP kernel
|
||||
should make use of. maxcpus=n : n >= 0 limits the
|
||||
|
@ -1286,8 +1191,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
it is equivalent to "nosmp", which also disables
|
||||
the IO APIC.
|
||||
|
||||
max_addr=nn[KMG] [KNL,BOOT,ia64] All physical memory greater than
|
||||
or equal to this physical address is ignored.
|
||||
max_loop= [LOOP] Maximum number of loopback devices that can
|
||||
be mounted
|
||||
Format: <1-256>
|
||||
|
||||
max_luns= [SCSI] Maximum number of LUNs to probe.
|
||||
Should be between 1 and 2^32-1.
|
||||
|
@ -1414,6 +1320,16 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
mousedev.yres= [MOUSE] Vertical screen resolution, used for devices
|
||||
reporting absolute coordinates, such as tablets
|
||||
|
||||
movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter
|
||||
is similar to kernelcore except it specifies the
|
||||
amount of memory used for migratable allocations.
|
||||
If both kernelcore and movablecore is specified,
|
||||
then kernelcore will be at *least* the specified
|
||||
value but may be more. If movablecore on its own
|
||||
is specified, the administrator must be careful
|
||||
that the amount of memory usable for all allocations
|
||||
is not too small.
|
||||
|
||||
mpu401= [HW,OSS]
|
||||
Format: <io>,<irq>
|
||||
|
||||
|
@ -1435,6 +1351,23 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
[HW] Make the MicroTouch USB driver use raw coordinates
|
||||
('y', default) or cooked coordinates ('n')
|
||||
|
||||
mtrr_chunk_size=nn[KMG] [X86]
|
||||
used for mtrr cleanup. It is largest continous chunk
|
||||
that could hold holes aka. UC entries.
|
||||
|
||||
mtrr_gran_size=nn[KMG] [X86]
|
||||
Used for mtrr cleanup. It is granularity of mtrr block.
|
||||
Default is 1.
|
||||
Large value could prevent small alignment from
|
||||
using up MTRRs.
|
||||
|
||||
mtrr_spare_reg_nr=n [X86]
|
||||
Format: <integer>
|
||||
Range: 0,7 : spare reg number
|
||||
Default : 1
|
||||
Used for mtrr cleanup. It is spare mtrr entries number.
|
||||
Set to 2 or more if your graphical card needs more.
|
||||
|
||||
n2= [NET] SDL Inc. RISCom/N2 synchronous serial card
|
||||
|
||||
NCR_D700= [HW,SCSI]
|
||||
|
@ -1495,11 +1428,13 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
0 - turn nmi_watchdog off
|
||||
1 - use the IO-APIC timer for the NMI watchdog
|
||||
2 - use the local APIC for the NMI watchdog using
|
||||
a performance counter. Note: This will use one performance
|
||||
counter and the local APIC's performance vector.
|
||||
When panic is specified panic when an NMI watchdog timeout occurs.
|
||||
This is useful when you use a panic=... timeout and need the box
|
||||
quickly up again.
|
||||
a performance counter. Note: This will use one
|
||||
performance counter and the local APIC's performance
|
||||
vector.
|
||||
When panic is specified, panic when an NMI watchdog
|
||||
timeout occurs.
|
||||
This is useful when you use a panic=... timeout and
|
||||
need the box quickly up again.
|
||||
Instead of 1 and 2 it is possible to use the following
|
||||
symbolic names: lapic and ioapic
|
||||
Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic
|
||||
|
@ -1508,6 +1443,16 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
emulation library even if a 387 maths coprocessor
|
||||
is present.
|
||||
|
||||
no_console_suspend
|
||||
[HW] Never suspend the console
|
||||
Disable suspending of consoles during suspend and
|
||||
hibernate operations. Once disabled, debugging
|
||||
messages can reach various consoles while the rest
|
||||
of the system is being put to sleep (ie, while
|
||||
debugging driver suspend/resume hooks). This may
|
||||
not work reliably with all consoles, but is known
|
||||
to work with serial and VGA consoles.
|
||||
|
||||
noaliencache [MM, NUMA, SLAB] Disables the allocation of alien
|
||||
caches in the slab allocator. Saves per-node memory,
|
||||
but will impact performance.
|
||||
|
@ -1522,6 +1467,8 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
|
||||
nocache [ARM]
|
||||
|
||||
noclflush [BUGS=X86] Don't use the CLFLUSH instruction
|
||||
|
||||
nodelayacct [KNL] Disable per-task delay accounting
|
||||
|
||||
nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects.
|
||||
|
@ -1550,8 +1497,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
register save and restore. The kernel will only save
|
||||
legacy floating-point registers on task switch.
|
||||
|
||||
noclflush [BUGS=X86] Don't use the CLFLUSH instruction
|
||||
|
||||
nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
|
||||
wfi(ARM) instruction doesn't work correctly and not to
|
||||
use it. This is also useful when using JTAG debugger.
|
||||
|
@ -1596,12 +1541,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
|
||||
nolapic_timer [X86-32,APIC] Do not use the local APIC timer.
|
||||
|
||||
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
|
||||
|
||||
x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of
|
||||
default x2apic cluster mode on platforms
|
||||
supporting x2apic.
|
||||
|
||||
noltlbs [PPC] Do not use large page/tlb entries for kernel
|
||||
lowmem mapping on PPC40x.
|
||||
|
||||
|
@ -1612,6 +1551,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
nomfgpt [X86-32] Disable Multi-Function General Purpose
|
||||
Timer usage (for AMD Geode machines).
|
||||
|
||||
norandmaps Don't use address space randomization. Equivalent to
|
||||
echo 0 > /proc/sys/kernel/randomize_va_space
|
||||
|
||||
noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops
|
||||
|
||||
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
|
||||
|
@ -1650,13 +1592,13 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
purges which is reported from either PAL_VM_SUMMARY or
|
||||
SAL PALO.
|
||||
|
||||
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
|
||||
|
||||
numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA.
|
||||
one of ['zone', 'node', 'default'] can be specified
|
||||
This can be set from sysctl after boot.
|
||||
See Documentation/sysctl/vm.txt for details.
|
||||
|
||||
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
|
||||
|
||||
ohci1394_dma=early [HW] enable debugging via the ohci1394 driver.
|
||||
See Documentation/debugging-via-ohci1394.txt for more
|
||||
info.
|
||||
|
@ -1905,6 +1847,14 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
printk.time= Show timing data prefixed to each printk message line
|
||||
Format: <bool> (1/Y/y=enable, 0/N/n=disable)
|
||||
|
||||
processor.max_cstate= [HW,ACPI]
|
||||
Limit processor to maximum C-state
|
||||
max_cstate=9 overrides any DMI blacklist limit.
|
||||
|
||||
processor.nocst [HW,ACPI]
|
||||
Ignore the _CST method to determine C-states,
|
||||
instead using the legacy FADT method
|
||||
|
||||
profile= [KNL] Enable kernel profiling via /proc/profile
|
||||
Format: [schedule,]<number>
|
||||
Param: "schedule" - profile schedule points.
|
||||
|
@ -1914,14 +1864,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Requires CONFIG_SCHEDSTATS
|
||||
Param: "kvm" - profile VM exits.
|
||||
|
||||
processor.max_cstate= [HW,ACPI]
|
||||
Limit processor to maximum C-state
|
||||
max_cstate=9 overrides any DMI blacklist limit.
|
||||
|
||||
processor.nocst [HW,ACPI]
|
||||
Ignore the _CST method to determine C-states,
|
||||
instead using the legacy FADT method
|
||||
|
||||
prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk
|
||||
before loading.
|
||||
See Documentation/blockdev/ramdisk.txt.
|
||||
|
@ -2075,7 +2017,13 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
allowing boot to proceed. none ignores them, expecting
|
||||
user space to do the scan.
|
||||
|
||||
selinux [SELINUX] Disable or enable SELinux at boot time.
|
||||
security= [SECURITY] Choose a security module to enable at boot.
|
||||
If this boot parameter is not specified, only the first
|
||||
security module asking for security registration will be
|
||||
loaded. An invalid security module name will be treated
|
||||
as if no module has been chosen.
|
||||
|
||||
selinux= [SELINUX] Disable or enable SELinux at boot time.
|
||||
Format: { "0" | "1" }
|
||||
See security/selinux/Kconfig help text.
|
||||
0 -- disable.
|
||||
|
@ -2499,9 +2447,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
medium is write-protected).
|
||||
Example: quirks=0419:aaf5:rl,0421:0433:rc
|
||||
|
||||
add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in
|
||||
kernel's map of available physical RAM.
|
||||
|
||||
vdso= [X86-32,SH,x86-64]
|
||||
vdso=2: enable compat VDSO (default with COMPAT_VDSO)
|
||||
vdso=1: enable VDSO (default)
|
||||
|
@ -2540,6 +2485,31 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
vmpoff= [KNL,S390] Perform z/VM CP command after power off.
|
||||
Format: <command>
|
||||
|
||||
vt.default_blu= [VT]
|
||||
Format: <blue0>,<blue1>,<blue2>,...,<blue15>
|
||||
Change the default blue palette of the console.
|
||||
This is a 16-member array composed of values
|
||||
ranging from 0-255.
|
||||
|
||||
vt.default_grn= [VT]
|
||||
Format: <green0>,<green1>,<green2>,...,<green15>
|
||||
Change the default green palette of the console.
|
||||
This is a 16-member array composed of values
|
||||
ranging from 0-255.
|
||||
|
||||
vt.default_red= [VT]
|
||||
Format: <red0>,<red1>,<red2>,...,<red15>
|
||||
Change the default red palette of the console.
|
||||
This is a 16-member array composed of values
|
||||
ranging from 0-255.
|
||||
|
||||
vt.default_utf8=
|
||||
[VT]
|
||||
Format=<0|1>
|
||||
Set system-wide default UTF-8 mode for all tty's.
|
||||
Default is 1, i.e. UTF-8 mode is enabled for all
|
||||
newly opened terminals.
|
||||
|
||||
waveartist= [HW,OSS]
|
||||
Format: <io>,<irq>,<dma>,<dma2>
|
||||
|
||||
|
@ -2552,6 +2522,10 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
wdt= [WDT] Watchdog
|
||||
See Documentation/watchdog/wdt.txt.
|
||||
|
||||
x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of
|
||||
default x2apic cluster mode on platforms
|
||||
supporting x2apic.
|
||||
|
||||
xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks.
|
||||
xd_geo= See header of drivers/block/xd.c.
|
||||
|
||||
|
@ -2559,9 +2533,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Format:
|
||||
<irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
|
||||
|
||||
norandmaps Don't use address space randomization. Equivalent to
|
||||
echo 0 > /proc/sys/kernel/randomize_va_space
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
TODO:
|
||||
|
|
|
@ -5,9 +5,21 @@ Required properties:
|
|||
- reg : should specify localbus chip select and size used for the chip.
|
||||
- fsl,upm-addr-offset : UPM pattern offset for the address latch.
|
||||
- fsl,upm-cmd-offset : UPM pattern offset for the command latch.
|
||||
- gpios : may specify optional GPIO connected to the Ready-Not-Busy pin.
|
||||
|
||||
Example:
|
||||
Optional properties:
|
||||
- fsl,upm-wait-flags : add chip-dependent short delays after running the
|
||||
UPM pattern (0x1), after writing a data byte (0x2) or after
|
||||
writing out a buffer (0x4).
|
||||
- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
|
||||
The corresponding address lines are used to select the chip.
|
||||
- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
|
||||
(R/B#). For multi-chip devices, "n" GPIO definitions are required
|
||||
according to the number of chips.
|
||||
- chip-delay : chip dependent delay for transfering data from array to
|
||||
read registers (tR). Required if property "gpios" is not used
|
||||
(R/B# pins not connected).
|
||||
|
||||
Examples:
|
||||
|
||||
upm@1,0 {
|
||||
compatible = "fsl,upm-nand";
|
||||
|
@ -26,3 +38,26 @@ upm@1,0 {
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
upm@3,0 {
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
|
||||
reg = <3 0x0 0x800>;
|
||||
fsl,upm-addr-offset = <0x10>;
|
||||
fsl,upm-cmd-offset = <0x08>;
|
||||
/* Multi-chip NAND device */
|
||||
fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
|
||||
fsl,upm-wait-flags = <0x5>;
|
||||
chip-delay = <25>; // in micro-seconds
|
||||
|
||||
nand@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "fs";
|
||||
reg = <0x00000000 0x10000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,15 +1,43 @@
|
|||
LED connected to GPIO
|
||||
LEDs connected to GPIO lines
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "gpio-led".
|
||||
- label : (optional) the label for this LED. If omitted, the label is
|
||||
- compatible : should be "gpio-leds".
|
||||
|
||||
Each LED is represented as a sub-node of the gpio-leds device. Each
|
||||
node's name represents the name of the corresponding LED.
|
||||
|
||||
LED sub-node properties:
|
||||
- gpios : Should specify the LED's GPIO, see "Specifying GPIO information
|
||||
for devices" in Documentation/powerpc/booting-without-of.txt. Active
|
||||
low LEDs should be indicated using flags in the GPIO specifier.
|
||||
- label : (optional) The label for this LED. If omitted, the label is
|
||||
taken from the node name (excluding the unit address).
|
||||
- gpios : should specify LED GPIO.
|
||||
- linux,default-trigger : (optional) This parameter, if present, is a
|
||||
string defining the trigger assigned to the LED. Current triggers are:
|
||||
"backlight" - LED will act as a back-light, controlled by the framebuffer
|
||||
system
|
||||
"default-on" - LED will turn on
|
||||
"heartbeat" - LED "double" flashes at a load average based rate
|
||||
"ide-disk" - LED indicates disk activity
|
||||
"timer" - LED flashes at a fixed, configurable rate
|
||||
|
||||
Example:
|
||||
Examples:
|
||||
|
||||
led@0 {
|
||||
compatible = "gpio-led";
|
||||
label = "hdd";
|
||||
gpios = <&mcu_pio 0 1>;
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
hdd {
|
||||
label = "IDE Activity";
|
||||
gpios = <&mcu_pio 0 1>; /* Active low */
|
||||
linux,default-trigger = "ide-disk";
|
||||
};
|
||||
};
|
||||
|
||||
run-control {
|
||||
compatible = "gpio-leds";
|
||||
red {
|
||||
gpios = <&mpc8572 6 0>;
|
||||
};
|
||||
green {
|
||||
gpios = <&mpc8572 7 0>;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -60,17 +60,9 @@ Supported Cards/Chipsets
|
|||
9005:0285:9005:02d5 Adaptec ASR-2405 (Voodoo40 Lite)
|
||||
9005:0285:9005:02d6 Adaptec ASR-2445 (Voodoo44 Lite)
|
||||
9005:0285:9005:02d7 Adaptec ASR-2805 (Voodoo80 Lite)
|
||||
9005:0285:9005:02d8 Adaptec 5405G (Voodoo40 PM)
|
||||
9005:0285:9005:02d9 Adaptec 5445G (Voodoo44 PM)
|
||||
9005:0285:9005:02da Adaptec 5805G (Voodoo80 PM)
|
||||
9005:0285:9005:02db Adaptec 5085G (Voodoo08 PM)
|
||||
9005:0285:9005:02dc Adaptec 51245G (Voodoo124 PM)
|
||||
9005:0285:9005:02dd Adaptec 51645G (Voodoo164 PM)
|
||||
9005:0285:9005:02de Adaptec 52445G (Voodoo244 PM)
|
||||
9005:0285:9005:02df Adaptec ASR-2045G (Voodoo04 Lite PM)
|
||||
9005:0285:9005:02e0 Adaptec ASR-2405G (Voodoo40 Lite PM)
|
||||
9005:0285:9005:02e1 Adaptec ASR-2445G (Voodoo44 Lite PM)
|
||||
9005:0285:9005:02e2 Adaptec ASR-2805G (Voodoo80 Lite PM)
|
||||
9005:0285:9005:02d8 Adaptec 5405Z (Voodoo40 BLBU)
|
||||
9005:0285:9005:02d9 Adaptec 5445Z (Voodoo44 BLBU)
|
||||
9005:0285:9005:02da Adaptec 5805Z (Voodoo80 BLBU)
|
||||
1011:0046:9005:0364 Adaptec 5400S (Mustang)
|
||||
1011:0046:9005:0365 Adaptec 5400S (Mustang)
|
||||
9005:0287:9005:0800 Adaptec Themisto (Jupiter)
|
||||
|
@ -140,6 +132,7 @@ Deanna Bonds (non-DASD support, PAE fibs and 64 bit,
|
|||
where fibs that go to the hardware are consistently called hw_fibs and
|
||||
not just fibs like the name of the driver tracking structure)
|
||||
Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas. Performance tuning, card failover and bug mitigations.
|
||||
Achim Leubner <Achim_Leubner@adaptec.com>
|
||||
|
||||
Original Driver
|
||||
-------------------------
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* mach-davinci/nand.h
|
||||
*
|
||||
* Copyright © 2006 Texas Instruments.
|
||||
*
|
||||
* Ported to 2.6.23 Copyright © 2008 by
|
||||
* Sander Huijsen <Shuijsen@optelecom-nkf.com>
|
||||
* Troy Kisky <troy.kisky@boundarydevices.com>
|
||||
* Dirk Behme <Dirk.Behme@gmail.com>
|
||||
*
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_DAVINCI_NAND_H
|
||||
#define __ARCH_ARM_DAVINCI_NAND_H
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
|
||||
#define NRCSR_OFFSET 0x00
|
||||
#define AWCCR_OFFSET 0x04
|
||||
#define A1CR_OFFSET 0x10
|
||||
#define NANDFCR_OFFSET 0x60
|
||||
#define NANDFSR_OFFSET 0x64
|
||||
#define NANDF1ECC_OFFSET 0x70
|
||||
|
||||
/* 4-bit ECC syndrome registers */
|
||||
#define NAND_4BIT_ECC_LOAD_OFFSET 0xbc
|
||||
#define NAND_4BIT_ECC1_OFFSET 0xc0
|
||||
#define NAND_4BIT_ECC2_OFFSET 0xc4
|
||||
#define NAND_4BIT_ECC3_OFFSET 0xc8
|
||||
#define NAND_4BIT_ECC4_OFFSET 0xcc
|
||||
#define NAND_ERR_ADD1_OFFSET 0xd0
|
||||
#define NAND_ERR_ADD2_OFFSET 0xd4
|
||||
#define NAND_ERR_ERRVAL1_OFFSET 0xd8
|
||||
#define NAND_ERR_ERRVAL2_OFFSET 0xdc
|
||||
|
||||
/* NOTE: boards don't need to use these address bits
|
||||
* for ALE/CLE unless they support booting from NAND.
|
||||
* They're used unless platform data overrides them.
|
||||
*/
|
||||
#define MASK_ALE 0x08
|
||||
#define MASK_CLE 0x10
|
||||
|
||||
struct davinci_nand_pdata { /* platform_data */
|
||||
uint32_t mask_ale;
|
||||
uint32_t mask_cle;
|
||||
|
||||
/* for packages using two chipselects */
|
||||
uint32_t mask_chipsel;
|
||||
|
||||
/* board's default static partition info */
|
||||
struct mtd_partition *parts;
|
||||
unsigned nr_parts;
|
||||
|
||||
/* none == NAND_ECC_NONE (strongly *not* advised!!)
|
||||
* soft == NAND_ECC_SOFT
|
||||
* 1-bit == NAND_ECC_HW
|
||||
* 4-bit == NAND_ECC_HW_SYNDROME (not on all chips)
|
||||
*/
|
||||
nand_ecc_modes_t ecc_mode;
|
||||
|
||||
/* e.g. NAND_BUSWIDTH_16 or NAND_USE_FLASH_BBT */
|
||||
unsigned options;
|
||||
};
|
||||
|
||||
#endif /* __ARCH_ARM_DAVINCI_NAND_H */
|
|
@ -49,6 +49,9 @@ struct pxa3xx_nand_platform_data {
|
|||
*/
|
||||
int enable_arbiter;
|
||||
|
||||
/* allow platform code to keep OBM/bootloader defined NFC config */
|
||||
int keep_config;
|
||||
|
||||
const struct mtd_partition *parts;
|
||||
unsigned int nr_parts;
|
||||
|
||||
|
|
|
@ -337,7 +337,7 @@ int _access_ok(unsigned long addr, unsigned long size)
|
|||
if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
|
||||
return 1;
|
||||
|
||||
#ifdef CONFIG_ROMFS_MTD_FS
|
||||
#ifdef CONFIG_ROMFS_ON_MTD
|
||||
/* For XIP, allow user space to use pointers within the ROMFS. */
|
||||
if (addr >= memory_mtd_start && (addr + size) <= memory_mtd_end)
|
||||
return 1;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/highmem.h>
|
||||
#include <asm/spr-regs.h>
|
||||
|
||||
.section .text.tlbmiss
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* (C) Copyright TOSHIBA CORPORATION 2007
|
||||
*/
|
||||
#ifndef __ASM_TXX9_NDFMC_H
|
||||
#define __ASM_TXX9_NDFMC_H
|
||||
|
||||
#define NDFMC_PLAT_FLAG_USE_BSPRT 0x01
|
||||
#define NDFMC_PLAT_FLAG_NO_RSTR 0x02
|
||||
#define NDFMC_PLAT_FLAG_HOLDADD 0x04
|
||||
#define NDFMC_PLAT_FLAG_DUMMYWRITE 0x08
|
||||
|
||||
struct txx9ndfmc_platform_data {
|
||||
unsigned int shift;
|
||||
unsigned int gbus_clock;
|
||||
unsigned int hold; /* hold time in nanosecond */
|
||||
unsigned int spw; /* strobe pulse width in nanosecond */
|
||||
unsigned int flags;
|
||||
unsigned char ch_mask; /* available channel bitmask */
|
||||
unsigned char wp_mask; /* write-protect bitmask */
|
||||
unsigned char wide_mask; /* 16bit-nand bitmask */
|
||||
};
|
||||
|
||||
void txx9_ndfmc_init(unsigned long baseaddr,
|
||||
const struct txx9ndfmc_platform_data *plat_data);
|
||||
|
||||
#endif /* __ASM_TXX9_NDFMC_H */
|
|
@ -130,4 +130,13 @@
|
|||
void rbtx4939_prom_init(void);
|
||||
void rbtx4939_irq_setup(void);
|
||||
|
||||
struct mtd_partition;
|
||||
struct map_info;
|
||||
struct rbtx4939_flash_data {
|
||||
unsigned int width;
|
||||
unsigned int nr_parts;
|
||||
struct mtd_partition *parts;
|
||||
void (*map_init)(struct map_info *map);
|
||||
};
|
||||
|
||||
#endif /* __ASM_TXX9_RBTX4939_H */
|
||||
|
|
|
@ -291,6 +291,7 @@ int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot);
|
|||
void tx4938_setup_pcierr_irq(void);
|
||||
void tx4938_irq_init(void);
|
||||
void tx4938_mtd_init(int ch);
|
||||
void tx4938_ndfmc_init(unsigned int hold, unsigned int spw);
|
||||
|
||||
struct tx4938ide_platform_info {
|
||||
/*
|
||||
|
|
|
@ -542,5 +542,7 @@ int tx4939_irq(void);
|
|||
void tx4939_mtd_init(int ch);
|
||||
void tx4939_ata_init(void);
|
||||
void tx4939_rtc_init(void);
|
||||
void tx4939_ndfmc_init(unsigned int hold, unsigned int spw,
|
||||
unsigned char ch_mask, unsigned char wide_mask);
|
||||
|
||||
#endif /* __ASM_TXX9_TX4939_H */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <asm/txx9/generic.h>
|
||||
#include <asm/txx9/pci.h>
|
||||
#include <asm/txx9tmr.h>
|
||||
#include <asm/txx9/ndfmc.h>
|
||||
#ifdef CONFIG_CPU_TX49XX
|
||||
#include <asm/txx9/tx4938.h>
|
||||
#endif
|
||||
|
@ -691,6 +692,26 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
|
|||
#endif
|
||||
}
|
||||
|
||||
void __init txx9_ndfmc_init(unsigned long baseaddr,
|
||||
const struct txx9ndfmc_platform_data *pdata)
|
||||
{
|
||||
#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \
|
||||
defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE)
|
||||
struct resource res = {
|
||||
.start = baseaddr,
|
||||
.end = baseaddr + 0x1000 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
struct platform_device *pdev = platform_device_alloc("txx9ndfmc", -1);
|
||||
|
||||
if (!pdev ||
|
||||
platform_device_add_resources(pdev, &res, 1) ||
|
||||
platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
|
||||
platform_device_add(pdev))
|
||||
platform_device_put(pdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
|
||||
static DEFINE_SPINLOCK(txx9_iocled_lock);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <asm/txx9tmr.h>
|
||||
#include <asm/txx9pio.h>
|
||||
#include <asm/txx9/generic.h>
|
||||
#include <asm/txx9/ndfmc.h>
|
||||
#include <asm/txx9/tx4938.h>
|
||||
|
||||
static void __init tx4938_wdr_init(void)
|
||||
|
@ -382,6 +383,26 @@ void __init tx4938_ata_init(unsigned int irq, unsigned int shift, int tune)
|
|||
platform_device_put(pdev);
|
||||
}
|
||||
|
||||
void __init tx4938_ndfmc_init(unsigned int hold, unsigned int spw)
|
||||
{
|
||||
struct txx9ndfmc_platform_data plat_data = {
|
||||
.shift = 1,
|
||||
.gbus_clock = txx9_gbus_clock,
|
||||
.hold = hold,
|
||||
.spw = spw,
|
||||
.ch_mask = 1,
|
||||
};
|
||||
unsigned long baseaddr = TX4938_NDFMC_REG & 0xfffffffffULL;
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
baseaddr += 4;
|
||||
#endif
|
||||
if ((__raw_readq(&tx4938_ccfgptr->pcfg) &
|
||||
(TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL)) ==
|
||||
TX4938_PCFG_NDF_SEL)
|
||||
txx9_ndfmc_init(baseaddr, &plat_data);
|
||||
}
|
||||
|
||||
static void __init tx4938_stop_unused_modules(void)
|
||||
{
|
||||
__u64 pcfg, rst = 0, ckd = 0;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <asm/txx9irq.h>
|
||||
#include <asm/txx9tmr.h>
|
||||
#include <asm/txx9/generic.h>
|
||||
#include <asm/txx9/ndfmc.h>
|
||||
#include <asm/txx9/tx4939.h>
|
||||
|
||||
static void __init tx4939_wdr_init(void)
|
||||
|
@ -457,6 +458,22 @@ void __init tx4939_rtc_init(void)
|
|||
platform_device_register(&rtc_dev);
|
||||
}
|
||||
|
||||
void __init tx4939_ndfmc_init(unsigned int hold, unsigned int spw,
|
||||
unsigned char ch_mask, unsigned char wide_mask)
|
||||
{
|
||||
struct txx9ndfmc_platform_data plat_data = {
|
||||
.shift = 1,
|
||||
.gbus_clock = txx9_gbus_clock,
|
||||
.hold = hold,
|
||||
.spw = spw,
|
||||
.flags = NDFMC_PLAT_FLAG_NO_RSTR | NDFMC_PLAT_FLAG_HOLDADD |
|
||||
NDFMC_PLAT_FLAG_DUMMYWRITE,
|
||||
.ch_mask = ch_mask,
|
||||
.wide_mask = wide_mask,
|
||||
};
|
||||
txx9_ndfmc_init(TX4939_NDFMC_REG & 0xfffffffffULL, &plat_data);
|
||||
}
|
||||
|
||||
static void __init tx4939_stop_unused_modules(void)
|
||||
{
|
||||
__u64 pcfg, rst = 0, ckd = 0;
|
||||
|
|
|
@ -352,6 +352,8 @@ static void __init rbtx4938_device_init(void)
|
|||
rbtx4938_ne_init();
|
||||
tx4938_wdt_init();
|
||||
rbtx4938_mtd_init();
|
||||
/* TC58DVM82A1FT: tDH=10ns, tWP=tRP=tREADID=35ns */
|
||||
tx4938_ndfmc_init(10, 35);
|
||||
tx4938_ata_init(RBTX4938_IRQ_IOC_ATA, 0, 1);
|
||||
txx9_iocled_init(RBTX4938_LED_ADDR - IO_BASE, -1, 8, 1, "green", NULL);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/txx9/generic.h>
|
||||
#include <asm/txx9/pci.h>
|
||||
|
@ -282,6 +285,159 @@ static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
|
|||
__rbtx4939_7segled_putc(pos, val);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MTD_RBTX4939) || defined(CONFIG_MTD_RBTX4939_MODULE)
|
||||
/* special mapping for boot rom */
|
||||
static unsigned long rbtx4939_flash_fixup_ofs(unsigned long ofs)
|
||||
{
|
||||
u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
|
||||
unsigned char shift;
|
||||
|
||||
if (bdipsw & 8) {
|
||||
/* BOOT Mode: USER ROM1 / USER ROM2 */
|
||||
shift = bdipsw & 3;
|
||||
/* rotate A[23:22] */
|
||||
return (ofs & ~0xc00000) | ((((ofs >> 22) + shift) & 3) << 22);
|
||||
}
|
||||
#ifdef __BIG_ENDIAN
|
||||
if (bdipsw == 0)
|
||||
/* BOOT Mode: Monitor ROM */
|
||||
ofs ^= 0x400000; /* swap A[22] */
|
||||
#endif
|
||||
return ofs;
|
||||
}
|
||||
|
||||
static map_word rbtx4939_flash_read16(struct map_info *map, unsigned long ofs)
|
||||
{
|
||||
map_word r;
|
||||
|
||||
ofs = rbtx4939_flash_fixup_ofs(ofs);
|
||||
r.x[0] = __raw_readw(map->virt + ofs);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void rbtx4939_flash_write16(struct map_info *map, const map_word datum,
|
||||
unsigned long ofs)
|
||||
{
|
||||
ofs = rbtx4939_flash_fixup_ofs(ofs);
|
||||
__raw_writew(datum.x[0], map->virt + ofs);
|
||||
mb(); /* see inline_map_write() in mtd/map.h */
|
||||
}
|
||||
|
||||
static void rbtx4939_flash_copy_from(struct map_info *map, void *to,
|
||||
unsigned long from, ssize_t len)
|
||||
{
|
||||
u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
|
||||
unsigned char shift;
|
||||
ssize_t curlen;
|
||||
|
||||
from += (unsigned long)map->virt;
|
||||
if (bdipsw & 8) {
|
||||
/* BOOT Mode: USER ROM1 / USER ROM2 */
|
||||
shift = bdipsw & 3;
|
||||
while (len) {
|
||||
curlen = min_t(unsigned long, len,
|
||||
0x400000 - (from & (0x400000 - 1)));
|
||||
memcpy(to,
|
||||
(void *)((from & ~0xc00000) |
|
||||
((((from >> 22) + shift) & 3) << 22)),
|
||||
curlen);
|
||||
len -= curlen;
|
||||
from += curlen;
|
||||
to += curlen;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef __BIG_ENDIAN
|
||||
if (bdipsw == 0) {
|
||||
/* BOOT Mode: Monitor ROM */
|
||||
while (len) {
|
||||
curlen = min_t(unsigned long, len,
|
||||
0x400000 - (from & (0x400000 - 1)));
|
||||
memcpy(to, (void *)(from ^ 0x400000), curlen);
|
||||
len -= curlen;
|
||||
from += curlen;
|
||||
to += curlen;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
memcpy(to, (void *)from, len);
|
||||
}
|
||||
|
||||
static void rbtx4939_flash_map_init(struct map_info *map)
|
||||
{
|
||||
map->read = rbtx4939_flash_read16;
|
||||
map->write = rbtx4939_flash_write16;
|
||||
map->copy_from = rbtx4939_flash_copy_from;
|
||||
}
|
||||
|
||||
static void __init rbtx4939_mtd_init(void)
|
||||
{
|
||||
static struct {
|
||||
struct platform_device dev;
|
||||
struct resource res;
|
||||
struct rbtx4939_flash_data data;
|
||||
} pdevs[4];
|
||||
int i;
|
||||
static char names[4][8];
|
||||
static struct mtd_partition parts[4];
|
||||
struct rbtx4939_flash_data *boot_pdata = &pdevs[0].data;
|
||||
u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
|
||||
|
||||
if (bdipsw & 8) {
|
||||
/* BOOT Mode: USER ROM1 / USER ROM2 */
|
||||
boot_pdata->nr_parts = 4;
|
||||
for (i = 0; i < boot_pdata->nr_parts; i++) {
|
||||
sprintf(names[i], "img%d", 4 - i);
|
||||
parts[i].name = names[i];
|
||||
parts[i].size = 0x400000;
|
||||
parts[i].offset = MTDPART_OFS_NXTBLK;
|
||||
}
|
||||
} else if (bdipsw == 0) {
|
||||
/* BOOT Mode: Monitor ROM */
|
||||
boot_pdata->nr_parts = 2;
|
||||
strcpy(names[0], "big");
|
||||
strcpy(names[1], "little");
|
||||
for (i = 0; i < boot_pdata->nr_parts; i++) {
|
||||
parts[i].name = names[i];
|
||||
parts[i].size = 0x400000;
|
||||
parts[i].offset = MTDPART_OFS_NXTBLK;
|
||||
}
|
||||
} else {
|
||||
/* BOOT Mode: ROM Emulator */
|
||||
boot_pdata->nr_parts = 2;
|
||||
parts[0].name = "boot";
|
||||
parts[0].offset = 0xc00000;
|
||||
parts[0].size = 0x400000;
|
||||
parts[1].name = "user";
|
||||
parts[1].offset = 0;
|
||||
parts[1].size = 0xc00000;
|
||||
}
|
||||
boot_pdata->parts = parts;
|
||||
boot_pdata->map_init = rbtx4939_flash_map_init;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pdevs); i++) {
|
||||
struct resource *r = &pdevs[i].res;
|
||||
struct platform_device *dev = &pdevs[i].dev;
|
||||
|
||||
r->start = 0x1f000000 - i * 0x1000000;
|
||||
r->end = r->start + 0x1000000 - 1;
|
||||
r->flags = IORESOURCE_MEM;
|
||||
pdevs[i].data.width = 2;
|
||||
dev->num_resources = 1;
|
||||
dev->resource = r;
|
||||
dev->id = i;
|
||||
dev->name = "rbtx4939-flash";
|
||||
dev->dev.platform_data = &pdevs[i].data;
|
||||
platform_device_register(dev);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void __init rbtx4939_mtd_init(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init rbtx4939_arch_init(void)
|
||||
{
|
||||
rbtx4939_pci_setup();
|
||||
|
@ -333,6 +489,11 @@ static void __init rbtx4939_device_init(void)
|
|||
platform_device_add_data(pdev, &smc_pdata, sizeof(smc_pdata)) ||
|
||||
platform_device_add(pdev))
|
||||
platform_device_put(pdev);
|
||||
rbtx4939_mtd_init();
|
||||
/* TC58DVM82A1FT: tDH=10ns, tWP=tRP=tREADID=35ns */
|
||||
tx4939_ndfmc_init(10, 35,
|
||||
(1 << 1) | (1 << 2),
|
||||
(1 << 2)); /* ch1:8bit, ch2:16bit */
|
||||
rbtx4939_led_setup();
|
||||
tx4939_wdt_init();
|
||||
tx4939_ata_init();
|
||||
|
|
|
@ -397,10 +397,13 @@
|
|||
upm@3,0 {
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,upm-nand";
|
||||
compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
|
||||
reg = <3 0x0 0x800>;
|
||||
fsl,upm-addr-offset = <0x10>;
|
||||
fsl,upm-cmd-offset = <0x08>;
|
||||
/* Micron MT29F8G08FAB multi-chip device */
|
||||
fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
|
||||
fsl,upm-wait-flags = <0x5>;
|
||||
chip-delay = <25>; // in micro-seconds
|
||||
|
||||
nand@0 {
|
||||
|
@ -409,7 +412,7 @@
|
|||
|
||||
partition@0 {
|
||||
label = "fs";
|
||||
reg = <0x00000000 0x01000000>;
|
||||
reg = <0x00000000 0x10000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -397,10 +397,13 @@
|
|||
upm@3,0 {
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,upm-nand";
|
||||
compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
|
||||
reg = <3 0x0 0x800>;
|
||||
fsl,upm-addr-offset = <0x10>;
|
||||
fsl,upm-cmd-offset = <0x08>;
|
||||
/* Micron MT29F8G08FAB multi-chip device */
|
||||
fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
|
||||
fsl,upm-wait-flags = <0x5>;
|
||||
chip-delay = <25>; // in micro-seconds
|
||||
|
||||
nand@0 {
|
||||
|
@ -409,7 +412,7 @@
|
|||
|
||||
partition@0 {
|
||||
label = "fs";
|
||||
reg = <0x00000000 0x01000000>;
|
||||
reg = <0x00000000 0x10000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -150,7 +150,7 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
|
|||
|
||||
spin_lock_irqsave(&fsl_lbc_lock, flags);
|
||||
|
||||
out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
|
||||
out_be32(&fsl_lbc_regs->mar, mar);
|
||||
|
||||
switch (upm->width) {
|
||||
case 8:
|
||||
|
|
|
@ -253,6 +253,7 @@ config SMP
|
|||
config X86_X2APIC
|
||||
bool "Support x2apic"
|
||||
depends on X86_LOCAL_APIC && X86_64
|
||||
select INTR_REMAP
|
||||
---help---
|
||||
This enables x2apic support on CPUs that have this feature.
|
||||
|
||||
|
@ -1882,7 +1883,6 @@ config DMAR_FLOPPY_WA
|
|||
config INTR_REMAP
|
||||
bool "Support for Interrupt Remapping (EXPERIMENTAL)"
|
||||
depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
|
||||
select X86_X2APIC
|
||||
---help---
|
||||
Supports Interrupt remapping for IO-APIC and MSI devices.
|
||||
To use x2apic mode in the CPU's which support x2APIC enhancements or
|
||||
|
|
|
@ -107,6 +107,9 @@ extern u32 native_safe_apic_wait_icr_idle(void);
|
|||
extern void native_apic_icr_write(u32 low, u32 id);
|
||||
extern u64 native_apic_icr_read(void);
|
||||
|
||||
#define EIM_8BIT_APIC_ID 0
|
||||
#define EIM_32BIT_APIC_ID 1
|
||||
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
/*
|
||||
* Make previous memory operations globally visible before
|
||||
|
|
|
@ -162,10 +162,13 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
|
|||
extern void ioapic_init_mappings(void);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
extern int save_IO_APIC_setup(void);
|
||||
extern void mask_IO_APIC_setup(void);
|
||||
extern void restore_IO_APIC_setup(void);
|
||||
extern void reinit_intr_remapped_IO_APIC(int);
|
||||
extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
|
||||
extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
|
||||
extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
|
||||
extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
|
||||
extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
|
||||
extern void reinit_intr_remapped_IO_APIC(int intr_remapping,
|
||||
struct IO_APIC_route_entry **ioapic_entries);
|
||||
#endif
|
||||
|
||||
extern void probe_nr_irqs_gsi(void);
|
||||
|
|
|
@ -1308,6 +1308,7 @@ void __init enable_IR_x2apic(void)
|
|||
#ifdef CONFIG_INTR_REMAP
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
||||
|
||||
if (!cpu_has_x2apic)
|
||||
return;
|
||||
|
@ -1338,17 +1339,23 @@ void __init enable_IR_x2apic(void)
|
|||
return;
|
||||
}
|
||||
|
||||
ret = save_IO_APIC_setup();
|
||||
ioapic_entries = alloc_ioapic_entries();
|
||||
if (!ioapic_entries) {
|
||||
pr_info("Allocate ioapic_entries failed: %d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = save_IO_APIC_setup(ioapic_entries);
|
||||
if (ret) {
|
||||
pr_info("Saving IO-APIC state failed: %d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
mask_IO_APIC_setup();
|
||||
mask_IO_APIC_setup(ioapic_entries);
|
||||
mask_8259A();
|
||||
|
||||
ret = enable_intr_remapping(1);
|
||||
ret = enable_intr_remapping(EIM_32BIT_APIC_ID);
|
||||
|
||||
if (ret && x2apic_preenabled) {
|
||||
local_irq_restore(flags);
|
||||
|
@ -1368,9 +1375,9 @@ end_restore:
|
|||
/*
|
||||
* IR enabling failed
|
||||
*/
|
||||
restore_IO_APIC_setup();
|
||||
restore_IO_APIC_setup(ioapic_entries);
|
||||
else
|
||||
reinit_intr_remapped_IO_APIC(x2apic_preenabled);
|
||||
reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);
|
||||
|
||||
unmask_8259A();
|
||||
local_irq_restore(flags);
|
||||
|
@ -1383,6 +1390,8 @@ end:
|
|||
pr_info("Enabled Interrupt-remapping\n");
|
||||
} else
|
||||
pr_err("Failed to enable Interrupt-remapping and x2apic\n");
|
||||
if (ioapic_entries)
|
||||
free_ioapic_entries(ioapic_entries);
|
||||
#else
|
||||
if (!cpu_has_x2apic)
|
||||
return;
|
||||
|
@ -1958,6 +1967,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
|
|||
|
||||
local_irq_save(flags);
|
||||
disable_local_APIC();
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
if (intr_remapping_enabled)
|
||||
disable_intr_remapping();
|
||||
#endif
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1968,15 +1981,41 @@ static int lapic_resume(struct sys_device *dev)
|
|||
unsigned long flags;
|
||||
int maxlvt;
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
int ret;
|
||||
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
||||
|
||||
if (!apic_pm_state.active)
|
||||
return 0;
|
||||
|
||||
maxlvt = lapic_get_maxlvt();
|
||||
local_irq_save(flags);
|
||||
if (x2apic) {
|
||||
ioapic_entries = alloc_ioapic_entries();
|
||||
if (!ioapic_entries) {
|
||||
WARN(1, "Alloc ioapic_entries in lapic resume failed.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = save_IO_APIC_setup(ioapic_entries);
|
||||
if (ret) {
|
||||
WARN(1, "Saving IO-APIC state failed: %d\n", ret);
|
||||
free_ioapic_entries(ioapic_entries);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mask_IO_APIC_setup(ioapic_entries);
|
||||
mask_8259A();
|
||||
enable_x2apic();
|
||||
}
|
||||
#else
|
||||
if (!apic_pm_state.active)
|
||||
return 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (x2apic)
|
||||
enable_x2apic();
|
||||
#endif
|
||||
|
||||
else {
|
||||
/*
|
||||
* Make sure the APICBASE points to the right address
|
||||
|
@ -1990,6 +2029,7 @@ static int lapic_resume(struct sys_device *dev)
|
|||
wrmsr(MSR_IA32_APICBASE, l, h);
|
||||
}
|
||||
|
||||
maxlvt = lapic_get_maxlvt();
|
||||
apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
|
||||
apic_write(APIC_ID, apic_pm_state.apic_id);
|
||||
apic_write(APIC_DFR, apic_pm_state.apic_dfr);
|
||||
|
@ -2013,8 +2053,20 @@ static int lapic_resume(struct sys_device *dev)
|
|||
apic_write(APIC_ESR, 0);
|
||||
apic_read(APIC_ESR);
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
if (intr_remapping_enabled)
|
||||
reenable_intr_remapping(EIM_32BIT_APIC_ID);
|
||||
|
||||
if (x2apic) {
|
||||
unmask_8259A();
|
||||
restore_IO_APIC_setup(ioapic_entries);
|
||||
free_ioapic_entries(ioapic_entries);
|
||||
}
|
||||
#endif
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2052,7 +2104,9 @@ static int __init init_lapic_sysfs(void)
|
|||
error = sysdev_register(&device_lapic);
|
||||
return error;
|
||||
}
|
||||
device_initcall(init_lapic_sysfs);
|
||||
|
||||
/* local apic needs to resume before other devices access its registers. */
|
||||
core_initcall(init_lapic_sysfs);
|
||||
|
||||
#else /* CONFIG_PM */
|
||||
|
||||
|
|
|
@ -851,63 +851,74 @@ __setup("pirq=", ioapic_pirq_setup);
|
|||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
/* I/O APIC RTE contents at the OS boot up */
|
||||
static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
|
||||
struct IO_APIC_route_entry **alloc_ioapic_entries(void)
|
||||
{
|
||||
int apic;
|
||||
struct IO_APIC_route_entry **ioapic_entries;
|
||||
|
||||
ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
|
||||
GFP_ATOMIC);
|
||||
if (!ioapic_entries)
|
||||
return 0;
|
||||
|
||||
for (apic = 0; apic < nr_ioapics; apic++) {
|
||||
ioapic_entries[apic] =
|
||||
kzalloc(sizeof(struct IO_APIC_route_entry) *
|
||||
nr_ioapic_registers[apic], GFP_ATOMIC);
|
||||
if (!ioapic_entries[apic])
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
return ioapic_entries;
|
||||
|
||||
nomem:
|
||||
while (--apic >= 0)
|
||||
kfree(ioapic_entries[apic]);
|
||||
kfree(ioapic_entries);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Saves all the IO-APIC RTE's
|
||||
*/
|
||||
int save_IO_APIC_setup(void)
|
||||
int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
|
||||
{
|
||||
union IO_APIC_reg_01 reg_01;
|
||||
unsigned long flags;
|
||||
int apic, pin;
|
||||
|
||||
/*
|
||||
* The number of IO-APIC IRQ registers (== #pins):
|
||||
*/
|
||||
for (apic = 0; apic < nr_ioapics; apic++) {
|
||||
spin_lock_irqsave(&ioapic_lock, flags);
|
||||
reg_01.raw = io_apic_read(apic, 1);
|
||||
spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
nr_ioapic_registers[apic] = reg_01.bits.entries+1;
|
||||
}
|
||||
if (!ioapic_entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (apic = 0; apic < nr_ioapics; apic++) {
|
||||
early_ioapic_entries[apic] =
|
||||
kzalloc(sizeof(struct IO_APIC_route_entry) *
|
||||
nr_ioapic_registers[apic], GFP_KERNEL);
|
||||
if (!early_ioapic_entries[apic])
|
||||
goto nomem;
|
||||
}
|
||||
if (!ioapic_entries[apic])
|
||||
return -ENOMEM;
|
||||
|
||||
for (apic = 0; apic < nr_ioapics; apic++)
|
||||
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
|
||||
early_ioapic_entries[apic][pin] =
|
||||
ioapic_entries[apic][pin] =
|
||||
ioapic_read_entry(apic, pin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
nomem:
|
||||
while (apic >= 0)
|
||||
kfree(early_ioapic_entries[apic--]);
|
||||
memset(early_ioapic_entries, 0,
|
||||
ARRAY_SIZE(early_ioapic_entries));
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void mask_IO_APIC_setup(void)
|
||||
/*
|
||||
* Mask all IO APIC entries.
|
||||
*/
|
||||
void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
|
||||
{
|
||||
int apic, pin;
|
||||
|
||||
if (!ioapic_entries)
|
||||
return;
|
||||
|
||||
for (apic = 0; apic < nr_ioapics; apic++) {
|
||||
if (!early_ioapic_entries[apic])
|
||||
if (!ioapic_entries[apic])
|
||||
break;
|
||||
|
||||
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
|
||||
struct IO_APIC_route_entry entry;
|
||||
|
||||
entry = early_ioapic_entries[apic][pin];
|
||||
entry = ioapic_entries[apic][pin];
|
||||
if (!entry.mask) {
|
||||
entry.mask = 1;
|
||||
ioapic_write_entry(apic, pin, entry);
|
||||
|
@ -916,22 +927,30 @@ void mask_IO_APIC_setup(void)
|
|||
}
|
||||
}
|
||||
|
||||
void restore_IO_APIC_setup(void)
|
||||
/*
|
||||
* Restore IO APIC entries which was saved in ioapic_entries.
|
||||
*/
|
||||
int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
|
||||
{
|
||||
int apic, pin;
|
||||
|
||||
if (!ioapic_entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (apic = 0; apic < nr_ioapics; apic++) {
|
||||
if (!early_ioapic_entries[apic])
|
||||
break;
|
||||
if (!ioapic_entries[apic])
|
||||
return -ENOMEM;
|
||||
|
||||
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
|
||||
ioapic_write_entry(apic, pin,
|
||||
early_ioapic_entries[apic][pin]);
|
||||
kfree(early_ioapic_entries[apic]);
|
||||
early_ioapic_entries[apic] = NULL;
|
||||
ioapic_entries[apic][pin]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reinit_intr_remapped_IO_APIC(int intr_remapping)
|
||||
void reinit_intr_remapped_IO_APIC(int intr_remapping,
|
||||
struct IO_APIC_route_entry **ioapic_entries)
|
||||
|
||||
{
|
||||
/*
|
||||
* for now plain restore of previous settings.
|
||||
|
@ -940,7 +959,17 @@ void reinit_intr_remapped_IO_APIC(int intr_remapping)
|
|||
* table entries. for now, do a plain restore, and wait for
|
||||
* the setup_IO_APIC_irqs() to do proper initialization.
|
||||
*/
|
||||
restore_IO_APIC_setup();
|
||||
restore_IO_APIC_setup(ioapic_entries);
|
||||
}
|
||||
|
||||
void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
|
||||
{
|
||||
int apic;
|
||||
|
||||
for (apic = 0; apic < nr_ioapics; apic++)
|
||||
kfree(ioapic_entries[apic]);
|
||||
|
||||
kfree(ioapic_entries);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2495,7 +2524,7 @@ static void irq_complete_move(struct irq_desc **descp)
|
|||
static inline void irq_complete_move(struct irq_desc **descp) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
|
||||
{
|
||||
int apic, pin;
|
||||
|
@ -2540,7 +2569,6 @@ static void ack_x2apic_edge(unsigned int irq)
|
|||
{
|
||||
ack_x2APIC_irq();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ack_apic_edge(unsigned int irq)
|
||||
|
@ -2651,6 +2679,26 @@ static void ack_apic_level(unsigned int irq)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
static void ir_ack_apic_edge(unsigned int irq)
|
||||
{
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
if (x2apic_enabled())
|
||||
return ack_x2apic_edge(irq);
|
||||
#endif
|
||||
return ack_apic_edge(irq);
|
||||
}
|
||||
|
||||
static void ir_ack_apic_level(unsigned int irq)
|
||||
{
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
if (x2apic_enabled())
|
||||
return ack_x2apic_level(irq);
|
||||
#endif
|
||||
return ack_apic_level(irq);
|
||||
}
|
||||
#endif /* CONFIG_INTR_REMAP */
|
||||
|
||||
static struct irq_chip ioapic_chip __read_mostly = {
|
||||
.name = "IO-APIC",
|
||||
.startup = startup_ioapic_irq,
|
||||
|
@ -2670,8 +2718,8 @@ static struct irq_chip ir_ioapic_chip __read_mostly = {
|
|||
.mask = mask_IO_APIC_irq,
|
||||
.unmask = unmask_IO_APIC_irq,
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
.ack = ack_x2apic_edge,
|
||||
.eoi = ack_x2apic_level,
|
||||
.ack = ir_ack_apic_edge,
|
||||
.eoi = ir_ack_apic_level,
|
||||
#ifdef CONFIG_SMP
|
||||
.set_affinity = set_ir_ioapic_affinity_irq,
|
||||
#endif
|
||||
|
@ -3397,7 +3445,7 @@ static struct irq_chip msi_ir_chip = {
|
|||
.unmask = unmask_msi_irq,
|
||||
.mask = mask_msi_irq,
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
.ack = ack_x2apic_edge,
|
||||
.ack = ir_ack_apic_edge,
|
||||
#ifdef CONFIG_SMP
|
||||
.set_affinity = ir_set_msi_irq_affinity,
|
||||
#endif
|
||||
|
|
|
@ -484,11 +484,11 @@ static int blk_init_free_list(struct request_queue *q)
|
|||
{
|
||||
struct request_list *rl = &q->rq;
|
||||
|
||||
rl->count[READ] = rl->count[WRITE] = 0;
|
||||
rl->starved[READ] = rl->starved[WRITE] = 0;
|
||||
rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0;
|
||||
rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0;
|
||||
rl->elvpriv = 0;
|
||||
init_waitqueue_head(&rl->wait[READ]);
|
||||
init_waitqueue_head(&rl->wait[WRITE]);
|
||||
init_waitqueue_head(&rl->wait[BLK_RW_SYNC]);
|
||||
init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]);
|
||||
|
||||
rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
|
||||
mempool_free_slab, request_cachep, q->node);
|
||||
|
@ -699,18 +699,18 @@ static void ioc_set_batching(struct request_queue *q, struct io_context *ioc)
|
|||
ioc->last_waited = jiffies;
|
||||
}
|
||||
|
||||
static void __freed_request(struct request_queue *q, int rw)
|
||||
static void __freed_request(struct request_queue *q, int sync)
|
||||
{
|
||||
struct request_list *rl = &q->rq;
|
||||
|
||||
if (rl->count[rw] < queue_congestion_off_threshold(q))
|
||||
blk_clear_queue_congested(q, rw);
|
||||
if (rl->count[sync] < queue_congestion_off_threshold(q))
|
||||
blk_clear_queue_congested(q, sync);
|
||||
|
||||
if (rl->count[rw] + 1 <= q->nr_requests) {
|
||||
if (waitqueue_active(&rl->wait[rw]))
|
||||
wake_up(&rl->wait[rw]);
|
||||
if (rl->count[sync] + 1 <= q->nr_requests) {
|
||||
if (waitqueue_active(&rl->wait[sync]))
|
||||
wake_up(&rl->wait[sync]);
|
||||
|
||||
blk_clear_queue_full(q, rw);
|
||||
blk_clear_queue_full(q, sync);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,18 +718,18 @@ static void __freed_request(struct request_queue *q, int rw)
|
|||
* A request has just been released. Account for it, update the full and
|
||||
* congestion status, wake up any waiters. Called under q->queue_lock.
|
||||
*/
|
||||
static void freed_request(struct request_queue *q, int rw, int priv)
|
||||
static void freed_request(struct request_queue *q, int sync, int priv)
|
||||
{
|
||||
struct request_list *rl = &q->rq;
|
||||
|
||||
rl->count[rw]--;
|
||||
rl->count[sync]--;
|
||||
if (priv)
|
||||
rl->elvpriv--;
|
||||
|
||||
__freed_request(q, rw);
|
||||
__freed_request(q, sync);
|
||||
|
||||
if (unlikely(rl->starved[rw ^ 1]))
|
||||
__freed_request(q, rw ^ 1);
|
||||
if (unlikely(rl->starved[sync ^ 1]))
|
||||
__freed_request(q, sync ^ 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -743,15 +743,15 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
|||
struct request *rq = NULL;
|
||||
struct request_list *rl = &q->rq;
|
||||
struct io_context *ioc = NULL;
|
||||
const int rw = rw_flags & 0x01;
|
||||
const bool is_sync = rw_is_sync(rw_flags) != 0;
|
||||
int may_queue, priv;
|
||||
|
||||
may_queue = elv_may_queue(q, rw_flags);
|
||||
if (may_queue == ELV_MQUEUE_NO)
|
||||
goto rq_starved;
|
||||
|
||||
if (rl->count[rw]+1 >= queue_congestion_on_threshold(q)) {
|
||||
if (rl->count[rw]+1 >= q->nr_requests) {
|
||||
if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) {
|
||||
if (rl->count[is_sync]+1 >= q->nr_requests) {
|
||||
ioc = current_io_context(GFP_ATOMIC, q->node);
|
||||
/*
|
||||
* The queue will fill after this allocation, so set
|
||||
|
@ -759,9 +759,9 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
|||
* This process will be allowed to complete a batch of
|
||||
* requests, others will be blocked.
|
||||
*/
|
||||
if (!blk_queue_full(q, rw)) {
|
||||
if (!blk_queue_full(q, is_sync)) {
|
||||
ioc_set_batching(q, ioc);
|
||||
blk_set_queue_full(q, rw);
|
||||
blk_set_queue_full(q, is_sync);
|
||||
} else {
|
||||
if (may_queue != ELV_MQUEUE_MUST
|
||||
&& !ioc_batching(q, ioc)) {
|
||||
|
@ -774,7 +774,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
|||
}
|
||||
}
|
||||
}
|
||||
blk_set_queue_congested(q, rw);
|
||||
blk_set_queue_congested(q, is_sync);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -782,11 +782,11 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
|||
* limit of requests, otherwise we could have thousands of requests
|
||||
* allocated with any setting of ->nr_requests
|
||||
*/
|
||||
if (rl->count[rw] >= (3 * q->nr_requests / 2))
|
||||
if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
|
||||
goto out;
|
||||
|
||||
rl->count[rw]++;
|
||||
rl->starved[rw] = 0;
|
||||
rl->count[is_sync]++;
|
||||
rl->starved[is_sync] = 0;
|
||||
|
||||
priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
|
||||
if (priv)
|
||||
|
@ -804,7 +804,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
|||
* wait queue, but this is pretty rare.
|
||||
*/
|
||||
spin_lock_irq(q->queue_lock);
|
||||
freed_request(q, rw, priv);
|
||||
freed_request(q, is_sync, priv);
|
||||
|
||||
/*
|
||||
* in the very unlikely event that allocation failed and no
|
||||
|
@ -814,8 +814,8 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
|||
* rq mempool into READ and WRITE
|
||||
*/
|
||||
rq_starved:
|
||||
if (unlikely(rl->count[rw] == 0))
|
||||
rl->starved[rw] = 1;
|
||||
if (unlikely(rl->count[is_sync] == 0))
|
||||
rl->starved[is_sync] = 1;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
@ -829,7 +829,7 @@ rq_starved:
|
|||
if (ioc_batching(q, ioc))
|
||||
ioc->nr_batch_requests--;
|
||||
|
||||
trace_block_getrq(q, bio, rw);
|
||||
trace_block_getrq(q, bio, rw_flags & 1);
|
||||
out:
|
||||
return rq;
|
||||
}
|
||||
|
@ -843,7 +843,7 @@ out:
|
|||
static struct request *get_request_wait(struct request_queue *q, int rw_flags,
|
||||
struct bio *bio)
|
||||
{
|
||||
const int rw = rw_flags & 0x01;
|
||||
const bool is_sync = rw_is_sync(rw_flags) != 0;
|
||||
struct request *rq;
|
||||
|
||||
rq = get_request(q, rw_flags, bio, GFP_NOIO);
|
||||
|
@ -852,10 +852,10 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
|
|||
struct io_context *ioc;
|
||||
struct request_list *rl = &q->rq;
|
||||
|
||||
prepare_to_wait_exclusive(&rl->wait[rw], &wait,
|
||||
prepare_to_wait_exclusive(&rl->wait[is_sync], &wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
|
||||
trace_block_sleeprq(q, bio, rw);
|
||||
trace_block_sleeprq(q, bio, rw_flags & 1);
|
||||
|
||||
__generic_unplug_device(q);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
@ -871,7 +871,7 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
|
|||
ioc_set_batching(q, ioc);
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
finish_wait(&rl->wait[rw], &wait);
|
||||
finish_wait(&rl->wait[is_sync], &wait);
|
||||
|
||||
rq = get_request(q, rw_flags, bio, GFP_NOIO);
|
||||
};
|
||||
|
@ -1070,14 +1070,14 @@ void __blk_put_request(struct request_queue *q, struct request *req)
|
|||
* it didn't come out of our reserved rq pools
|
||||
*/
|
||||
if (req->cmd_flags & REQ_ALLOCED) {
|
||||
int rw = rq_data_dir(req);
|
||||
int is_sync = rq_is_sync(req) != 0;
|
||||
int priv = req->cmd_flags & REQ_ELVPRIV;
|
||||
|
||||
BUG_ON(!list_empty(&req->queuelist));
|
||||
BUG_ON(!hlist_unhashed(&req->hash));
|
||||
|
||||
blk_free_request(q, req);
|
||||
freed_request(q, rw, priv);
|
||||
freed_request(q, is_sync, priv);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__blk_put_request);
|
||||
|
@ -1128,6 +1128,8 @@ void init_request_from_bio(struct request *req, struct bio *bio)
|
|||
req->cmd_flags |= REQ_UNPLUG;
|
||||
if (bio_rw_meta(bio))
|
||||
req->cmd_flags |= REQ_RW_META;
|
||||
if (bio_noidle(bio))
|
||||
req->cmd_flags |= REQ_NOIDLE;
|
||||
|
||||
req->errors = 0;
|
||||
req->hard_sector = req->sector = bio->bi_sector;
|
||||
|
@ -1136,6 +1138,15 @@ void init_request_from_bio(struct request *req, struct bio *bio)
|
|||
blk_rq_bio_prep(req->q, req, bio);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only disabling plugging for non-rotational devices if it does tagging
|
||||
* as well, otherwise we do need the proper merging
|
||||
*/
|
||||
static inline bool queue_should_plug(struct request_queue *q)
|
||||
{
|
||||
return !(blk_queue_nonrot(q) && blk_queue_tagged(q));
|
||||
}
|
||||
|
||||
static int __make_request(struct request_queue *q, struct bio *bio)
|
||||
{
|
||||
struct request *req;
|
||||
|
@ -1242,11 +1253,11 @@ get_rq:
|
|||
if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) ||
|
||||
bio_flagged(bio, BIO_CPU_AFFINE))
|
||||
req->cpu = blk_cpu_to_group(smp_processor_id());
|
||||
if (!blk_queue_nonrot(q) && elv_queue_empty(q))
|
||||
if (queue_should_plug(q) && elv_queue_empty(q))
|
||||
blk_plug_device(q);
|
||||
add_request(q, req);
|
||||
out:
|
||||
if (unplug || blk_queue_nonrot(q))
|
||||
if (unplug || !queue_should_plug(q))
|
||||
__generic_unplug_device(q);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
return 0;
|
||||
|
|
|
@ -48,28 +48,28 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count)
|
|||
q->nr_requests = nr;
|
||||
blk_queue_congestion_threshold(q);
|
||||
|
||||
if (rl->count[READ] >= queue_congestion_on_threshold(q))
|
||||
blk_set_queue_congested(q, READ);
|
||||
else if (rl->count[READ] < queue_congestion_off_threshold(q))
|
||||
blk_clear_queue_congested(q, READ);
|
||||
if (rl->count[BLK_RW_SYNC] >= queue_congestion_on_threshold(q))
|
||||
blk_set_queue_congested(q, BLK_RW_SYNC);
|
||||
else if (rl->count[BLK_RW_SYNC] < queue_congestion_off_threshold(q))
|
||||
blk_clear_queue_congested(q, BLK_RW_SYNC);
|
||||
|
||||
if (rl->count[WRITE] >= queue_congestion_on_threshold(q))
|
||||
blk_set_queue_congested(q, WRITE);
|
||||
else if (rl->count[WRITE] < queue_congestion_off_threshold(q))
|
||||
blk_clear_queue_congested(q, WRITE);
|
||||
if (rl->count[BLK_RW_ASYNC] >= queue_congestion_on_threshold(q))
|
||||
blk_set_queue_congested(q, BLK_RW_ASYNC);
|
||||
else if (rl->count[BLK_RW_ASYNC] < queue_congestion_off_threshold(q))
|
||||
blk_clear_queue_congested(q, BLK_RW_ASYNC);
|
||||
|
||||
if (rl->count[READ] >= q->nr_requests) {
|
||||
blk_set_queue_full(q, READ);
|
||||
} else if (rl->count[READ]+1 <= q->nr_requests) {
|
||||
blk_clear_queue_full(q, READ);
|
||||
wake_up(&rl->wait[READ]);
|
||||
if (rl->count[BLK_RW_SYNC] >= q->nr_requests) {
|
||||
blk_set_queue_full(q, BLK_RW_SYNC);
|
||||
} else if (rl->count[BLK_RW_SYNC]+1 <= q->nr_requests) {
|
||||
blk_clear_queue_full(q, BLK_RW_SYNC);
|
||||
wake_up(&rl->wait[BLK_RW_SYNC]);
|
||||
}
|
||||
|
||||
if (rl->count[WRITE] >= q->nr_requests) {
|
||||
blk_set_queue_full(q, WRITE);
|
||||
} else if (rl->count[WRITE]+1 <= q->nr_requests) {
|
||||
blk_clear_queue_full(q, WRITE);
|
||||
wake_up(&rl->wait[WRITE]);
|
||||
if (rl->count[BLK_RW_ASYNC] >= q->nr_requests) {
|
||||
blk_set_queue_full(q, BLK_RW_ASYNC);
|
||||
} else if (rl->count[BLK_RW_ASYNC]+1 <= q->nr_requests) {
|
||||
blk_clear_queue_full(q, BLK_RW_ASYNC);
|
||||
wake_up(&rl->wait[BLK_RW_ASYNC]);
|
||||
}
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
return ret;
|
||||
|
|
|
@ -1992,8 +1992,10 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
|
|||
}
|
||||
if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq))
|
||||
cfq_slice_expired(cfqd, 1);
|
||||
else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
|
||||
else if (sync && !rq_noidle(rq) &&
|
||||
RB_EMPTY_ROOT(&cfqq->sort_list)) {
|
||||
cfq_arm_slice_timer(cfqd);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfqd->rq_in_driver)
|
||||
|
|
|
@ -677,7 +677,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
|
|||
}
|
||||
|
||||
if (unplug_it && blk_queue_plugged(q)) {
|
||||
int nrq = q->rq.count[READ] + q->rq.count[WRITE]
|
||||
int nrq = q->rq.count[BLK_RW_SYNC] + q->rq.count[BLK_RW_ASYNC]
|
||||
- q->in_flight;
|
||||
|
||||
if (nrq >= q->unplug_thresh)
|
||||
|
|
|
@ -75,6 +75,7 @@ MODULE_DEVICE_TABLE(pci, applicom_pci_tbl);
|
|||
MODULE_AUTHOR("David Woodhouse & Applicom International");
|
||||
MODULE_DESCRIPTION("Driver for Applicom Profibus card");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_MISCDEV(AC_MINOR);
|
||||
|
||||
MODULE_SUPPORTED_DEVICE("ac");
|
||||
|
||||
|
|
|
@ -646,6 +646,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -5408,3 +5409,4 @@ module_exit(cy_cleanup_module);
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(CY_VERSION);
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
|
||||
|
|
|
@ -925,6 +925,7 @@ static void isicom_shutdown_port(struct isi_port *port)
|
|||
if (!card->count)
|
||||
isicom_shutdown_board(card);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static void isicom_flush_buffer(struct tty_struct *tty)
|
||||
|
|
|
@ -1486,11 +1486,11 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
|||
}
|
||||
|
||||
if (!handle) /* nothing else to do */
|
||||
return 0;
|
||||
goto put;
|
||||
|
||||
intr = readw(ip); /* port irq status */
|
||||
if (intr == 0)
|
||||
return 0;
|
||||
goto put;
|
||||
|
||||
writew(0, ip); /* ACK port */
|
||||
ofsAddr = p->tableAddr;
|
||||
|
@ -1499,16 +1499,17 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
|||
ofsAddr + HostStat);
|
||||
|
||||
if (!inited)
|
||||
return 0;
|
||||
goto put;
|
||||
|
||||
if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
tty_schedule_flip(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
||||
if (intr & IntrLine)
|
||||
moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
|
||||
put:
|
||||
tty_kref_put(tty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -820,7 +820,6 @@ static void mxser_check_modem_status(struct tty_struct *tty,
|
|||
wake_up_interruptible(&port->port.open_wait);
|
||||
}
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (port->port.flags & ASYNC_CTS_FLOW) {
|
||||
if (tty->hw_stopped) {
|
||||
if (status & UART_MSR_CTS) {
|
||||
|
|
|
@ -333,7 +333,7 @@ void rio_copy_to_card(void *from, void __iomem *to, int len)
|
|||
|
||||
int rio_minor(struct tty_struct *tty)
|
||||
{
|
||||
return tty->index + (tty->driver == rio_driver) ? 0 : 256;
|
||||
return tty->index + ((tty->driver == rio_driver) ? 0 : 256);
|
||||
}
|
||||
|
||||
static int rio_set_real_termios(void *ptr)
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
@ -1524,6 +1525,7 @@ module_param(iobase2, int, 0);
|
|||
module_param(iobase3, int, 0);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(RISCOM8_NORMAL_MAJOR);
|
||||
#endif /* MODULE */
|
||||
|
||||
/*
|
||||
|
|
|
@ -2365,3 +2365,4 @@ module_init(specialix_init_module);
|
|||
module_exit(specialix_exit_module);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(SPECIALIX_NORMAL_MAJOR);
|
||||
|
|
|
@ -14,8 +14,4 @@ config I2C_ALGOPCF
|
|||
config I2C_ALGOPCA
|
||||
tristate "I2C PCA 9564 interfaces"
|
||||
|
||||
config I2C_ALGO_SGI
|
||||
tristate
|
||||
depends on SGI_IP22 || SGI_IP32 || X86_VISWS
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
|
||||
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
|
||||
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
|
||||
obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and
|
||||
* MACE (SGI O2) chips.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-sgi.h>
|
||||
|
||||
|
||||
#define SGI_I2C_FORCE_IDLE (0 << 0)
|
||||
#define SGI_I2C_NOT_IDLE (1 << 0)
|
||||
#define SGI_I2C_WRITE (0 << 1)
|
||||
#define SGI_I2C_READ (1 << 1)
|
||||
#define SGI_I2C_RELEASE_BUS (0 << 2)
|
||||
#define SGI_I2C_HOLD_BUS (1 << 2)
|
||||
#define SGI_I2C_XFER_DONE (0 << 4)
|
||||
#define SGI_I2C_XFER_BUSY (1 << 4)
|
||||
#define SGI_I2C_ACK (0 << 5)
|
||||
#define SGI_I2C_NACK (1 << 5)
|
||||
#define SGI_I2C_BUS_OK (0 << 7)
|
||||
#define SGI_I2C_BUS_ERR (1 << 7)
|
||||
|
||||
#define get_control() adap->getctrl(adap->data)
|
||||
#define set_control(val) adap->setctrl(adap->data, val)
|
||||
#define read_data() adap->rdata(adap->data)
|
||||
#define write_data(val) adap->wdata(adap->data, val)
|
||||
|
||||
|
||||
static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adap->xfer_timeout; i++) {
|
||||
if ((get_control() & SGI_I2C_XFER_BUSY) == 0)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int wait_ack(struct i2c_algo_sgi_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (wait_xfer_done(adap))
|
||||
return -ETIMEDOUT;
|
||||
for (i = 0; i < adap->ack_timeout; i++) {
|
||||
if ((get_control() & SGI_I2C_NACK) == 0)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int force_idle(struct i2c_algo_sgi_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_control(SGI_I2C_FORCE_IDLE);
|
||||
for (i = 0; i < adap->xfer_timeout; i++) {
|
||||
if ((get_control() & SGI_I2C_NOT_IDLE) == 0)
|
||||
goto out;
|
||||
udelay(1);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
out:
|
||||
if (get_control() & SGI_I2C_BUS_ERR)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
|
||||
int rd)
|
||||
{
|
||||
if (rd)
|
||||
set_control(SGI_I2C_NOT_IDLE);
|
||||
/* Check if bus is idle, eventually force it to do so */
|
||||
if (get_control() & SGI_I2C_NOT_IDLE)
|
||||
if (force_idle(adap))
|
||||
return -EIO;
|
||||
/* Write out the i2c chip address and specify operation */
|
||||
set_control(SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
|
||||
if (rd)
|
||||
addr |= 1;
|
||||
write_data(addr);
|
||||
if (wait_ack(adap))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_control(SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (wait_xfer_done(adap))
|
||||
return -EIO;
|
||||
buf[i] = read_data();
|
||||
}
|
||||
set_control(SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* We are already in write state */
|
||||
for (i = 0; i < len; i++) {
|
||||
write_data(buf[i]);
|
||||
if (wait_ack(adap))
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
|
||||
struct i2c_msg *p;
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 0; !err && i < num; i++) {
|
||||
p = &msgs[i];
|
||||
err = do_address(adap, p->addr, p->flags & I2C_M_RD);
|
||||
if (err || !p->len)
|
||||
continue;
|
||||
if (p->flags & I2C_M_RD)
|
||||
err = i2c_read(adap, p->buf, p->len);
|
||||
else
|
||||
err = i2c_write(adap, p->buf, p->len);
|
||||
}
|
||||
|
||||
return (err < 0) ? err : i;
|
||||
}
|
||||
|
||||
static u32 sgi_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm sgi_algo = {
|
||||
.master_xfer = sgi_xfer,
|
||||
.functionality = sgi_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_sgi_add_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
adap->algo = &sgi_algo;
|
||||
|
||||
return i2c_add_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_sgi_add_bus);
|
||||
|
||||
MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
|
||||
MODULE_DESCRIPTION("I2C-Bus SGI algorithm");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -31,6 +31,13 @@ config LEDS_LOCOMO
|
|||
This option enables support for the LEDs on Sharp Locomo.
|
||||
Zaurus models SL-5500 and SL-5600.
|
||||
|
||||
config LEDS_MIKROTIK_RB532
|
||||
tristate "LED Support for Mikrotik Routerboard 532"
|
||||
depends on LEDS_CLASS && MIKROTIK_RB532
|
||||
help
|
||||
This option enables support for the so called "User LED" of
|
||||
Mikrotik's Routerboard 532.
|
||||
|
||||
config LEDS_S3C24XX
|
||||
tristate "LED Support for Samsung S3C24XX GPIO LEDs"
|
||||
depends on LEDS_CLASS && ARCH_S3C2410
|
||||
|
@ -117,11 +124,40 @@ config LEDS_GPIO
|
|||
help
|
||||
This option enables support for the LEDs connected to GPIO
|
||||
outputs. To be useful the particular board must have LEDs
|
||||
and they must be connected to the GPIO lines.
|
||||
and they must be connected to the GPIO lines. The LEDs must be
|
||||
defined as platform devices and/or OpenFirmware platform devices.
|
||||
The code to use these bindings can be selected below.
|
||||
|
||||
config LEDS_GPIO_PLATFORM
|
||||
bool "Platform device bindings for GPIO LEDs"
|
||||
depends on LEDS_GPIO
|
||||
default y
|
||||
help
|
||||
Let the leds-gpio driver drive LEDs which have been defined as
|
||||
platform devices. If you don't know what this means, say yes.
|
||||
|
||||
config LEDS_GPIO_OF
|
||||
bool "OpenFirmware platform device bindings for GPIO LEDs"
|
||||
depends on LEDS_GPIO && OF_DEVICE
|
||||
default y
|
||||
help
|
||||
Let the leds-gpio driver drive LEDs which have been defined as
|
||||
of_platform devices. For instance, LEDs which are listed in a "dts"
|
||||
file.
|
||||
|
||||
config LEDS_LP5521
|
||||
tristate "LED Support for the LP5521 LEDs"
|
||||
depends on LEDS_CLASS && I2C
|
||||
help
|
||||
If you say 'Y' here you get support for the National Semiconductor
|
||||
LP5521 LED driver used in n8x0 boards.
|
||||
|
||||
This driver can be built as a module by choosing 'M'. The module
|
||||
will be called leds-lp5521.
|
||||
|
||||
config LEDS_CLEVO_MAIL
|
||||
tristate "Mail LED on Clevo notebook (EXPERIMENTAL)"
|
||||
depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL
|
||||
tristate "Mail LED on Clevo notebook"
|
||||
depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI
|
||||
help
|
||||
This driver makes the mail LED accessible from userspace
|
||||
programs through the leds subsystem. This LED have three
|
||||
|
@ -171,6 +207,26 @@ config LEDS_DA903X
|
|||
This option enables support for on-chip LED drivers found
|
||||
on Dialog Semiconductor DA9030/DA9034 PMICs.
|
||||
|
||||
config LEDS_DAC124S085
|
||||
tristate "LED Support for DAC124S085 SPI DAC"
|
||||
depends on LEDS_CLASS && SPI
|
||||
help
|
||||
This option enables support for DAC124S085 SPI DAC from NatSemi,
|
||||
which can be used to control up to four LEDs.
|
||||
|
||||
config LEDS_PWM
|
||||
tristate "PWM driven LED Support"
|
||||
depends on LEDS_CLASS && HAVE_PWM
|
||||
help
|
||||
This option enables support for pwm driven LEDs
|
||||
|
||||
config LEDS_BD2802
|
||||
tristate "LED driver for BD2802 RGB LED"
|
||||
depends on LEDS_CLASS && I2C
|
||||
help
|
||||
This option enables support for BD2802GU RGB LED driver chips
|
||||
accessed via the I2C bus.
|
||||
|
||||
comment "LED Triggers"
|
||||
|
||||
config LEDS_TRIGGERS
|
||||
|
@ -216,6 +272,19 @@ config LEDS_TRIGGER_BACKLIGHT
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config LEDS_TRIGGER_GPIO
|
||||
tristate "LED GPIO Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
depends on GPIOLIB
|
||||
help
|
||||
This allows LEDs to be controlled by gpio events. It's good
|
||||
when using gpios as switches and triggering the needed LEDs
|
||||
from there. One use case is n810's keypad LEDs that could
|
||||
be triggered by this trigger when user slides up to show
|
||||
keypad.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config LEDS_TRIGGER_DEFAULT_ON
|
||||
tristate "LED Default ON Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
|
|
|
@ -6,7 +6,9 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
|
|||
|
||||
# LED Platform Drivers
|
||||
obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
|
||||
obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
|
||||
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
|
||||
obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
|
||||
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
|
||||
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
|
||||
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
|
||||
|
@ -24,10 +26,15 @@ obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
|
|||
obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
|
||||
obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
|
||||
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
|
||||
obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
|
||||
|
||||
# LED SPI Drivers
|
||||
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
||||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
|
||||
|
|
|
@ -64,7 +64,16 @@ static ssize_t led_brightness_store(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t led_max_brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", led_cdev->max_brightness);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
|
||||
static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL);
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
|
||||
#endif
|
||||
|
@ -138,6 +147,13 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
|||
list_add_tail(&led_cdev->node, &leds_list);
|
||||
up_write(&leds_list_lock);
|
||||
|
||||
if (!led_cdev->max_brightness)
|
||||
led_cdev->max_brightness = LED_FULL;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_max_brightness);
|
||||
if (rc)
|
||||
goto err_out_attr_max;
|
||||
|
||||
led_update_brightness(led_cdev);
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
|
@ -155,9 +171,11 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
|||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
err_out_led_list:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
|
||||
#endif
|
||||
err_out_attr_max:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_brightness);
|
||||
list_del(&led_cdev->node);
|
||||
#endif
|
||||
err_out:
|
||||
device_unregister(led_cdev->dev);
|
||||
return rc;
|
||||
|
@ -172,6 +190,7 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
|
|||
*/
|
||||
void led_classdev_unregister(struct led_classdev *led_cdev)
|
||||
{
|
||||
device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_brightness);
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
device_remove_file(led_cdev->dev, &dev_attr_trigger);
|
||||
|
|
|
@ -156,12 +156,20 @@ EXPORT_SYMBOL_GPL(led_trigger_set_default);
|
|||
int led_trigger_register(struct led_trigger *trigger)
|
||||
{
|
||||
struct led_classdev *led_cdev;
|
||||
struct led_trigger *trig;
|
||||
|
||||
rwlock_init(&trigger->leddev_list_lock);
|
||||
INIT_LIST_HEAD(&trigger->led_cdevs);
|
||||
|
||||
/* Add to the list of led triggers */
|
||||
down_write(&triggers_list_lock);
|
||||
/* Make sure the trigger's name isn't already in use */
|
||||
list_for_each_entry(trig, &trigger_list, next_trig) {
|
||||
if (!strcmp(trig->name, trigger->name)) {
|
||||
up_write(&triggers_list_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
/* Add to the list of led triggers */
|
||||
list_add_tail(&trigger->next_trig, &trigger_list);
|
||||
up_write(&triggers_list_lock);
|
||||
|
||||
|
|
|
@ -0,0 +1,765 @@
|
|||
/*
|
||||
* leds-bd2802.c - RGB LED Driver
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics
|
||||
* Kim Kyuwon <q1.kim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/leds-bd2802.h>
|
||||
|
||||
|
||||
#define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
|
||||
|
||||
#define BD2802_LED_OFFSET 0xa
|
||||
#define BD2802_COLOR_OFFSET 0x3
|
||||
|
||||
#define BD2802_REG_CLKSETUP 0x00
|
||||
#define BD2802_REG_CONTROL 0x01
|
||||
#define BD2802_REG_HOURSETUP 0x02
|
||||
#define BD2802_REG_CURRENT1SETUP 0x03
|
||||
#define BD2802_REG_CURRENT2SETUP 0x04
|
||||
#define BD2802_REG_WAVEPATTERN 0x05
|
||||
|
||||
#define BD2802_CURRENT_032 0x10 /* 3.2mA */
|
||||
#define BD2802_CURRENT_000 0x00 /* 0.0mA */
|
||||
|
||||
#define BD2802_PATTERN_FULL 0x07
|
||||
#define BD2802_PATTERN_HALF 0x03
|
||||
|
||||
enum led_ids {
|
||||
LED1,
|
||||
LED2,
|
||||
LED_NUM,
|
||||
};
|
||||
|
||||
enum led_colors {
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
};
|
||||
|
||||
enum led_bits {
|
||||
BD2802_OFF,
|
||||
BD2802_BLINK,
|
||||
BD2802_ON,
|
||||
};
|
||||
|
||||
/*
|
||||
* State '0' : 'off'
|
||||
* State '1' : 'blink'
|
||||
* State '2' : 'on'.
|
||||
*/
|
||||
struct led_state {
|
||||
unsigned r:2;
|
||||
unsigned g:2;
|
||||
unsigned b:2;
|
||||
};
|
||||
|
||||
struct bd2802_led {
|
||||
struct bd2802_led_platform_data *pdata;
|
||||
struct i2c_client *client;
|
||||
struct rw_semaphore rwsem;
|
||||
struct work_struct work;
|
||||
|
||||
struct led_state led[2];
|
||||
|
||||
/*
|
||||
* Making led_classdev as array is not recommended, because array
|
||||
* members prevent using 'container_of' macro. So repetitive works
|
||||
* are needed.
|
||||
*/
|
||||
struct led_classdev cdev_led1r;
|
||||
struct led_classdev cdev_led1g;
|
||||
struct led_classdev cdev_led1b;
|
||||
struct led_classdev cdev_led2r;
|
||||
struct led_classdev cdev_led2g;
|
||||
struct led_classdev cdev_led2b;
|
||||
|
||||
/*
|
||||
* Advanced Configuration Function(ADF) mode:
|
||||
* In ADF mode, user can set registers of BD2802GU directly,
|
||||
* therefore BD2802GU doesn't enter reset state.
|
||||
*/
|
||||
int adf_on;
|
||||
|
||||
enum led_ids led_id;
|
||||
enum led_colors color;
|
||||
enum led_bits state;
|
||||
};
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* BD2802GU helper functions */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
|
||||
enum led_colors color)
|
||||
{
|
||||
switch (color) {
|
||||
case RED:
|
||||
return !led->led[id].r;
|
||||
case GREEN:
|
||||
return !led->led[id].g;
|
||||
case BLUE:
|
||||
return !led->led[id].b;
|
||||
default:
|
||||
dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
|
||||
{
|
||||
if (led->led[id].r || led->led[id].g || led->led[id].b)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int bd2802_is_all_off(struct bd2802_led *led)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LED_NUM; i++)
|
||||
if (!bd2802_is_led_off(led, i))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
|
||||
{
|
||||
return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
|
||||
}
|
||||
|
||||
static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
|
||||
u8 reg_offset)
|
||||
{
|
||||
return reg_offset + bd2802_get_base_offset(id, color);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* BD2802GU core functions */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
|
||||
{
|
||||
int ret = i2c_smbus_write_byte_data(client, reg, val);
|
||||
if (ret >= 0)
|
||||
return 0;
|
||||
|
||||
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
|
||||
__func__, reg, val, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
|
||||
enum led_colors color, enum led_bits led_bit)
|
||||
{
|
||||
int i;
|
||||
u8 value;
|
||||
|
||||
for (i = 0; i < LED_NUM; i++) {
|
||||
if (i == id) {
|
||||
switch (color) {
|
||||
case RED:
|
||||
led->led[i].r = led_bit;
|
||||
break;
|
||||
case GREEN:
|
||||
led->led[i].g = led_bit;
|
||||
break;
|
||||
case BLUE:
|
||||
led->led[i].b = led_bit;
|
||||
break;
|
||||
default:
|
||||
dev_err(&led->client->dev,
|
||||
"%s: Invalid color\n", __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
|
||||
return;
|
||||
|
||||
if (!bd2802_is_led_off(led, id))
|
||||
return;
|
||||
|
||||
if (bd2802_is_all_off(led) && !led->adf_on) {
|
||||
gpio_set_value(led->pdata->reset_gpio, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In this case, other led is turned on, and current led is turned
|
||||
* off. So set RGB LED Control register to stop the current RGB LED
|
||||
*/
|
||||
value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
|
||||
bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
|
||||
}
|
||||
|
||||
static void bd2802_configure(struct bd2802_led *led)
|
||||
{
|
||||
struct bd2802_led_platform_data *pdata = led->pdata;
|
||||
u8 reg;
|
||||
|
||||
reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
|
||||
bd2802_write_byte(led->client, reg, pdata->rgb_time);
|
||||
|
||||
reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
|
||||
bd2802_write_byte(led->client, reg, pdata->rgb_time);
|
||||
}
|
||||
|
||||
static void bd2802_reset_cancel(struct bd2802_led *led)
|
||||
{
|
||||
gpio_set_value(led->pdata->reset_gpio, 1);
|
||||
udelay(100);
|
||||
bd2802_configure(led);
|
||||
}
|
||||
|
||||
static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
|
||||
{
|
||||
enum led_ids other_led = (id == LED1) ? LED2 : LED1;
|
||||
u8 value, other_led_on;
|
||||
|
||||
other_led_on = !bd2802_is_led_off(led, other_led);
|
||||
if (id == LED1)
|
||||
value = LED_CTL(other_led_on, 1);
|
||||
else
|
||||
value = LED_CTL(1 , other_led_on);
|
||||
|
||||
bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
|
||||
}
|
||||
|
||||
static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
|
||||
enum led_colors color)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
if (bd2802_is_all_off(led) && !led->adf_on)
|
||||
bd2802_reset_cancel(led);
|
||||
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
|
||||
bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
|
||||
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
|
||||
bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
|
||||
|
||||
bd2802_enable(led, id);
|
||||
bd2802_update_state(led, id, color, BD2802_ON);
|
||||
}
|
||||
|
||||
static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
|
||||
enum led_colors color)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
if (bd2802_is_all_off(led) && !led->adf_on)
|
||||
bd2802_reset_cancel(led);
|
||||
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
|
||||
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
|
||||
bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
|
||||
bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
|
||||
|
||||
bd2802_enable(led, id);
|
||||
bd2802_update_state(led, id, color, BD2802_BLINK);
|
||||
}
|
||||
|
||||
static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
|
||||
enum led_colors color, enum led_bits led_bit)
|
||||
{
|
||||
if (led_bit == BD2802_OFF) {
|
||||
dev_err(&led->client->dev,
|
||||
"Only 'blink' and 'on' are allowed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (led_bit == BD2802_BLINK)
|
||||
bd2802_set_blink(led, id, color);
|
||||
else
|
||||
bd2802_set_on(led, id, color);
|
||||
}
|
||||
|
||||
static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
|
||||
enum led_colors color)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
if (bd2802_is_rgb_off(led, id, color))
|
||||
return;
|
||||
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
|
||||
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
|
||||
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
|
||||
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
|
||||
|
||||
bd2802_update_state(led, id, color, BD2802_OFF);
|
||||
}
|
||||
|
||||
static void bd2802_restore_state(struct bd2802_led *led)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LED_NUM; i++) {
|
||||
if (led->led[i].r)
|
||||
bd2802_turn_on(led, i, RED, led->led[i].r);
|
||||
if (led->led[i].g)
|
||||
bd2802_turn_on(led, i, GREEN, led->led[i].g);
|
||||
if (led->led[i].b)
|
||||
bd2802_turn_on(led, i, BLUE, led->led[i].b);
|
||||
}
|
||||
}
|
||||
|
||||
#define BD2802_SET_REGISTER(reg_addr, reg_name) \
|
||||
static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
|
||||
unsigned long val; \
|
||||
int ret; \
|
||||
if (!count) \
|
||||
return -EINVAL; \
|
||||
ret = strict_strtoul(buf, 16, &val); \
|
||||
if (ret) \
|
||||
return ret; \
|
||||
down_write(&led->rwsem); \
|
||||
bd2802_write_byte(led->client, reg_addr, (u8) val); \
|
||||
up_write(&led->rwsem); \
|
||||
return count; \
|
||||
} \
|
||||
static struct device_attribute bd2802_reg##reg_addr##_attr = { \
|
||||
.attr = {.name = reg_name, .mode = 0644, .owner = THIS_MODULE}, \
|
||||
.store = bd2802_store_reg##reg_addr, \
|
||||
};
|
||||
|
||||
BD2802_SET_REGISTER(0x00, "0x00");
|
||||
BD2802_SET_REGISTER(0x01, "0x01");
|
||||
BD2802_SET_REGISTER(0x02, "0x02");
|
||||
BD2802_SET_REGISTER(0x03, "0x03");
|
||||
BD2802_SET_REGISTER(0x04, "0x04");
|
||||
BD2802_SET_REGISTER(0x05, "0x05");
|
||||
BD2802_SET_REGISTER(0x06, "0x06");
|
||||
BD2802_SET_REGISTER(0x07, "0x07");
|
||||
BD2802_SET_REGISTER(0x08, "0x08");
|
||||
BD2802_SET_REGISTER(0x09, "0x09");
|
||||
BD2802_SET_REGISTER(0x0a, "0x0a");
|
||||
BD2802_SET_REGISTER(0x0b, "0x0b");
|
||||
BD2802_SET_REGISTER(0x0c, "0x0c");
|
||||
BD2802_SET_REGISTER(0x0d, "0x0d");
|
||||
BD2802_SET_REGISTER(0x0e, "0x0e");
|
||||
BD2802_SET_REGISTER(0x0f, "0x0f");
|
||||
BD2802_SET_REGISTER(0x10, "0x10");
|
||||
BD2802_SET_REGISTER(0x11, "0x11");
|
||||
BD2802_SET_REGISTER(0x12, "0x12");
|
||||
BD2802_SET_REGISTER(0x13, "0x13");
|
||||
BD2802_SET_REGISTER(0x14, "0x14");
|
||||
BD2802_SET_REGISTER(0x15, "0x15");
|
||||
|
||||
static struct device_attribute *bd2802_addr_attributes[] = {
|
||||
&bd2802_reg0x00_attr,
|
||||
&bd2802_reg0x01_attr,
|
||||
&bd2802_reg0x02_attr,
|
||||
&bd2802_reg0x03_attr,
|
||||
&bd2802_reg0x04_attr,
|
||||
&bd2802_reg0x05_attr,
|
||||
&bd2802_reg0x06_attr,
|
||||
&bd2802_reg0x07_attr,
|
||||
&bd2802_reg0x08_attr,
|
||||
&bd2802_reg0x09_attr,
|
||||
&bd2802_reg0x0a_attr,
|
||||
&bd2802_reg0x0b_attr,
|
||||
&bd2802_reg0x0c_attr,
|
||||
&bd2802_reg0x0d_attr,
|
||||
&bd2802_reg0x0e_attr,
|
||||
&bd2802_reg0x0f_attr,
|
||||
&bd2802_reg0x10_attr,
|
||||
&bd2802_reg0x11_attr,
|
||||
&bd2802_reg0x12_attr,
|
||||
&bd2802_reg0x13_attr,
|
||||
&bd2802_reg0x14_attr,
|
||||
&bd2802_reg0x15_attr,
|
||||
};
|
||||
|
||||
static void bd2802_enable_adv_conf(struct bd2802_led *led)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
|
||||
ret = device_create_file(&led->client->dev,
|
||||
bd2802_addr_attributes[i]);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "failed to sysfs file %s\n",
|
||||
bd2802_addr_attributes[i]->attr.name);
|
||||
goto failed_remove_files;
|
||||
}
|
||||
}
|
||||
|
||||
if (bd2802_is_all_off(led))
|
||||
bd2802_reset_cancel(led);
|
||||
|
||||
led->adf_on = 1;
|
||||
|
||||
return;
|
||||
|
||||
failed_remove_files:
|
||||
for (i--; i >= 0; i--)
|
||||
device_remove_file(&led->client->dev,
|
||||
bd2802_addr_attributes[i]);
|
||||
}
|
||||
|
||||
static void bd2802_disable_adv_conf(struct bd2802_led *led)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
|
||||
device_remove_file(&led->client->dev,
|
||||
bd2802_addr_attributes[i]);
|
||||
|
||||
if (bd2802_is_all_off(led))
|
||||
gpio_set_value(led->pdata->reset_gpio, 0);
|
||||
|
||||
led->adf_on = 0;
|
||||
}
|
||||
|
||||
static ssize_t bd2802_show_adv_conf(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
|
||||
ssize_t ret;
|
||||
|
||||
down_read(&led->rwsem);
|
||||
if (led->adf_on)
|
||||
ret = sprintf(buf, "on\n");
|
||||
else
|
||||
ret = sprintf(buf, "off\n");
|
||||
up_read(&led->rwsem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t bd2802_store_adv_conf(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
down_write(&led->rwsem);
|
||||
if (!led->adf_on && !strncmp(buf, "on", 2))
|
||||
bd2802_enable_adv_conf(led);
|
||||
else if (led->adf_on && !strncmp(buf, "off", 3))
|
||||
bd2802_disable_adv_conf(led);
|
||||
up_write(&led->rwsem);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute bd2802_adv_conf_attr = {
|
||||
.attr = {
|
||||
.name = "advanced_configuration",
|
||||
.mode = 0644,
|
||||
.owner = THIS_MODULE
|
||||
},
|
||||
.show = bd2802_show_adv_conf,
|
||||
.store = bd2802_store_adv_conf,
|
||||
};
|
||||
|
||||
static void bd2802_led_work(struct work_struct *work)
|
||||
{
|
||||
struct bd2802_led *led = container_of(work, struct bd2802_led, work);
|
||||
|
||||
if (led->state)
|
||||
bd2802_turn_on(led, led->led_id, led->color, led->state);
|
||||
else
|
||||
bd2802_turn_off(led, led->led_id, led->color);
|
||||
}
|
||||
|
||||
#define BD2802_CONTROL_RGBS(name, id, clr) \
|
||||
static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
|
||||
enum led_brightness value) \
|
||||
{ \
|
||||
struct bd2802_led *led = \
|
||||
container_of(led_cdev, struct bd2802_led, cdev_##name); \
|
||||
led->led_id = id; \
|
||||
led->color = clr; \
|
||||
if (value == LED_OFF) \
|
||||
led->state = BD2802_OFF; \
|
||||
else \
|
||||
led->state = BD2802_ON; \
|
||||
schedule_work(&led->work); \
|
||||
} \
|
||||
static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
|
||||
unsigned long *delay_on, unsigned long *delay_off) \
|
||||
{ \
|
||||
struct bd2802_led *led = \
|
||||
container_of(led_cdev, struct bd2802_led, cdev_##name); \
|
||||
if (*delay_on == 0 || *delay_off == 0) \
|
||||
return -EINVAL; \
|
||||
led->led_id = id; \
|
||||
led->color = clr; \
|
||||
led->state = BD2802_BLINK; \
|
||||
schedule_work(&led->work); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
BD2802_CONTROL_RGBS(led1r, LED1, RED);
|
||||
BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
|
||||
BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
|
||||
BD2802_CONTROL_RGBS(led2r, LED2, RED);
|
||||
BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
|
||||
BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
|
||||
|
||||
static int bd2802_register_led_classdev(struct bd2802_led *led)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_WORK(&led->work, bd2802_led_work);
|
||||
|
||||
led->cdev_led1r.name = "led1_R";
|
||||
led->cdev_led1r.brightness = LED_OFF;
|
||||
led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
|
||||
led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
|
||||
led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
|
||||
if (ret < 0) {
|
||||
dev_err(&led->client->dev, "couldn't register LED %s\n",
|
||||
led->cdev_led1r.name);
|
||||
goto failed_unregister_led1_R;
|
||||
}
|
||||
|
||||
led->cdev_led1g.name = "led1_G";
|
||||
led->cdev_led1g.brightness = LED_OFF;
|
||||
led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
|
||||
led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
|
||||
led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
|
||||
if (ret < 0) {
|
||||
dev_err(&led->client->dev, "couldn't register LED %s\n",
|
||||
led->cdev_led1g.name);
|
||||
goto failed_unregister_led1_G;
|
||||
}
|
||||
|
||||
led->cdev_led1b.name = "led1_B";
|
||||
led->cdev_led1b.brightness = LED_OFF;
|
||||
led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
|
||||
led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
|
||||
led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
|
||||
if (ret < 0) {
|
||||
dev_err(&led->client->dev, "couldn't register LED %s\n",
|
||||
led->cdev_led1b.name);
|
||||
goto failed_unregister_led1_B;
|
||||
}
|
||||
|
||||
led->cdev_led2r.name = "led2_R";
|
||||
led->cdev_led2r.brightness = LED_OFF;
|
||||
led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
|
||||
led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
|
||||
led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
|
||||
if (ret < 0) {
|
||||
dev_err(&led->client->dev, "couldn't register LED %s\n",
|
||||
led->cdev_led2r.name);
|
||||
goto failed_unregister_led2_R;
|
||||
}
|
||||
|
||||
led->cdev_led2g.name = "led2_G";
|
||||
led->cdev_led2g.brightness = LED_OFF;
|
||||
led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
|
||||
led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
|
||||
led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
|
||||
if (ret < 0) {
|
||||
dev_err(&led->client->dev, "couldn't register LED %s\n",
|
||||
led->cdev_led2g.name);
|
||||
goto failed_unregister_led2_G;
|
||||
}
|
||||
|
||||
led->cdev_led2b.name = "led2_B";
|
||||
led->cdev_led2b.brightness = LED_OFF;
|
||||
led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
|
||||
led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
|
||||
led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
|
||||
if (ret < 0) {
|
||||
dev_err(&led->client->dev, "couldn't register LED %s\n",
|
||||
led->cdev_led2b.name);
|
||||
goto failed_unregister_led2_B;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed_unregister_led2_B:
|
||||
led_classdev_unregister(&led->cdev_led2g);
|
||||
failed_unregister_led2_G:
|
||||
led_classdev_unregister(&led->cdev_led2r);
|
||||
failed_unregister_led2_R:
|
||||
led_classdev_unregister(&led->cdev_led1b);
|
||||
failed_unregister_led1_B:
|
||||
led_classdev_unregister(&led->cdev_led1g);
|
||||
failed_unregister_led1_G:
|
||||
led_classdev_unregister(&led->cdev_led1r);
|
||||
failed_unregister_led1_R:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bd2802_unregister_led_classdev(struct bd2802_led *led)
|
||||
{
|
||||
cancel_work_sync(&led->work);
|
||||
led_classdev_unregister(&led->cdev_led1r);
|
||||
}
|
||||
|
||||
static int __devinit bd2802_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct bd2802_led *led;
|
||||
struct bd2802_led_platform_data *pdata;
|
||||
int ret;
|
||||
|
||||
led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
|
||||
if (!led) {
|
||||
dev_err(&client->dev, "failed to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
led->client = client;
|
||||
pdata = led->pdata = client->dev.platform_data;
|
||||
i2c_set_clientdata(client, led);
|
||||
|
||||
/* Configure RESET GPIO (L: RESET, H: RESET cancel) */
|
||||
gpio_request(pdata->reset_gpio, "RGB_RESETB");
|
||||
gpio_direction_output(pdata->reset_gpio, 1);
|
||||
|
||||
/* Tacss = min 0.1ms */
|
||||
udelay(100);
|
||||
|
||||
/* Detect BD2802GU */
|
||||
ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to detect device\n");
|
||||
goto failed_free;
|
||||
} else
|
||||
dev_info(&client->dev, "return 0x%02x\n", ret);
|
||||
|
||||
/* To save the power, reset BD2802 after detecting */
|
||||
gpio_set_value(led->pdata->reset_gpio, 0);
|
||||
|
||||
init_rwsem(&led->rwsem);
|
||||
|
||||
ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to create sysfs file %s\n",
|
||||
bd2802_adv_conf_attr.attr.name);
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
ret = bd2802_register_led_classdev(led);
|
||||
if (ret < 0)
|
||||
goto failed_unregister_dev_file;
|
||||
|
||||
return 0;
|
||||
|
||||
failed_unregister_dev_file:
|
||||
device_remove_file(&client->dev, &bd2802_adv_conf_attr);
|
||||
failed_free:
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(led);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit bd2802_remove(struct i2c_client *client)
|
||||
{
|
||||
struct bd2802_led *led = i2c_get_clientdata(client);
|
||||
|
||||
bd2802_unregister_led_classdev(led);
|
||||
gpio_set_value(led->pdata->reset_gpio, 0);
|
||||
if (led->adf_on)
|
||||
bd2802_disable_adv_conf(led);
|
||||
device_remove_file(&client->dev, &bd2802_adv_conf_attr);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(led);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg)
|
||||
{
|
||||
struct bd2802_led *led = i2c_get_clientdata(client);
|
||||
|
||||
gpio_set_value(led->pdata->reset_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd2802_resume(struct i2c_client *client)
|
||||
{
|
||||
struct bd2802_led *led = i2c_get_clientdata(client);
|
||||
|
||||
if (!bd2802_is_all_off(led) || led->adf_on) {
|
||||
gpio_set_value(led->pdata->reset_gpio, 1);
|
||||
udelay(100);
|
||||
bd2802_restore_state(led);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id bd2802_id[] = {
|
||||
{ "BD2802", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bd2802_id);
|
||||
|
||||
static struct i2c_driver bd2802_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "BD2802",
|
||||
},
|
||||
.probe = bd2802_probe,
|
||||
.remove = __exit_p(bd2802_remove),
|
||||
.suspend = bd2802_suspend,
|
||||
.resume = bd2802_resume,
|
||||
.id_table = bd2802_id,
|
||||
};
|
||||
|
||||
static int __init bd2802_init(void)
|
||||
{
|
||||
return i2c_add_driver(&bd2802_i2c_driver);
|
||||
}
|
||||
module_init(bd2802_init);
|
||||
|
||||
static void __exit bd2802_exit(void)
|
||||
{
|
||||
i2c_del_driver(&bd2802_i2c_driver);
|
||||
}
|
||||
module_exit(bd2802_exit);
|
||||
|
||||
MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("BD2802 LED driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright 2008
|
||||
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* LED driver for the DAC124S085 SPI DAC
|
||||
*/
|
||||
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
struct dac124s085_led {
|
||||
struct led_classdev ldev;
|
||||
struct spi_device *spi;
|
||||
int id;
|
||||
int brightness;
|
||||
char name[sizeof("dac124s085-3")];
|
||||
|
||||
struct mutex mutex;
|
||||
struct work_struct work;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct dac124s085 {
|
||||
struct dac124s085_led leds[4];
|
||||
};
|
||||
|
||||
#define REG_WRITE (0 << 12)
|
||||
#define REG_WRITE_UPDATE (1 << 12)
|
||||
#define ALL_WRITE_UPDATE (2 << 12)
|
||||
#define POWER_DOWN_OUTPUT (3 << 12)
|
||||
|
||||
static void dac124s085_led_work(struct work_struct *work)
|
||||
{
|
||||
struct dac124s085_led *led = container_of(work, struct dac124s085_led,
|
||||
work);
|
||||
u16 word;
|
||||
|
||||
mutex_lock(&led->mutex);
|
||||
word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE |
|
||||
(led->brightness & 0xfff));
|
||||
spi_write(led->spi, (const u8 *)&word, sizeof(word));
|
||||
mutex_unlock(&led->mutex);
|
||||
}
|
||||
|
||||
static void dac124s085_set_brightness(struct led_classdev *ldev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
|
||||
ldev);
|
||||
|
||||
spin_lock(&led->lock);
|
||||
led->brightness = brightness;
|
||||
schedule_work(&led->work);
|
||||
spin_unlock(&led->lock);
|
||||
}
|
||||
|
||||
static int dac124s085_probe(struct spi_device *spi)
|
||||
{
|
||||
struct dac124s085 *dac;
|
||||
struct dac124s085_led *led;
|
||||
int i, ret;
|
||||
|
||||
dac = kzalloc(sizeof(*dac), GFP_KERNEL);
|
||||
if (!dac)
|
||||
return -ENOMEM;
|
||||
|
||||
spi->bits_per_word = 16;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
|
||||
led = dac->leds + i;
|
||||
led->id = i;
|
||||
led->brightness = LED_OFF;
|
||||
led->spi = spi;
|
||||
snprintf(led->name, sizeof(led->name), "dac124s085-%d", i);
|
||||
spin_lock_init(&led->lock);
|
||||
INIT_WORK(&led->work, dac124s085_led_work);
|
||||
mutex_init(&led->mutex);
|
||||
led->ldev.name = led->name;
|
||||
led->ldev.brightness = LED_OFF;
|
||||
led->ldev.max_brightness = 0xfff;
|
||||
led->ldev.brightness_set = dac124s085_set_brightness;
|
||||
ret = led_classdev_register(&spi->dev, &led->ldev);
|
||||
if (ret < 0)
|
||||
goto eledcr;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, dac);
|
||||
|
||||
return 0;
|
||||
|
||||
eledcr:
|
||||
while (i--)
|
||||
led_classdev_unregister(&dac->leds[i].ldev);
|
||||
|
||||
spi_set_drvdata(spi, NULL);
|
||||
kfree(dac);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dac124s085_remove(struct spi_device *spi)
|
||||
{
|
||||
struct dac124s085 *dac = spi_get_drvdata(spi);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
|
||||
led_classdev_unregister(&dac->leds[i].ldev);
|
||||
cancel_work_sync(&dac->leds[i].work);
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, NULL);
|
||||
kfree(dac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver dac124s085_driver = {
|
||||
.probe = dac124s085_probe,
|
||||
.remove = dac124s085_remove,
|
||||
.driver = {
|
||||
.name = "dac124s085",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dac124s085_leds_init(void)
|
||||
{
|
||||
return spi_register_driver(&dac124s085_driver);
|
||||
}
|
||||
|
||||
static void __exit dac124s085_leds_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&dac124s085_driver);
|
||||
}
|
||||
|
||||
module_init(dac124s085_leds_init);
|
||||
module_exit(dac124s085_leds_exit);
|
||||
|
||||
MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
|
||||
MODULE_DESCRIPTION("DAC124S085 LED driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2007 8D Technologies inc.
|
||||
* Raphael Assenat <raph@8d.com>
|
||||
* Copyright (C) 2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -71,11 +72,67 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
|
|||
return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
|
||||
}
|
||||
|
||||
static int __devinit create_gpio_led(const struct gpio_led *template,
|
||||
struct gpio_led_data *led_dat, struct device *parent,
|
||||
int (*blink_set)(unsigned, unsigned long *, unsigned long *))
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* skip leds that aren't available */
|
||||
if (!gpio_is_valid(template->gpio)) {
|
||||
printk(KERN_INFO "Skipping unavilable LED gpio %d (%s)\n",
|
||||
template->gpio, template->name);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = gpio_request(template->gpio, template->name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
led_dat->cdev.name = template->name;
|
||||
led_dat->cdev.default_trigger = template->default_trigger;
|
||||
led_dat->gpio = template->gpio;
|
||||
led_dat->can_sleep = gpio_cansleep(template->gpio);
|
||||
led_dat->active_low = template->active_low;
|
||||
if (blink_set) {
|
||||
led_dat->platform_gpio_blink_set = blink_set;
|
||||
led_dat->cdev.blink_set = gpio_blink_set;
|
||||
}
|
||||
led_dat->cdev.brightness_set = gpio_led_set;
|
||||
led_dat->cdev.brightness = LED_OFF;
|
||||
if (!template->retain_state_suspended)
|
||||
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = gpio_direction_output(led_dat->gpio, led_dat->active_low);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
INIT_WORK(&led_dat->work, gpio_led_work);
|
||||
|
||||
ret = led_classdev_register(parent, &led_dat->cdev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
gpio_free(led_dat->gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void delete_gpio_led(struct gpio_led_data *led)
|
||||
{
|
||||
if (!gpio_is_valid(led->gpio))
|
||||
return;
|
||||
led_classdev_unregister(&led->cdev);
|
||||
cancel_work_sync(&led->work);
|
||||
gpio_free(led->gpio);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LEDS_GPIO_PLATFORM
|
||||
static int gpio_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_led *cur_led;
|
||||
struct gpio_led_data *leds_data, *led_dat;
|
||||
struct gpio_led_data *leds_data;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!pdata)
|
||||
|
@ -87,35 +144,10 @@ static int gpio_led_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
cur_led = &pdata->leds[i];
|
||||
led_dat = &leds_data[i];
|
||||
|
||||
ret = gpio_request(cur_led->gpio, cur_led->name);
|
||||
ret = create_gpio_led(&pdata->leds[i], &leds_data[i],
|
||||
&pdev->dev, pdata->gpio_blink_set);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
led_dat->cdev.name = cur_led->name;
|
||||
led_dat->cdev.default_trigger = cur_led->default_trigger;
|
||||
led_dat->gpio = cur_led->gpio;
|
||||
led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
|
||||
led_dat->active_low = cur_led->active_low;
|
||||
if (pdata->gpio_blink_set) {
|
||||
led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
|
||||
led_dat->cdev.blink_set = gpio_blink_set;
|
||||
}
|
||||
led_dat->cdev.brightness_set = gpio_led_set;
|
||||
led_dat->cdev.brightness = LED_OFF;
|
||||
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
gpio_direction_output(led_dat->gpio, led_dat->active_low);
|
||||
|
||||
INIT_WORK(&led_dat->work, gpio_led_work);
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
|
||||
if (ret < 0) {
|
||||
gpio_free(led_dat->gpio);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, leds_data);
|
||||
|
@ -123,13 +155,8 @@ static int gpio_led_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
if (i > 0) {
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
led_classdev_unregister(&leds_data[i].cdev);
|
||||
cancel_work_sync(&leds_data[i].work);
|
||||
gpio_free(leds_data[i].gpio);
|
||||
}
|
||||
}
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
delete_gpio_led(&leds_data[i]);
|
||||
|
||||
kfree(leds_data);
|
||||
|
||||
|
@ -144,11 +171,8 @@ static int __devexit gpio_led_remove(struct platform_device *pdev)
|
|||
|
||||
leds_data = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
led_classdev_unregister(&leds_data[i].cdev);
|
||||
cancel_work_sync(&leds_data[i].work);
|
||||
gpio_free(leds_data[i].gpio);
|
||||
}
|
||||
for (i = 0; i < pdata->num_leds; i++)
|
||||
delete_gpio_led(&leds_data[i]);
|
||||
|
||||
kfree(leds_data);
|
||||
|
||||
|
@ -164,20 +188,133 @@ static struct platform_driver gpio_led_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:leds-gpio");
|
||||
#endif /* CONFIG_LEDS_GPIO_PLATFORM */
|
||||
|
||||
/* Code to create from OpenFirmware platform devices */
|
||||
#ifdef CONFIG_LEDS_GPIO_OF
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
struct gpio_led_of_platform_data {
|
||||
int num_leds;
|
||||
struct gpio_led_data led_data[];
|
||||
};
|
||||
|
||||
static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct device_node *np = ofdev->node, *child;
|
||||
struct gpio_led led;
|
||||
struct gpio_led_of_platform_data *pdata;
|
||||
int count = 0, ret;
|
||||
|
||||
/* count LEDs defined by this device, so we know how much to allocate */
|
||||
for_each_child_of_node(np, child)
|
||||
count++;
|
||||
if (!count)
|
||||
return 0; /* or ENODEV? */
|
||||
|
||||
pdata = kzalloc(sizeof(*pdata) + sizeof(struct gpio_led_data) * count,
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&led, 0, sizeof(led));
|
||||
for_each_child_of_node(np, child) {
|
||||
enum of_gpio_flags flags;
|
||||
|
||||
led.gpio = of_get_gpio_flags(child, 0, &flags);
|
||||
led.active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
led.name = of_get_property(child, "label", NULL) ? : child->name;
|
||||
led.default_trigger =
|
||||
of_get_property(child, "linux,default-trigger", NULL);
|
||||
|
||||
ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
|
||||
&ofdev->dev, NULL);
|
||||
if (ret < 0) {
|
||||
of_node_put(child);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, pdata);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (count = pdata->num_leds - 2; count >= 0; count--)
|
||||
delete_gpio_led(&pdata->led_data[count]);
|
||||
|
||||
kfree(pdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit of_gpio_leds_remove(struct of_device *ofdev)
|
||||
{
|
||||
struct gpio_led_of_platform_data *pdata = dev_get_drvdata(&ofdev->dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++)
|
||||
delete_gpio_led(&pdata->led_data[i]);
|
||||
|
||||
kfree(pdata);
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_gpio_leds_match[] = {
|
||||
{ .compatible = "gpio-leds", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct of_platform_driver of_gpio_leds_driver = {
|
||||
.driver = {
|
||||
.name = "of_gpio_leds",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.match_table = of_gpio_leds_match,
|
||||
.probe = of_gpio_leds_probe,
|
||||
.remove = __devexit_p(of_gpio_leds_remove),
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init gpio_led_init(void)
|
||||
{
|
||||
return platform_driver_register(&gpio_led_driver);
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_LEDS_GPIO_PLATFORM
|
||||
ret = platform_driver_register(&gpio_led_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
#ifdef CONFIG_LEDS_GPIO_OF
|
||||
ret = of_register_platform_driver(&of_gpio_leds_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_LEDS_GPIO_PLATFORM
|
||||
if (ret)
|
||||
platform_driver_unregister(&gpio_led_driver);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit gpio_led_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_LEDS_GPIO_PLATFORM
|
||||
platform_driver_unregister(&gpio_led_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_LEDS_GPIO_OF
|
||||
of_unregister_platform_driver(&of_gpio_leds_driver);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(gpio_led_init);
|
||||
module_exit(gpio_led_exit);
|
||||
|
||||
MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
|
||||
MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
|
||||
MODULE_DESCRIPTION("GPIO LED driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:leds-gpio");
|
||||
|
|
|
@ -104,7 +104,7 @@ static struct led_classdev h1940_blueled = {
|
|||
.default_trigger = "h1940-bluetooth",
|
||||
};
|
||||
|
||||
static int __init h1940leds_probe(struct platform_device *pdev)
|
||||
static int __devinit h1940leds_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
|
|||
{
|
||||
struct pca9532_data *data = input_get_drvdata(dev);
|
||||
|
||||
if (type != EV_SND && (code != SND_BELL || code != SND_TONE))
|
||||
if (!(type == EV_SND && (code == SND_BELL || code == SND_TONE)))
|
||||
return -1;
|
||||
|
||||
/* XXX: allow different kind of beeps with psc/pwm modifications */
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* linux/drivers/leds-pwm.c
|
||||
*
|
||||
* simple PWM based LED control
|
||||
*
|
||||
* Copyright 2009 Luotao Fu @ Pengutronix (l.fu@pengutronix.de)
|
||||
*
|
||||
* based on leds-gpio.c by Raphael Assenat <raph@8d.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/leds_pwm.h>
|
||||
|
||||
struct led_pwm_data {
|
||||
struct led_classdev cdev;
|
||||
struct pwm_device *pwm;
|
||||
unsigned int active_low;
|
||||
unsigned int period;
|
||||
unsigned int max_brightness;
|
||||
};
|
||||
|
||||
static void led_pwm_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct led_pwm_data *led_dat =
|
||||
container_of(led_cdev, struct led_pwm_data, cdev);
|
||||
unsigned int max = led_dat->max_brightness;
|
||||
unsigned int period = led_dat->period;
|
||||
|
||||
if (brightness == 0) {
|
||||
pwm_config(led_dat->pwm, 0, period);
|
||||
pwm_disable(led_dat->pwm);
|
||||
} else {
|
||||
pwm_config(led_dat->pwm, brightness * period / max, period);
|
||||
pwm_enable(led_dat->pwm);
|
||||
}
|
||||
}
|
||||
|
||||
static int led_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct led_pwm *cur_led;
|
||||
struct led_pwm_data *leds_data, *led_dat;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!pdata)
|
||||
return -EBUSY;
|
||||
|
||||
leds_data = kzalloc(sizeof(struct led_pwm_data) * pdata->num_leds,
|
||||
GFP_KERNEL);
|
||||
if (!leds_data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
cur_led = &pdata->leds[i];
|
||||
led_dat = &leds_data[i];
|
||||
|
||||
led_dat->pwm = pwm_request(cur_led->pwm_id,
|
||||
cur_led->name);
|
||||
if (IS_ERR(led_dat->pwm)) {
|
||||
dev_err(&pdev->dev, "unable to request PWM %d\n",
|
||||
cur_led->pwm_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
led_dat->cdev.name = cur_led->name;
|
||||
led_dat->cdev.default_trigger = cur_led->default_trigger;
|
||||
led_dat->active_low = cur_led->active_low;
|
||||
led_dat->max_brightness = cur_led->max_brightness;
|
||||
led_dat->period = cur_led->pwm_period_ns;
|
||||
led_dat->cdev.brightness_set = led_pwm_set;
|
||||
led_dat->cdev.brightness = LED_OFF;
|
||||
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
|
||||
if (ret < 0) {
|
||||
pwm_free(led_dat->pwm);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, leds_data);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (i > 0) {
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
led_classdev_unregister(&leds_data[i].cdev);
|
||||
pwm_free(leds_data[i].pwm);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(leds_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit led_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct led_pwm_data *leds_data;
|
||||
|
||||
leds_data = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
led_classdev_unregister(&leds_data[i].cdev);
|
||||
pwm_free(leds_data[i].pwm);
|
||||
}
|
||||
|
||||
kfree(leds_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver led_pwm_driver = {
|
||||
.probe = led_pwm_probe,
|
||||
.remove = __devexit_p(led_pwm_remove),
|
||||
.driver = {
|
||||
.name = "leds_pwm",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init led_pwm_init(void)
|
||||
{
|
||||
return platform_driver_register(&led_pwm_driver);
|
||||
}
|
||||
|
||||
static void __exit led_pwm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&led_pwm_driver);
|
||||
}
|
||||
|
||||
module_init(led_pwm_init);
|
||||
module_exit(led_pwm_exit);
|
||||
|
||||
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("PWM LED driver for PXA");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:leds-pwm");
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* LEDs driver for the "User LED" on Routerboard532
|
||||
*
|
||||
* Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org>
|
||||
*
|
||||
* Based on leds-cobalt-qube.c by Florian Fainelly and
|
||||
* rb-diag.c (my own standalone driver for both LED and
|
||||
* button of Routerboard532).
|
||||
*/
|
||||
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/mach-rc32434/gpio.h>
|
||||
#include <asm/mach-rc32434/rb.h>
|
||||
|
||||
static void rb532_led_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
if (brightness)
|
||||
set_latch_u5(LO_ULED, 0);
|
||||
|
||||
else
|
||||
set_latch_u5(0, LO_ULED);
|
||||
}
|
||||
|
||||
static enum led_brightness rb532_led_get(struct led_classdev *cdev)
|
||||
{
|
||||
return (get_latch_u5() & LO_ULED) ? LED_FULL : LED_OFF;
|
||||
}
|
||||
|
||||
static struct led_classdev rb532_uled = {
|
||||
.name = "uled",
|
||||
.brightness_set = rb532_led_set,
|
||||
.brightness_get = rb532_led_get,
|
||||
.default_trigger = "nand-disk",
|
||||
};
|
||||
|
||||
static int __devinit rb532_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
return led_classdev_register(&pdev->dev, &rb532_uled);
|
||||
}
|
||||
|
||||
static int __devexit rb532_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
led_classdev_unregister(&rb532_uled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rb532_led_driver = {
|
||||
.probe = rb532_led_probe,
|
||||
.remove = __devexit_p(rb532_led_remove),
|
||||
.driver = {
|
||||
.name = "rb532-led",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rb532_led_init(void)
|
||||
{
|
||||
return platform_driver_register(&rb532_led_driver);
|
||||
}
|
||||
|
||||
static void __exit rb532_led_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rb532_led_driver);
|
||||
}
|
||||
|
||||
module_init(rb532_led_init);
|
||||
module_exit(rb532_led_exit);
|
||||
|
||||
MODULE_ALIAS("platform:rb532-led");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("User LED support for Routerboard532");
|
||||
MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
|
|
@ -102,14 +102,11 @@ static int s3c24xx_led_probe(struct platform_device *dev)
|
|||
ret = led_classdev_register(&dev->dev, &led->cdev);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "led_classdev_register failed\n");
|
||||
goto exit_err1;
|
||||
kfree(led);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_err1:
|
||||
kfree(led);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver s3c24xx_led_driver = {
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
static inline void led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
if (value > LED_FULL)
|
||||
value = LED_FULL;
|
||||
if (value > led_cdev->max_brightness)
|
||||
value = led_cdev->max_brightness;
|
||||
led_cdev->brightness = value;
|
||||
if (!(led_cdev->flags & LED_SUSPENDED))
|
||||
led_cdev->brightness_set(led_cdev, value);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
static void defon_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
led_set_brightness(led_cdev, LED_FULL);
|
||||
led_set_brightness(led_cdev, led_cdev->max_brightness);
|
||||
}
|
||||
|
||||
static struct led_trigger defon_led_trigger = {
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* ledtrig-gio.c - LED Trigger Based on GPIO events
|
||||
*
|
||||
* Copyright 2009 Felipe Balbi <me@felipebalbi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/leds.h>
|
||||
#include "leds.h"
|
||||
|
||||
struct gpio_trig_data {
|
||||
struct led_classdev *led;
|
||||
struct work_struct work;
|
||||
|
||||
unsigned desired_brightness; /* desired brightness when led is on */
|
||||
unsigned inverted; /* true when gpio is inverted */
|
||||
unsigned gpio; /* gpio that triggers the leds */
|
||||
};
|
||||
|
||||
static irqreturn_t gpio_trig_irq(int irq, void *_led)
|
||||
{
|
||||
struct led_classdev *led = _led;
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
|
||||
/* just schedule_work since gpio_get_value can sleep */
|
||||
schedule_work(&gpio_data->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
};
|
||||
|
||||
static void gpio_trig_work(struct work_struct *work)
|
||||
{
|
||||
struct gpio_trig_data *gpio_data = container_of(work,
|
||||
struct gpio_trig_data, work);
|
||||
int tmp;
|
||||
|
||||
if (!gpio_data->gpio)
|
||||
return;
|
||||
|
||||
tmp = gpio_get_value(gpio_data->gpio);
|
||||
if (gpio_data->inverted)
|
||||
tmp = !tmp;
|
||||
|
||||
if (tmp) {
|
||||
if (gpio_data->desired_brightness)
|
||||
led_set_brightness(gpio_data->led,
|
||||
gpio_data->desired_brightness);
|
||||
else
|
||||
led_set_brightness(gpio_data->led, LED_FULL);
|
||||
} else {
|
||||
led_set_brightness(gpio_data->led, LED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t gpio_trig_brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
|
||||
return sprintf(buf, "%u\n", gpio_data->desired_brightness);
|
||||
}
|
||||
|
||||
static ssize_t gpio_trig_brightness_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
unsigned desired_brightness;
|
||||
int ret;
|
||||
|
||||
ret = sscanf(buf, "%u", &desired_brightness);
|
||||
if (ret < 1 || desired_brightness > 255) {
|
||||
dev_err(dev, "invalid value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_data->desired_brightness = desired_brightness;
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
|
||||
gpio_trig_brightness_store);
|
||||
|
||||
static ssize_t gpio_trig_inverted_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
|
||||
return sprintf(buf, "%s\n", gpio_data->inverted ? "yes" : "no");
|
||||
}
|
||||
|
||||
static ssize_t gpio_trig_inverted_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
unsigned inverted;
|
||||
int ret;
|
||||
|
||||
ret = sscanf(buf, "%u", &inverted);
|
||||
if (ret < 1) {
|
||||
dev_err(dev, "invalid value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_data->inverted = !!inverted;
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show,
|
||||
gpio_trig_inverted_store);
|
||||
|
||||
static ssize_t gpio_trig_gpio_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
|
||||
return sprintf(buf, "%u\n", gpio_data->gpio);
|
||||
}
|
||||
|
||||
static ssize_t gpio_trig_gpio_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
unsigned gpio;
|
||||
int ret;
|
||||
|
||||
ret = sscanf(buf, "%u", &gpio);
|
||||
if (ret < 1) {
|
||||
dev_err(dev, "couldn't read gpio number\n");
|
||||
flush_work(&gpio_data->work);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!gpio) {
|
||||
free_irq(gpio_to_irq(gpio_data->gpio), led);
|
||||
return n;
|
||||
}
|
||||
|
||||
if (gpio_data->gpio > 0 && gpio_data->gpio != gpio)
|
||||
free_irq(gpio_to_irq(gpio_data->gpio), led);
|
||||
|
||||
gpio_data->gpio = gpio;
|
||||
ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq,
|
||||
IRQF_SHARED | IRQF_TRIGGER_RISING
|
||||
| IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
|
||||
if (ret)
|
||||
dev_err(dev, "request_irq failed with error %d\n", ret);
|
||||
|
||||
return ret ? ret : n;
|
||||
}
|
||||
static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store);
|
||||
|
||||
static void gpio_trig_activate(struct led_classdev *led)
|
||||
{
|
||||
struct gpio_trig_data *gpio_data;
|
||||
int ret;
|
||||
|
||||
gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
|
||||
if (!gpio_data)
|
||||
return;
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_gpio);
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_inverted);
|
||||
if (ret)
|
||||
goto err_inverted;
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_desired_brightness);
|
||||
if (ret)
|
||||
goto err_brightness;
|
||||
|
||||
gpio_data->led = led;
|
||||
led->trigger_data = gpio_data;
|
||||
INIT_WORK(&gpio_data->work, gpio_trig_work);
|
||||
|
||||
return;
|
||||
|
||||
err_brightness:
|
||||
device_remove_file(led->dev, &dev_attr_inverted);
|
||||
|
||||
err_inverted:
|
||||
device_remove_file(led->dev, &dev_attr_gpio);
|
||||
|
||||
err_gpio:
|
||||
kfree(gpio_data);
|
||||
}
|
||||
|
||||
static void gpio_trig_deactivate(struct led_classdev *led)
|
||||
{
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
|
||||
if (gpio_data) {
|
||||
device_remove_file(led->dev, &dev_attr_gpio);
|
||||
device_remove_file(led->dev, &dev_attr_inverted);
|
||||
device_remove_file(led->dev, &dev_attr_desired_brightness);
|
||||
flush_work(&gpio_data->work);
|
||||
free_irq(gpio_to_irq(gpio_data->gpio),led);
|
||||
kfree(gpio_data);
|
||||
}
|
||||
}
|
||||
|
||||
static struct led_trigger gpio_led_trigger = {
|
||||
.name = "gpio",
|
||||
.activate = gpio_trig_activate,
|
||||
.deactivate = gpio_trig_deactivate,
|
||||
};
|
||||
|
||||
static int __init gpio_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&gpio_led_trigger);
|
||||
}
|
||||
module_init(gpio_trig_init);
|
||||
|
||||
static void __exit gpio_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&gpio_led_trigger);
|
||||
}
|
||||
module_exit(gpio_trig_exit);
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>");
|
||||
MODULE_DESCRIPTION("GPIO LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -47,7 +47,7 @@ static void led_heartbeat_function(unsigned long data)
|
|||
msecs_to_jiffies(heartbeat_data->period);
|
||||
delay = msecs_to_jiffies(70);
|
||||
heartbeat_data->phase++;
|
||||
brightness = LED_FULL;
|
||||
brightness = led_cdev->max_brightness;
|
||||
break;
|
||||
case 1:
|
||||
delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
|
||||
|
@ -56,7 +56,7 @@ static void led_heartbeat_function(unsigned long data)
|
|||
case 2:
|
||||
delay = msecs_to_jiffies(70);
|
||||
heartbeat_data->phase++;
|
||||
brightness = LED_FULL;
|
||||
brightness = led_cdev->max_brightness;
|
||||
break;
|
||||
default:
|
||||
delay = heartbeat_data->period - heartbeat_data->period / 4 -
|
||||
|
|
|
@ -37,7 +37,8 @@ static void ledtrig_ide_timerfunc(unsigned long data)
|
|||
{
|
||||
if (ide_lastactivity != ide_activity) {
|
||||
ide_lastactivity = ide_activity;
|
||||
led_trigger_event(ledtrig_ide, LED_FULL);
|
||||
/* INT_MAX will set each LED to its maximum brightness */
|
||||
led_trigger_event(ledtrig_ide, INT_MAX);
|
||||
mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
|
||||
} else {
|
||||
led_trigger_event(ledtrig_ide, LED_OFF);
|
||||
|
|
|
@ -166,7 +166,7 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
|
|||
|
||||
timer_data->brightness_on = led_get_brightness(led_cdev);
|
||||
if (timer_data->brightness_on == LED_OFF)
|
||||
timer_data->brightness_on = LED_FULL;
|
||||
timer_data->brightness_on = led_cdev->max_brightness;
|
||||
led_cdev->trigger_data = timer_data;
|
||||
|
||||
init_timer(&timer_data->timer);
|
||||
|
|
|
@ -123,6 +123,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
|
|||
goto out_free_pages;
|
||||
|
||||
bio->bi_io_vec[i].bv_page = page;
|
||||
bio->bi_vcnt = i+1;
|
||||
}
|
||||
}
|
||||
/* If not user-requests, copy the page pointers to all bios */
|
||||
|
@ -138,9 +139,9 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
|
|||
return r1_bio;
|
||||
|
||||
out_free_pages:
|
||||
for (i=0; i < RESYNC_PAGES ; i++)
|
||||
for (j=0 ; j < pi->raid_disks; j++)
|
||||
safe_put_page(r1_bio->bios[j]->bi_io_vec[i].bv_page);
|
||||
for (j=0 ; j < pi->raid_disks; j++)
|
||||
for (i=0; i < r1_bio->bios[j]->bi_vcnt ; i++)
|
||||
put_page(r1_bio->bios[j]->bi_io_vec[i].bv_page);
|
||||
j = -1;
|
||||
out_free_bio:
|
||||
while ( ++j < pi->raid_disks )
|
||||
|
@ -585,7 +586,7 @@ static int raid1_congested(void *data, int bits)
|
|||
/* Note the '|| 1' - when read_balance prefers
|
||||
* non-congested targets, it can be removed
|
||||
*/
|
||||
if ((bits & (1<<BDI_write_congested)) || 1)
|
||||
if ((bits & (1<<BDI_async_congested)) || 1)
|
||||
ret |= bdi_congested(&q->backing_dev_info, bits);
|
||||
else
|
||||
ret &= bdi_congested(&q->backing_dev_info, bits);
|
||||
|
|
|
@ -2279,9 +2279,8 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
|
|||
mutex_lock(&ioc->sas_topology_mutex);
|
||||
list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
|
||||
|
||||
if (port_info->phy_info &&
|
||||
(!(port_info->phy_info[0].identify.device_info &
|
||||
MPI_SAS_DEVICE_INFO_SMP_TARGET)))
|
||||
if (!(port_info->phy_info[0].identify.device_info &
|
||||
MPI_SAS_DEVICE_INFO_SMP_TARGET))
|
||||
continue;
|
||||
|
||||
if (mptsas_sas_expander_pg0(ioc, &buffer,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# Core functionality.
|
||||
obj-$(CONFIG_MTD) += mtd.o
|
||||
mtd-y := mtdcore.o mtdsuper.o
|
||||
mtd-y := mtdcore.o mtdsuper.o mtdbdi.o
|
||||
mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
|
||||
|
||||
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
|
||||
|
|
|
@ -44,8 +44,6 @@ struct ar7_bin_rec {
|
|||
unsigned int address;
|
||||
};
|
||||
|
||||
static struct mtd_partition ar7_parts[AR7_PARTS];
|
||||
|
||||
static int create_mtd_partitions(struct mtd_info *master,
|
||||
struct mtd_partition **pparts,
|
||||
unsigned long origin)
|
||||
|
@ -57,7 +55,11 @@ static int create_mtd_partitions(struct mtd_info *master,
|
|||
unsigned int root_offset = ROOT_OFFSET;
|
||||
|
||||
int retries = 10;
|
||||
struct mtd_partition *ar7_parts;
|
||||
|
||||
ar7_parts = kzalloc(sizeof(*ar7_parts) * AR7_PARTS, GFP_KERNEL);
|
||||
if (!ar7_parts)
|
||||
return -ENOMEM;
|
||||
ar7_parts[0].name = "loader";
|
||||
ar7_parts[0].offset = 0;
|
||||
ar7_parts[0].size = master->erasesize;
|
||||
|
|
|
@ -1236,10 +1236,14 @@ static int inval_cache_and_wait_for_operation(
|
|||
remove_wait_queue(&chip->wq, &wait);
|
||||
spin_lock(chip->mutex);
|
||||
}
|
||||
if (chip->erase_suspended || chip->write_suspended) {
|
||||
/* Suspend has occured while sleep: reset timeout */
|
||||
if (chip->erase_suspended && chip_state == FL_ERASING) {
|
||||
/* Erase suspend occured while sleep: reset timeout */
|
||||
timeo = reset_timeo;
|
||||
chip->erase_suspended = 0;
|
||||
}
|
||||
if (chip->write_suspended && chip_state == FL_WRITING) {
|
||||
/* Write suspend occured while sleep: reset timeout */
|
||||
timeo = reset_timeo;
|
||||
chip->write_suspended = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -282,6 +282,16 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
|
|||
}
|
||||
}
|
||||
|
||||
static void fixup_M29W128G_write_buffer(struct mtd_info *mtd, void *param)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
if (cfi->cfiq->BufWriteTimeoutTyp) {
|
||||
pr_warning("Don't use write buffer on ST flash M29W128G\n");
|
||||
cfi->cfiq->BufWriteTimeoutTyp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct cfi_fixup cfi_fixup_table[] = {
|
||||
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
|
||||
#ifdef AMD_BOOTLOC_BUG
|
||||
|
@ -298,6 +308,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
|
|||
{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, },
|
||||
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, },
|
||||
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, },
|
||||
{ CFI_MFR_ST, 0x227E, fixup_M29W128G_write_buffer, NULL, },
|
||||
#if !FORCE_WORD_WRITE
|
||||
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
|
||||
#endif
|
||||
|
|
|
@ -159,6 +159,7 @@
|
|||
#define SST39LF800 0x2781
|
||||
#define SST39LF160 0x2782
|
||||
#define SST39VF1601 0x234b
|
||||
#define SST39VF3201 0x235b
|
||||
#define SST39LF512 0x00D4
|
||||
#define SST39LF010 0x00D5
|
||||
#define SST39LF020 0x00D6
|
||||
|
@ -1489,6 +1490,21 @@ static const struct amd_flash_info jedec_table[] = {
|
|||
ERASEINFO(0x1000,256),
|
||||
ERASEINFO(0x1000,256)
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_SST, /* should be CFI */
|
||||
.dev_id = SST39VF3201,
|
||||
.name = "SST 39VF3201",
|
||||
.devtypes = CFI_DEVICETYPE_X16,
|
||||
.uaddr = MTD_UADDR_0xAAAA_0x5555,
|
||||
.dev_size = SIZE_4MiB,
|
||||
.cmd_set = P_ID_AMD_STD,
|
||||
.nr_regions = 4,
|
||||
.regions = {
|
||||
ERASEINFO(0x1000,256),
|
||||
ERASEINFO(0x1000,256),
|
||||
ERASEINFO(0x1000,256),
|
||||
ERASEINFO(0x1000,256)
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_SST,
|
||||
.dev_id = SST36VF3203,
|
||||
|
|
|
@ -21,6 +21,8 @@ static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch
|
|||
static int mapram_erase (struct mtd_info *, struct erase_info *);
|
||||
static void mapram_nop (struct mtd_info *);
|
||||
static struct mtd_info *map_ram_probe(struct map_info *map);
|
||||
static unsigned long mapram_unmapped_area(struct mtd_info *, unsigned long,
|
||||
unsigned long, unsigned long);
|
||||
|
||||
|
||||
static struct mtd_chip_driver mapram_chipdrv = {
|
||||
|
@ -64,6 +66,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
|
|||
mtd->type = MTD_RAM;
|
||||
mtd->size = map->size;
|
||||
mtd->erase = mapram_erase;
|
||||
mtd->get_unmapped_area = mapram_unmapped_area;
|
||||
mtd->read = mapram_read;
|
||||
mtd->write = mapram_write;
|
||||
mtd->sync = mapram_nop;
|
||||
|
@ -79,6 +82,20 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allow NOMMU mmap() to directly map the device (if not NULL)
|
||||
* - return the address to which the offset maps
|
||||
* - return -ENOSYS to indicate refusal to do the mapping
|
||||
*/
|
||||
static unsigned long mapram_unmapped_area(struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
return (unsigned long) map->virt + offset;
|
||||
}
|
||||
|
||||
static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
|
|
|
@ -20,6 +20,8 @@ static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch
|
|||
static void maprom_nop (struct mtd_info *);
|
||||
static struct mtd_info *map_rom_probe(struct map_info *map);
|
||||
static int maprom_erase (struct mtd_info *mtd, struct erase_info *info);
|
||||
static unsigned long maprom_unmapped_area(struct mtd_info *, unsigned long,
|
||||
unsigned long, unsigned long);
|
||||
|
||||
static struct mtd_chip_driver maprom_chipdrv = {
|
||||
.probe = map_rom_probe,
|
||||
|
@ -40,6 +42,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
|
|||
mtd->name = map->name;
|
||||
mtd->type = MTD_ROM;
|
||||
mtd->size = map->size;
|
||||
mtd->get_unmapped_area = maprom_unmapped_area;
|
||||
mtd->read = maprom_read;
|
||||
mtd->write = maprom_write;
|
||||
mtd->sync = maprom_nop;
|
||||
|
@ -53,6 +56,20 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allow NOMMU mmap() to directly map the device (if not NULL)
|
||||
* - return the address to which the offset maps
|
||||
* - return -ENOSYS to indicate refusal to do the mapping
|
||||
*/
|
||||
static unsigned long maprom_unmapped_area(struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
return (unsigned long) map->virt + offset;
|
||||
}
|
||||
|
||||
static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
|
|
|
@ -335,7 +335,11 @@ static int parse_cmdline_partitions(struct mtd_info *master,
|
|||
}
|
||||
offset += part->parts[i].size;
|
||||
}
|
||||
*pparts = part->parts;
|
||||
*pparts = kmemdup(part->parts,
|
||||
sizeof(*part->parts) * part->num_parts,
|
||||
GFP_KERNEL);
|
||||
if (!*pparts)
|
||||
return -ENOMEM;
|
||||
return part->num_parts;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -65,12 +65,6 @@
|
|||
#define FAST_READ_DUMMY_BYTE 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
#define mtd_has_partitions() (1)
|
||||
#else
|
||||
#define mtd_has_partitions() (0)
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
struct m25p {
|
||||
|
@ -678,6 +672,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
|
|||
flash->mtd.erasesize = info->sector_size;
|
||||
}
|
||||
|
||||
flash->mtd.dev.parent = &spi->dev;
|
||||
|
||||
dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
|
||||
(long long)flash->mtd.size >> 10);
|
||||
|
||||
|
@ -708,12 +704,13 @@ static int __devinit m25p_probe(struct spi_device *spi)
|
|||
struct mtd_partition *parts = NULL;
|
||||
int nr_parts = 0;
|
||||
|
||||
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||
static const char *part_probes[] = { "cmdlinepart", NULL, };
|
||||
if (mtd_has_cmdlinepart()) {
|
||||
static const char *part_probes[]
|
||||
= { "cmdlinepart", NULL, };
|
||||
|
||||
nr_parts = parse_mtd_partitions(&flash->mtd,
|
||||
part_probes, &parts, 0);
|
||||
#endif
|
||||
nr_parts = parse_mtd_partitions(&flash->mtd,
|
||||
part_probes, &parts, 0);
|
||||
}
|
||||
|
||||
if (nr_parts <= 0 && data && data->parts) {
|
||||
parts = data->parts;
|
||||
|
|
|
@ -98,12 +98,6 @@ struct dataflash {
|
|||
struct mtd_info mtd;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
#define mtd_has_partitions() (1)
|
||||
#else
|
||||
#define mtd_has_partitions() (0)
|
||||
#endif
|
||||
|
||||
/* ......................................................................... */
|
||||
|
||||
/*
|
||||
|
@ -670,6 +664,8 @@ add_dataflash_otp(struct spi_device *spi, char *name,
|
|||
device->write = dataflash_write;
|
||||
device->priv = priv;
|
||||
|
||||
device->dev.parent = &spi->dev;
|
||||
|
||||
if (revision >= 'c')
|
||||
otp_tag = otp_setup(device, revision);
|
||||
|
||||
|
@ -682,11 +678,13 @@ add_dataflash_otp(struct spi_device *spi, char *name,
|
|||
struct mtd_partition *parts;
|
||||
int nr_parts = 0;
|
||||
|
||||
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||
static const char *part_probes[] = { "cmdlinepart", NULL, };
|
||||
if (mtd_has_cmdlinepart()) {
|
||||
static const char *part_probes[]
|
||||
= { "cmdlinepart", NULL, };
|
||||
|
||||
nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);
|
||||
#endif
|
||||
nr_parts = parse_mtd_partitions(device,
|
||||
part_probes, &parts, 0);
|
||||
}
|
||||
|
||||
if (nr_parts <= 0 && pdata && pdata->parts) {
|
||||
parts = pdata->parts;
|
||||
|
|
|
@ -65,6 +65,19 @@ static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
|||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow NOMMU mmap() to directly map the device (if not NULL)
|
||||
* - return the address to which the offset maps
|
||||
* - return -ENOSYS to indicate refusal to do the mapping
|
||||
*/
|
||||
static unsigned long ram_get_unmapped_area(struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags)
|
||||
{
|
||||
return (unsigned long) mtd->priv + offset;
|
||||
}
|
||||
|
||||
static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
|
@ -116,6 +129,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
|
|||
mtd->erase = ram_erase;
|
||||
mtd->point = ram_point;
|
||||
mtd->unpoint = ram_unpoint;
|
||||
mtd->get_unmapped_area = ram_get_unmapped_area;
|
||||
mtd->read = ram_read;
|
||||
mtd->write = ram_write;
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/* Internal MTD definitions
|
||||
*
|
||||
* Copyright © 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* mtdbdi.c
|
||||
*/
|
||||
extern struct backing_dev_info mtd_bdi_unmappable;
|
||||
extern struct backing_dev_info mtd_bdi_ro_mappable;
|
||||
extern struct backing_dev_info mtd_bdi_rw_mappable;
|
|
@ -529,12 +529,6 @@ config MTD_DMV182
|
|||
help
|
||||
Map driver for Dy-4 SVME/DMV-182 board.
|
||||
|
||||
config MTD_SHARP_SL
|
||||
tristate "ROM mapped on Sharp SL Series"
|
||||
depends on ARCH_PXA
|
||||
help
|
||||
This enables access to the flash chip on the Sharp SL Series of PDAs.
|
||||
|
||||
config MTD_INTEL_VR_NOR
|
||||
tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0"
|
||||
depends on PCI
|
||||
|
@ -542,6 +536,12 @@ config MTD_INTEL_VR_NOR
|
|||
Map driver for a NOR flash bank located on the Expansion Bus of the
|
||||
Intel Vermilion Range chipset.
|
||||
|
||||
config MTD_RBTX4939
|
||||
tristate "Map driver for RBTX4939 board"
|
||||
depends on TOSHIBA_RBTX4939 && MTD_CFI && MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
Map driver for NOR flash chips on RBTX4939 board.
|
||||
|
||||
config MTD_PLATRAM
|
||||
tristate "Map driver for platform device RAM (mtd-ram)"
|
||||
select MTD_RAM
|
||||
|
|
|
@ -56,9 +56,9 @@ obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
|
|||
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
|
||||
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
|
||||
obj-$(CONFIG_MTD_DMV182) += dmv182.o
|
||||
obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
|
||||
obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
|
||||
obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
|
||||
obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
|
||||
obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o
|
||||
obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
|
||||
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
|
||||
|
|
|
@ -115,6 +115,8 @@ static int __init omapflash_probe(struct platform_device *pdev)
|
|||
}
|
||||
info->mtd->owner = THIS_MODULE;
|
||||
|
||||
info->mtd->dev.parent = &pdev->dev;
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0);
|
||||
if (err > 0)
|
||||
|
|
|
@ -147,6 +147,7 @@ static int physmap_flash_probe(struct platform_device *dev)
|
|||
devices_found++;
|
||||
}
|
||||
info->mtd[i]->owner = THIS_MODULE;
|
||||
info->mtd[i]->dev.parent = &dev->dev;
|
||||
}
|
||||
|
||||
if (devices_found == 1) {
|
||||
|
|
|
@ -219,6 +219,7 @@ static int __devinit of_flash_probe(struct of_device *dev,
|
|||
goto err_out;
|
||||
}
|
||||
info->mtd->owner = THIS_MODULE;
|
||||
info->mtd->dev.parent = &dev->dev;
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
/* First look for RedBoot table or partitions on the command
|
||||
|
|
|
@ -224,6 +224,7 @@ static int platram_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
info->mtd->owner = THIS_MODULE;
|
||||
info->mtd->dev.parent = &pdev->dev;
|
||||
|
||||
platram_setrw(info, PLATRAM_RW);
|
||||
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* rbtx4939-flash (based on physmap.c)
|
||||
*
|
||||
* This is a simplified physmap driver with map_init callback function.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/txx9/rbtx4939.h>
|
||||
|
||||
struct rbtx4939_flash_info {
|
||||
struct mtd_info *mtd;
|
||||
struct map_info map;
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
int nr_parts;
|
||||
struct mtd_partition *parts;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int rbtx4939_flash_remove(struct platform_device *dev)
|
||||
{
|
||||
struct rbtx4939_flash_info *info;
|
||||
|
||||
info = platform_get_drvdata(dev);
|
||||
if (!info)
|
||||
return 0;
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
if (info->mtd) {
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
struct rbtx4939_flash_data *pdata = dev->dev.platform_data;
|
||||
|
||||
if (info->nr_parts) {
|
||||
del_mtd_partitions(info->mtd);
|
||||
kfree(info->parts);
|
||||
} else if (pdata->nr_parts)
|
||||
del_mtd_partitions(info->mtd);
|
||||
else
|
||||
del_mtd_device(info->mtd);
|
||||
#else
|
||||
del_mtd_device(info->mtd);
|
||||
#endif
|
||||
map_destroy(info->mtd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
static const char *part_probe_types[] = { "cmdlinepart", NULL };
|
||||
#endif
|
||||
|
||||
static int rbtx4939_flash_probe(struct platform_device *dev)
|
||||
{
|
||||
struct rbtx4939_flash_data *pdata;
|
||||
struct rbtx4939_flash_info *info;
|
||||
struct resource *res;
|
||||
const char **probe_type;
|
||||
int err = 0;
|
||||
unsigned long size;
|
||||
|
||||
pdata = dev->dev.platform_data;
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
info = devm_kzalloc(&dev->dev, sizeof(struct rbtx4939_flash_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(dev, info);
|
||||
|
||||
size = resource_size(res);
|
||||
pr_notice("rbtx4939 platform flash device: %pR\n", res);
|
||||
|
||||
if (!devm_request_mem_region(&dev->dev, res->start, size,
|
||||
dev_name(&dev->dev)))
|
||||
return -EBUSY;
|
||||
|
||||
info->map.name = dev_name(&dev->dev);
|
||||
info->map.phys = res->start;
|
||||
info->map.size = size;
|
||||
info->map.bankwidth = pdata->width;
|
||||
|
||||
info->map.virt = devm_ioremap(&dev->dev, info->map.phys, size);
|
||||
if (!info->map.virt)
|
||||
return -EBUSY;
|
||||
|
||||
if (pdata->map_init)
|
||||
(*pdata->map_init)(&info->map);
|
||||
else
|
||||
simple_map_init(&info->map);
|
||||
|
||||
probe_type = rom_probe_types;
|
||||
for (; !info->mtd && *probe_type; probe_type++)
|
||||
info->mtd = do_map_probe(*probe_type, &info->map);
|
||||
if (!info->mtd) {
|
||||
dev_err(&dev->dev, "map_probe failed\n");
|
||||
err = -ENXIO;
|
||||
goto err_out;
|
||||
}
|
||||
info->mtd->owner = THIS_MODULE;
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
err = parse_mtd_partitions(info->mtd, part_probe_types,
|
||||
&info->parts, 0);
|
||||
if (err > 0) {
|
||||
add_mtd_partitions(info->mtd, info->parts, err);
|
||||
info->nr_parts = err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdata->nr_parts) {
|
||||
pr_notice("Using rbtx4939 partition information\n");
|
||||
add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
add_mtd_device(info->mtd);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
rbtx4939_flash_remove(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rbtx4939_flash_suspend(struct platform_device *dev,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct rbtx4939_flash_info *info = platform_get_drvdata(dev);
|
||||
|
||||
if (info->mtd->suspend)
|
||||
return info->mtd->suspend(info->mtd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rbtx4939_flash_resume(struct platform_device *dev)
|
||||
{
|
||||
struct rbtx4939_flash_info *info = platform_get_drvdata(dev);
|
||||
|
||||
if (info->mtd->resume)
|
||||
info->mtd->resume(info->mtd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rbtx4939_flash_shutdown(struct platform_device *dev)
|
||||
{
|
||||
struct rbtx4939_flash_info *info = platform_get_drvdata(dev);
|
||||
|
||||
if (info->mtd->suspend && info->mtd->resume)
|
||||
if (info->mtd->suspend(info->mtd) == 0)
|
||||
info->mtd->resume(info->mtd);
|
||||
}
|
||||
#else
|
||||
#define rbtx4939_flash_suspend NULL
|
||||
#define rbtx4939_flash_resume NULL
|
||||
#define rbtx4939_flash_shutdown NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver rbtx4939_flash_driver = {
|
||||
.probe = rbtx4939_flash_probe,
|
||||
.remove = rbtx4939_flash_remove,
|
||||
.suspend = rbtx4939_flash_suspend,
|
||||
.resume = rbtx4939_flash_resume,
|
||||
.shutdown = rbtx4939_flash_shutdown,
|
||||
.driver = {
|
||||
.name = "rbtx4939-flash",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rbtx4939_flash_init(void)
|
||||
{
|
||||
return platform_driver_register(&rbtx4939_flash_driver);
|
||||
}
|
||||
|
||||
static void __exit rbtx4939_flash_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rbtx4939_flash_driver);
|
||||
}
|
||||
|
||||
module_init(rbtx4939_flash_init);
|
||||
module_exit(rbtx4939_flash_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("RBTX4939 MTD map driver");
|
||||
MODULE_ALIAS("platform:rbtx4939-flash");
|
|
@ -351,7 +351,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
|
|||
|
||||
static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
|
||||
|
||||
static int __init sa1100_mtd_probe(struct platform_device *pdev)
|
||||
static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct flash_platform_data *plat = pdev->dev.platform_data;
|
||||
struct mtd_partition *parts;
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* sharpsl-flash.c
|
||||
*
|
||||
* Copyright (C) 2001 Lineo Japan, Inc.
|
||||
* Copyright (C) 2002 SHARP
|
||||
*
|
||||
* based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
|
||||
* Handle mapping of the flash on the RPX Lite and CLLF boards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#define WINDOW_ADDR 0x00000000
|
||||
#define WINDOW_SIZE 0x00800000
|
||||
#define BANK_WIDTH 2
|
||||
|
||||
static struct mtd_info *mymtd;
|
||||
|
||||
struct map_info sharpsl_map = {
|
||||
.name = "sharpsl-flash",
|
||||
.size = WINDOW_SIZE,
|
||||
.bankwidth = BANK_WIDTH,
|
||||
.phys = WINDOW_ADDR
|
||||
};
|
||||
|
||||
static struct mtd_partition sharpsl_partitions[1] = {
|
||||
{
|
||||
name: "Boot PROM Filesystem",
|
||||
}
|
||||
};
|
||||
|
||||
static int __init init_sharpsl(void)
|
||||
{
|
||||
struct mtd_partition *parts;
|
||||
int nb_parts = 0;
|
||||
char *part_type = "static";
|
||||
|
||||
printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n",
|
||||
WINDOW_SIZE, WINDOW_ADDR);
|
||||
sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
|
||||
if (!sharpsl_map.virt) {
|
||||
printk("Failed to ioremap\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
simple_map_init(&sharpsl_map);
|
||||
|
||||
mymtd = do_map_probe("map_rom", &sharpsl_map);
|
||||
if (!mymtd) {
|
||||
iounmap(sharpsl_map.virt);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
mymtd->owner = THIS_MODULE;
|
||||
|
||||
if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky()
|
||||
|| machine_is_poodle()) {
|
||||
sharpsl_partitions[0].size=0x006d0000;
|
||||
sharpsl_partitions[0].offset=0x00120000;
|
||||
} else if (machine_is_tosa()) {
|
||||
sharpsl_partitions[0].size=0x006a0000;
|
||||
sharpsl_partitions[0].offset=0x00160000;
|
||||
} else if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi()) {
|
||||
sharpsl_partitions[0].size=0x006b0000;
|
||||
sharpsl_partitions[0].offset=0x00140000;
|
||||
} else {
|
||||
map_destroy(mymtd);
|
||||
iounmap(sharpsl_map.virt);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
parts = sharpsl_partitions;
|
||||
nb_parts = ARRAY_SIZE(sharpsl_partitions);
|
||||
|
||||
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
|
||||
add_mtd_partitions(mymtd, parts, nb_parts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_sharpsl(void)
|
||||
{
|
||||
if (mymtd) {
|
||||
del_mtd_partitions(mymtd);
|
||||
map_destroy(mymtd);
|
||||
}
|
||||
if (sharpsl_map.virt) {
|
||||
iounmap(sharpsl_map.virt);
|
||||
sharpsl_map.virt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
module_init(init_sharpsl);
|
||||
module_exit(cleanup_sharpsl);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("SHARP (Original: Arnold Christensen <AKC@pel.dk>)");
|
||||
MODULE_DESCRIPTION("MTD map driver for SHARP SL series");
|
|
@ -286,6 +286,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
|
|||
gd->private_data = new;
|
||||
new->blkcore_priv = gd;
|
||||
gd->queue = tr->blkcore_priv->rq;
|
||||
gd->driverfs_dev = new->mtd->dev.parent;
|
||||
|
||||
if (new->readonly)
|
||||
set_disk_ro(gd, 1);
|
||||
|
@ -382,11 +383,12 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
|||
tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
|
||||
"%sd", tr->name);
|
||||
if (IS_ERR(tr->blkcore_priv->thread)) {
|
||||
int ret = PTR_ERR(tr->blkcore_priv->thread);
|
||||
blk_cleanup_queue(tr->blkcore_priv->rq);
|
||||
unregister_blkdev(tr->major, tr->name);
|
||||
kfree(tr->blkcore_priv);
|
||||
mutex_unlock(&mtd_table_mutex);
|
||||
return PTR_ERR(tr->blkcore_priv->thread);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&tr->devs);
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* MTD backing device capabilities
|
||||
*
|
||||
* Copyright © 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* backing device capabilities for non-mappable devices (such as NAND flash)
|
||||
* - permits private mappings, copies are taken of the data
|
||||
*/
|
||||
struct backing_dev_info mtd_bdi_unmappable = {
|
||||
.capabilities = BDI_CAP_MAP_COPY,
|
||||
};
|
||||
|
||||
/*
|
||||
* backing device capabilities for R/O mappable devices (such as ROM)
|
||||
* - permits private mappings, copies are taken of the data
|
||||
* - permits non-writable shared mappings
|
||||
*/
|
||||
struct backing_dev_info mtd_bdi_ro_mappable = {
|
||||
.capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
|
||||
BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
|
||||
};
|
||||
|
||||
/*
|
||||
* backing device capabilities for writable mappable devices (such as RAM)
|
||||
* - permits private mappings, copies are taken of the data
|
||||
* - permits non-writable shared mappings
|
||||
*/
|
||||
struct backing_dev_info mtd_bdi_rw_mappable = {
|
||||
.capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
|
||||
BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
|
||||
BDI_CAP_WRITE_MAP),
|
||||
};
|
|
@ -13,39 +13,13 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/backing-dev.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/compatmac.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static struct class *mtd_class;
|
||||
|
||||
static void mtd_notify_add(struct mtd_info* mtd)
|
||||
{
|
||||
if (!mtd)
|
||||
return;
|
||||
|
||||
device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
|
||||
NULL, "mtd%d", mtd->index);
|
||||
|
||||
device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
|
||||
NULL, "mtd%dro", mtd->index);
|
||||
}
|
||||
|
||||
static void mtd_notify_remove(struct mtd_info* mtd)
|
||||
{
|
||||
if (!mtd)
|
||||
return;
|
||||
|
||||
device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
|
||||
device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
|
||||
}
|
||||
|
||||
static struct mtd_notifier notifier = {
|
||||
.add = mtd_notify_add,
|
||||
.remove = mtd_notify_remove,
|
||||
};
|
||||
|
||||
/*
|
||||
* Data structure to hold the pointer to the mtd device as well
|
||||
|
@ -107,12 +81,15 @@ static int mtd_open(struct inode *inode, struct file *file)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (MTD_ABSENT == mtd->type) {
|
||||
if (mtd->type == MTD_ABSENT) {
|
||||
put_mtd_device(mtd);
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mtd->backing_dev_info)
|
||||
file->f_mapping->backing_dev_info = mtd->backing_dev_info;
|
||||
|
||||
/* You can't open it RW if it's not a writeable device */
|
||||
if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
|
||||
put_mtd_device(mtd);
|
||||
|
@ -781,6 +758,59 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
|||
return ret;
|
||||
} /* memory_ioctl */
|
||||
|
||||
/*
|
||||
* try to determine where a shared mapping can be made
|
||||
* - only supported for NOMMU at the moment (MMU can't doesn't copy private
|
||||
* mappings)
|
||||
*/
|
||||
#ifndef CONFIG_MMU
|
||||
static unsigned long mtd_get_unmapped_area(struct file *file,
|
||||
unsigned long addr,
|
||||
unsigned long len,
|
||||
unsigned long pgoff,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct mtd_file_info *mfi = file->private_data;
|
||||
struct mtd_info *mtd = mfi->mtd;
|
||||
|
||||
if (mtd->get_unmapped_area) {
|
||||
unsigned long offset;
|
||||
|
||||
if (addr != 0)
|
||||
return (unsigned long) -EINVAL;
|
||||
|
||||
if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT))
|
||||
return (unsigned long) -EINVAL;
|
||||
|
||||
offset = pgoff << PAGE_SHIFT;
|
||||
if (offset > mtd->size - len)
|
||||
return (unsigned long) -EINVAL;
|
||||
|
||||
return mtd->get_unmapped_area(mtd, len, offset, flags);
|
||||
}
|
||||
|
||||
/* can't map directly */
|
||||
return (unsigned long) -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* set up a mapping for shared memory segments
|
||||
*/
|
||||
static int mtd_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
#ifdef CONFIG_MMU
|
||||
struct mtd_file_info *mfi = file->private_data;
|
||||
struct mtd_info *mtd = mfi->mtd;
|
||||
|
||||
if (mtd->type == MTD_RAM || mtd->type == MTD_ROM)
|
||||
return 0;
|
||||
return -ENOSYS;
|
||||
#else
|
||||
return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct file_operations mtd_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = mtd_lseek,
|
||||
|
@ -789,39 +819,36 @@ static const struct file_operations mtd_fops = {
|
|||
.ioctl = mtd_ioctl,
|
||||
.open = mtd_open,
|
||||
.release = mtd_close,
|
||||
.mmap = mtd_mmap,
|
||||
#ifndef CONFIG_MMU
|
||||
.get_unmapped_area = mtd_get_unmapped_area,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init init_mtdchar(void)
|
||||
{
|
||||
if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
|
||||
int status;
|
||||
|
||||
status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops);
|
||||
if (status < 0) {
|
||||
printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
|
||||
MTD_CHAR_MAJOR);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
mtd_class = class_create(THIS_MODULE, "mtd");
|
||||
|
||||
if (IS_ERR(mtd_class)) {
|
||||
printk(KERN_ERR "Error creating mtd class.\n");
|
||||
unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
|
||||
return PTR_ERR(mtd_class);
|
||||
}
|
||||
|
||||
register_mtd_user(¬ifier);
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit cleanup_mtdchar(void)
|
||||
{
|
||||
unregister_mtd_user(¬ifier);
|
||||
class_destroy(mtd_class);
|
||||
unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
|
||||
}
|
||||
|
||||
module_init(init_mtdchar);
|
||||
module_exit(cleanup_mtdchar);
|
||||
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
|
||||
MODULE_DESCRIPTION("Direct character-device access to MTD devices");
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/backing-dev.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/concat.h>
|
||||
|
@ -683,6 +684,40 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* try to support NOMMU mmaps on concatenated devices
|
||||
* - we don't support subdev spanning as we can't guarantee it'll work
|
||||
*/
|
||||
static unsigned long concat_get_unmapped_area(struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
|
||||
if (offset >= subdev->size) {
|
||||
offset -= subdev->size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we've found the subdev over which the mapping will reside */
|
||||
if (offset + len > subdev->size)
|
||||
return (unsigned long) -EINVAL;
|
||||
|
||||
if (subdev->get_unmapped_area)
|
||||
return subdev->get_unmapped_area(subdev, len, offset,
|
||||
flags);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return (unsigned long) -ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function constructs a virtual MTD device by concatenating
|
||||
* num_devs MTD devices. A pointer to the new device object is
|
||||
|
@ -740,6 +775,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|||
|
||||
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
||||
|
||||
concat->mtd.backing_dev_info = subdev[0]->backing_dev_info;
|
||||
|
||||
concat->subdev[0] = subdev[0];
|
||||
|
||||
for (i = 1; i < num_devs; i++) {
|
||||
|
@ -766,6 +803,15 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|||
concat->mtd.flags |=
|
||||
subdev[i]->flags & MTD_WRITEABLE;
|
||||
}
|
||||
|
||||
/* only permit direct mapping if the BDIs are all the same
|
||||
* - copy-mapping is still permitted
|
||||
*/
|
||||
if (concat->mtd.backing_dev_info !=
|
||||
subdev[i]->backing_dev_info)
|
||||
concat->mtd.backing_dev_info =
|
||||
&default_backing_dev_info;
|
||||
|
||||
concat->mtd.size += subdev[i]->size;
|
||||
concat->mtd.ecc_stats.badblocks +=
|
||||
subdev[i]->ecc_stats.badblocks;
|
||||
|
@ -796,6 +842,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|||
concat->mtd.unlock = concat_unlock;
|
||||
concat->mtd.suspend = concat_suspend;
|
||||
concat->mtd.resume = concat_resume;
|
||||
concat->mtd.get_unmapped_area = concat_get_unmapped_area;
|
||||
|
||||
/*
|
||||
* Combine the erase block size info of the subdevices:
|
||||
|
|
|
@ -19,9 +19,13 @@
|
|||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include "internal.h"
|
||||
|
||||
#include "mtdcore.h"
|
||||
|
||||
|
||||
static struct class *mtd_class;
|
||||
|
||||
/* These are exported solely for the purpose of mtd_blkdevs.c. You
|
||||
should not use them for _anything_ else */
|
||||
DEFINE_MUTEX(mtd_table_mutex);
|
||||
|
@ -32,6 +36,160 @@ EXPORT_SYMBOL_GPL(mtd_table);
|
|||
|
||||
static LIST_HEAD(mtd_notifiers);
|
||||
|
||||
|
||||
#if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE)
|
||||
#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
|
||||
#else
|
||||
#define MTD_DEVT(index) 0
|
||||
#endif
|
||||
|
||||
/* REVISIT once MTD uses the driver model better, whoever allocates
|
||||
* the mtd_info will probably want to use the release() hook...
|
||||
*/
|
||||
static void mtd_release(struct device *dev)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
/* remove /dev/mtdXro node if needed */
|
||||
if (MTD_DEVT(mtd->index))
|
||||
device_destroy(mtd_class, MTD_DEVT(mtd->index) + 1);
|
||||
}
|
||||
|
||||
static ssize_t mtd_type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
char *type;
|
||||
|
||||
switch (mtd->type) {
|
||||
case MTD_ABSENT:
|
||||
type = "absent";
|
||||
break;
|
||||
case MTD_RAM:
|
||||
type = "ram";
|
||||
break;
|
||||
case MTD_ROM:
|
||||
type = "rom";
|
||||
break;
|
||||
case MTD_NORFLASH:
|
||||
type = "nor";
|
||||
break;
|
||||
case MTD_NANDFLASH:
|
||||
type = "nand";
|
||||
break;
|
||||
case MTD_DATAFLASH:
|
||||
type = "dataflash";
|
||||
break;
|
||||
case MTD_UBIVOLUME:
|
||||
type = "ubi";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", type);
|
||||
}
|
||||
static DEVICE_ATTR(type, S_IRUGO, mtd_type_show, NULL);
|
||||
|
||||
static ssize_t mtd_flags_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL);
|
||||
|
||||
static ssize_t mtd_size_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%llu\n",
|
||||
(unsigned long long)mtd->size);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL);
|
||||
|
||||
static ssize_t mtd_erasesize_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL);
|
||||
|
||||
static ssize_t mtd_writesize_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL);
|
||||
|
||||
static ssize_t mtd_oobsize_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
|
||||
|
||||
static ssize_t mtd_numeraseregions_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show,
|
||||
NULL);
|
||||
|
||||
static ssize_t mtd_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mtd_info *mtd = dev_to_mtd(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name);
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
|
||||
|
||||
static struct attribute *mtd_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_size.attr,
|
||||
&dev_attr_erasesize.attr,
|
||||
&dev_attr_writesize.attr,
|
||||
&dev_attr_oobsize.attr,
|
||||
&dev_attr_numeraseregions.attr,
|
||||
&dev_attr_name.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct attribute_group mtd_group = {
|
||||
.attrs = mtd_attrs,
|
||||
};
|
||||
|
||||
struct attribute_group *mtd_groups[] = {
|
||||
&mtd_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct device_type mtd_devtype = {
|
||||
.name = "mtd",
|
||||
.groups = mtd_groups,
|
||||
.release = mtd_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* add_mtd_device - register an MTD device
|
||||
* @mtd: pointer to new MTD device info structure
|
||||
|
@ -40,12 +198,27 @@ static LIST_HEAD(mtd_notifiers);
|
|||
* notify each currently active MTD 'user' of its arrival. Returns
|
||||
* zero on success or 1 on failure, which currently will only happen
|
||||
* if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16)
|
||||
* or there's a sysfs error.
|
||||
*/
|
||||
|
||||
int add_mtd_device(struct mtd_info *mtd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mtd->backing_dev_info) {
|
||||
switch (mtd->type) {
|
||||
case MTD_RAM:
|
||||
mtd->backing_dev_info = &mtd_bdi_rw_mappable;
|
||||
break;
|
||||
case MTD_ROM:
|
||||
mtd->backing_dev_info = &mtd_bdi_ro_mappable;
|
||||
break;
|
||||
default:
|
||||
mtd->backing_dev_info = &mtd_bdi_unmappable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(mtd->writesize == 0);
|
||||
mutex_lock(&mtd_table_mutex);
|
||||
|
||||
|
@ -80,6 +253,23 @@ int add_mtd_device(struct mtd_info *mtd)
|
|||
mtd->name);
|
||||
}
|
||||
|
||||
/* Caller should have set dev.parent to match the
|
||||
* physical device.
|
||||
*/
|
||||
mtd->dev.type = &mtd_devtype;
|
||||
mtd->dev.class = mtd_class;
|
||||
mtd->dev.devt = MTD_DEVT(i);
|
||||
dev_set_name(&mtd->dev, "mtd%d", i);
|
||||
if (device_register(&mtd->dev) != 0) {
|
||||
mtd_table[i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MTD_DEVT(i))
|
||||
device_create(mtd_class, mtd->dev.parent,
|
||||
MTD_DEVT(i) + 1,
|
||||
NULL, "mtd%dro", i);
|
||||
|
||||
DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
|
||||
/* No need to get a refcount on the module containing
|
||||
the notifier, since we hold the mtd_table_mutex */
|
||||
|
@ -124,6 +314,8 @@ int del_mtd_device (struct mtd_info *mtd)
|
|||
} else {
|
||||
struct mtd_notifier *not;
|
||||
|
||||
device_unregister(&mtd->dev);
|
||||
|
||||
/* No need to get a refcount on the module containing
|
||||
the notifier, since we hold the mtd_table_mutex */
|
||||
list_for_each_entry(not, &mtd_notifiers, list)
|
||||
|
@ -393,28 +585,38 @@ done:
|
|||
return ((count < begin+len-off) ? count : begin+len-off);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
/*====================================================================*/
|
||||
/* Init code */
|
||||
|
||||
static int __init init_mtd(void)
|
||||
{
|
||||
mtd_class = class_create(THIS_MODULE, "mtd");
|
||||
|
||||
if (IS_ERR(mtd_class)) {
|
||||
pr_err("Error creating mtd class.\n");
|
||||
return PTR_ERR(mtd_class);
|
||||
}
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
|
||||
proc_mtd->read_proc = mtd_read_proc;
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_mtd(void)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (proc_mtd)
|
||||
remove_proc_entry( "mtd", NULL);
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
class_destroy(mtd_class);
|
||||
}
|
||||
|
||||
module_init(init_mtd);
|
||||
module_exit(cleanup_mtd);
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
|
||||
MODULE_DESCRIPTION("Core MTD registration and access routines");
|
||||
|
|
|
@ -44,6 +44,7 @@ static struct mtdoops_context {
|
|||
int oops_pages;
|
||||
int nextpage;
|
||||
int nextcount;
|
||||
char *name;
|
||||
|
||||
void *oops_buf;
|
||||
|
||||
|
@ -273,6 +274,9 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
|
|||
{
|
||||
struct mtdoops_context *cxt = &oops_cxt;
|
||||
|
||||
if (cxt->name && !strcmp(mtd->name, cxt->name))
|
||||
cxt->mtd_index = mtd->index;
|
||||
|
||||
if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
|
||||
return;
|
||||
|
||||
|
@ -357,8 +361,10 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
|
|||
spin_lock_irqsave(&cxt->writecount_lock, flags);
|
||||
|
||||
/* Check ready status didn't change whilst waiting for the lock */
|
||||
if (!cxt->ready)
|
||||
if (!cxt->ready) {
|
||||
spin_unlock_irqrestore(&cxt->writecount_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cxt->writecount == 0) {
|
||||
u32 *stamp = cxt->oops_buf;
|
||||
|
@ -383,8 +389,12 @@ static int __init mtdoops_console_setup(struct console *co, char *options)
|
|||
{
|
||||
struct mtdoops_context *cxt = co->data;
|
||||
|
||||
if (cxt->mtd_index != -1)
|
||||
if (cxt->mtd_index != -1 || cxt->name)
|
||||
return -EBUSY;
|
||||
if (options) {
|
||||
cxt->name = kstrdup(options, GFP_KERNEL);
|
||||
return 0;
|
||||
}
|
||||
if (co->index == -1)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -412,6 +422,7 @@ static int __init mtdoops_console_init(void)
|
|||
|
||||
cxt->mtd_index = -1;
|
||||
cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
|
||||
spin_lock_init(&cxt->writecount_lock);
|
||||
|
||||
if (!cxt->oops_buf) {
|
||||
printk(KERN_ERR "Failed to allocate mtdoops buffer workspace\n");
|
||||
|
@ -432,6 +443,7 @@ static void __exit mtdoops_console_exit(void)
|
|||
|
||||
unregister_mtd_user(&mtdoops_notifier);
|
||||
unregister_console(&mtdoops_console);
|
||||
kfree(cxt->name);
|
||||
vfree(cxt->oops_buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,11 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
struct mtd_ecc_stats stats;
|
||||
int res;
|
||||
|
||||
stats = part->master->ecc_stats;
|
||||
|
||||
if (from >= mtd->size)
|
||||
len = 0;
|
||||
else if (from + len > mtd->size)
|
||||
|
@ -58,9 +61,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||
len, retlen, buf);
|
||||
if (unlikely(res)) {
|
||||
if (res == -EUCLEAN)
|
||||
mtd->ecc_stats.corrected++;
|
||||
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
||||
if (res == -EBADMSG)
|
||||
mtd->ecc_stats.failed++;
|
||||
mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -84,6 +87,18 @@ static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
|||
part->master->unpoint(part->master, from + part->offset, len);
|
||||
}
|
||||
|
||||
static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
|
||||
offset += part->offset;
|
||||
return part->master->get_unmapped_area(part->master, len, offset,
|
||||
flags);
|
||||
}
|
||||
|
||||
static int part_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
|
@ -342,6 +357,12 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
|
|||
|
||||
slave->mtd.name = part->name;
|
||||
slave->mtd.owner = master->owner;
|
||||
slave->mtd.backing_dev_info = master->backing_dev_info;
|
||||
|
||||
/* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
|
||||
* to have the same data be in two different partitions.
|
||||
*/
|
||||
slave->mtd.dev.parent = master->dev.parent;
|
||||
|
||||
slave->mtd.read = part_read;
|
||||
slave->mtd.write = part_write;
|
||||
|
@ -354,6 +375,8 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
|
|||
slave->mtd.unpoint = part_unpoint;
|
||||
}
|
||||
|
||||
if (master->get_unmapped_area)
|
||||
slave->mtd.get_unmapped_area = part_get_unmapped_area;
|
||||
if (master->read_oob)
|
||||
slave->mtd.read_oob = part_read_oob;
|
||||
if (master->write_oob)
|
||||
|
@ -493,7 +516,9 @@ out_register:
|
|||
* This function, given a master MTD object and a partition table, creates
|
||||
* and registers slave MTD objects which are bound to the master according to
|
||||
* the partition definitions.
|
||||
* (Q: should we register the master MTD object as well?)
|
||||
*
|
||||
* We don't register the master, or expect the caller to have done so,
|
||||
* for reasons of data integrity.
|
||||
*/
|
||||
|
||||
int add_mtd_partitions(struct mtd_info *master,
|
||||
|
|
|
@ -334,7 +334,7 @@ config MTD_NAND_ATMEL_ECC_NONE
|
|||
endchoice
|
||||
|
||||
config MTD_NAND_PXA3xx
|
||||
bool "Support for NAND flash devices on PXA3xx"
|
||||
tristate "Support for NAND flash devices on PXA3xx"
|
||||
depends on MTD_NAND && PXA3xx
|
||||
help
|
||||
This enables the driver for the NAND flash device found on
|
||||
|
@ -427,4 +427,23 @@ config MTD_NAND_SH_FLCTL
|
|||
Several Renesas SuperH CPU has FLCTL. This option enables support
|
||||
for NAND Flash using FLCTL. This driver support SH7723.
|
||||
|
||||
config MTD_NAND_DAVINCI
|
||||
tristate "Support NAND on DaVinci SoC"
|
||||
depends on ARCH_DAVINCI
|
||||
help
|
||||
Enable the driver for NAND flash chips on Texas Instruments
|
||||
DaVinci processors.
|
||||
|
||||
config MTD_NAND_TXX9NDFMC
|
||||
tristate "NAND Flash support for TXx9 SoC"
|
||||
depends on SOC_TX4938 || SOC_TX4939
|
||||
help
|
||||
This enables the NAND flash controller on the TXx9 SoCs.
|
||||
|
||||
config MTD_NAND_SOCRATES
|
||||
tristate "Support for NAND on Socrates board"
|
||||
depends on MTD_NAND && SOCRATES
|
||||
help
|
||||
Enables support for NAND Flash chips wired onto Socrates board.
|
||||
|
||||
endif # MTD_NAND
|
||||
|
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
|
|||
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
|
||||
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
|
||||
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
|
||||
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
|
||||
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
|
||||
|
@ -36,5 +37,7 @@ obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
|
|||
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
|
||||
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
|
||||
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
|
||||
|
||||
nand-objs := nand_base.o nand_bbt.o
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче