diff --git a/[refs] b/[refs]
index bbab38533c30..a78247b1a982 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: 37969581301e50872a1ae84dc73962b5f7ee6b76
+refs/heads/master: 290647b46e4d8c9bd9e89daa19b29ff71e14e4af
diff --git a/trunk/Documentation/00-INDEX b/trunk/Documentation/00-INDEX
index d273b557a934..40ac7759c3bb 100644
--- a/trunk/Documentation/00-INDEX
+++ b/trunk/Documentation/00-INDEX
@@ -126,16 +126,18 @@ devices.txt
- plain ASCII listing of all the nodes in /dev/ with major minor #'s.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
+dnotify.txt
+ - info about directory notification in Linux.
dontdiff
- file containing a list of files that should never be diff'ed.
driver-model/
- directory with info about Linux driver model.
+drivers/
+ - directory with driver documentation (currently only EDAC).
dvb/
- info on Linux Digital Video Broadcast (DVB) subsystem.
early-userspace/
- info about initramfs, klibc, and userspace early during boot.
-edac.txt
- - information on EDAC - Error Detection And Correction
eisa.txt
- info on EISA bus support.
exception.txt
@@ -332,8 +334,20 @@ rtc.txt
- notes on how to use the Real Time Clock (aka CMOS clock) driver.
s390/
- directory with info on using Linux on the IBM S390.
-scheduler/
- - directory with info on the scheduler.
+sched-arch.txt
+ - CPU Scheduler implementation hints for architecture specific code.
+sched-coding.txt
+ - reference for various scheduler-related methods in the O(1) scheduler.
+sched-design.txt
+ - goals, design and implementation of the Linux O(1) scheduler.
+sched-design-CFS.txt
+ - goals, design and implementation of the Complete Fair Scheduler.
+sched-domains.txt
+ - information on scheduling domains.
+sched-nice-design.txt
+ - How and why the scheduler's nice levels are implemented.
+sched-stats.txt
+ - information on schedstats (Linux Scheduler Statistics).
scsi/
- directory with info on Linux scsi support.
serial/
@@ -346,6 +360,8 @@ sgi-visws.txt
- short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
+sharedsubtree.txt
+ - a description of shared subtrees for namespaces.
smart-config.txt
- description of the Smart Config makefile feature.
sony-laptop.txt
diff --git a/trunk/Documentation/ABI/testing/sysfs-kernel-uids b/trunk/Documentation/ABI/testing/sysfs-kernel-uids
index 28f14695a852..648d65dbc0e7 100644
--- a/trunk/Documentation/ABI/testing/sysfs-kernel-uids
+++ b/trunk/Documentation/ABI/testing/sysfs-kernel-uids
@@ -11,4 +11,4 @@ Description:
example would be, if User A has shares = 1024 and user
B has shares = 2048, User B will get twice the CPU
bandwidth user A will. For more details refer
- Documentation/scheduler/sched-design-CFS.txt
+ Documentation/sched-design-CFS.txt
diff --git a/trunk/Documentation/DocBook/genericirq.tmpl b/trunk/Documentation/DocBook/genericirq.tmpl
index 3a882d9a90a9..4215f69ce7e6 100644
--- a/trunk/Documentation/DocBook/genericirq.tmpl
+++ b/trunk/Documentation/DocBook/genericirq.tmpl
@@ -172,7 +172,7 @@
Chiplevel hardware encapsulation
-
+
Interrupt control flow
Each interrupt is described by an interrupt descriptor structure
@@ -190,7 +190,7 @@
referenced by the assigned chip descriptor structure.
-
+
Highlevel Driver API
The highlevel Driver API consists of following functions:
@@ -210,7 +210,7 @@
See the autogenerated function documentation for details.
-
+
Highlevel IRQ flow handlers
The generic layer provides a set of pre-defined irq-flow methods:
@@ -224,9 +224,9 @@
specific) are assigned to specific interrupts by the architecture
either during bootup or during device initialization.
-
+
Default flow implementations
-
+
Helper functions
The helper functions call the chip primitives and
@@ -267,9 +267,9 @@ noop(irq)
-
+
Default flow handler implementations
-
+
Default Level IRQ flow handler
handle_level_irq provides a generic implementation
@@ -284,7 +284,7 @@ desc->chip->end();
-
+
Default Edge IRQ flow handler
handle_edge_irq provides a generic implementation
@@ -311,7 +311,7 @@ desc->chip->end();
-
+
Default simple IRQ flow handler
handle_simple_irq provides a generic implementation
@@ -328,7 +328,7 @@ handle_IRQ_event(desc->action);
-
+
Default per CPU flow handler
handle_percpu_irq provides a generic implementation
@@ -349,7 +349,7 @@ desc->chip->end();
-
+
Quirks and optimizations
The generic functions are intended for 'clean' architectures and chips,
@@ -358,7 +358,7 @@ desc->chip->end();
overriding the highlevel irq-flow handler.
-
+
Delayed interrupt disable
This per interrupt selectable feature, which was introduced by Russell
@@ -380,7 +380,7 @@ desc->chip->end();
-
+
Chiplevel hardware encapsulation
The chip level hardware descriptor structure irq_chip
diff --git a/trunk/Documentation/DocBook/lsm.tmpl b/trunk/Documentation/DocBook/lsm.tmpl
index fe7664ce9667..f63822195871 100644
--- a/trunk/Documentation/DocBook/lsm.tmpl
+++ b/trunk/Documentation/DocBook/lsm.tmpl
@@ -33,7 +33,7 @@
-Introduction
+Introduction
In March 2001, the National Security Agency (NSA) gave a presentation
diff --git a/trunk/Documentation/DocBook/mtdnand.tmpl b/trunk/Documentation/DocBook/mtdnand.tmpl
index 8e145857fc9d..957cf5c26831 100644
--- a/trunk/Documentation/DocBook/mtdnand.tmpl
+++ b/trunk/Documentation/DocBook/mtdnand.tmpl
@@ -80,7 +80,7 @@
struct member has a short description which is marked with an [XXX] identifier.
The following chapters explain the meaning of those identifiers.
-
+
Function identifiers [XXX]
The functions are marked with [XXX] identifiers in the short
@@ -115,7 +115,7 @@
-
+
Struct member identifiers [XXX]
The struct members are marked with [XXX] identifiers in the
@@ -159,7 +159,7 @@
basic functions and fill out some really board dependent
members in the nand chip description structure.
-
+
Basic defines
At least you have to provide a mtd structure and
@@ -185,7 +185,7 @@ static struct nand_chip board_chip;
static unsigned long baseaddr;
-
+
Partition defines
If you want to divide your device into partitions, then
@@ -204,7 +204,7 @@ static struct mtd_partition partition_info[] = {
};
-
+
Hardware control function
The hardware control function provides access to the
@@ -246,7 +246,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
}
-
+
Device ready function
If the hardware interface has the ready busy pin of the NAND chip connected to a
@@ -257,7 +257,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
the function must not be defined and the function pointer this->dev_ready is set to NULL.
-
+
Init function
The init function allocates memory and sets up all the board
@@ -325,7 +325,7 @@ out:
module_init(board_init);
-
+
Exit function
The exit function is only neccecary if the driver is
@@ -359,7 +359,7 @@ module_exit(board_cleanup);
driver. For a list of functions which can be overridden by the board
driver see the documentation of the nand_chip structure.
-
+
Multiple chip control
The nand driver can control chip arrays. Therefor the
@@ -419,9 +419,9 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
}
-
+
Hardware ECC support
-
+
Functions and constants
The nand driver supports three different types of
@@ -475,7 +475,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
-
+
Hardware ECC with syndrome calculation
Many hardware ECC implementations provide Reed-Solomon
@@ -500,7 +500,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
-
+
Bad block table support
Most NAND chips mark the bad blocks at a defined
@@ -552,7 +552,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
allows faster access than always checking the
bad block information on the flash chip itself.
-
+
Flash based tables
It may be desired or neccecary to keep a bad block table in FLASH.
@@ -587,7 +587,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
-
+
User defined tables
User defined tables are created by filling out a
@@ -676,7 +676,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
-
+
Spare area (auto)placement
The nand driver implements different possibilities for
@@ -730,7 +730,7 @@ struct nand_oobinfo {
-
+
Placement defined by fs driver
The calling function provides a pointer to a nand_oobinfo
@@ -760,7 +760,7 @@ struct nand_oobinfo {
done according to the given scheme in the nand_oobinfo structure.
-
+
Automatic placement
Automatic placement uses the built in defaults to place the
@@ -774,7 +774,7 @@ struct nand_oobinfo {
done according to the default builtin scheme.
-
+
User space placement selection
All non ecc functions like mtd->read and mtd->write use an internal
@@ -789,9 +789,9 @@ struct nand_oobinfo {
-
+
Spare area autoplacement default schemes
-
+
256 byte pagesize
@@ -843,7 +843,7 @@ pages this byte is reserved
-
+
512 byte pagesize
@@ -906,7 +906,7 @@ in this page
-
+
2048 byte pagesize
@@ -1126,9 +1126,9 @@ in this page
This chapter describes the constants which might be relevant for a driver developer.
-
+
Chip option constants
-
+
Constants for chip id table
These constants are defined in nand.h. They are ored together to describe
@@ -1153,7 +1153,7 @@ in this page
-
+
Constants for runtime options
These constants are defined in nand.h. They are ored together to describe
@@ -1171,7 +1171,7 @@ in this page
-
+
ECC selection constants
Use these constants to select the ECC algorithm.
@@ -1192,7 +1192,7 @@ in this page
-
+
Hardware control related constants
These constants describe the requested hardware access function when
@@ -1218,7 +1218,7 @@ in this page
-
+
Bad block table related constants
These constants describe the options used for bad block
diff --git a/trunk/Documentation/DocBook/procfs-guide.tmpl b/trunk/Documentation/DocBook/procfs-guide.tmpl
index 1fd6a1ec7591..2de84dc195a8 100644
--- a/trunk/Documentation/DocBook/procfs-guide.tmpl
+++ b/trunk/Documentation/DocBook/procfs-guide.tmpl
@@ -85,7 +85,7 @@
-
+
Preface
@@ -230,7 +230,7 @@
-
+
Creating a symlink
@@ -254,7 +254,7 @@
-
+
Creating a directory
@@ -274,7 +274,7 @@
-
+
Removing an entry
@@ -340,7 +340,7 @@ entry->write_proc = write_proc_foo;
-
+
Reading data
@@ -448,7 +448,7 @@ entry->write_proc = write_proc_foo;
-
+
Writing data
@@ -579,7 +579,7 @@ int foo_read_func(char *page, char **start, off_t off,
-
+
Modules
@@ -599,7 +599,7 @@ entry->owner = THIS_MODULE;
-
+
Mode and ownership
diff --git a/trunk/Documentation/DocBook/rapidio.tmpl b/trunk/Documentation/DocBook/rapidio.tmpl
index b9e143e28c64..a8b88c47e809 100644
--- a/trunk/Documentation/DocBook/rapidio.tmpl
+++ b/trunk/Documentation/DocBook/rapidio.tmpl
@@ -77,11 +77,11 @@
Known Bugs and Limitations
-
+
Bugs
None. ;)
-
+
Limitations
@@ -100,7 +100,7 @@
on devices, request/map memory region resources,
and manage mailboxes/doorbells.
-
+
Functions
!Iinclude/linux/rio_drv.h
!Edrivers/rapidio/rio-driver.c
@@ -116,23 +116,23 @@
subsystem.
- Structures
+ Structures
!Iinclude/linux/rio.h
- Enumeration and Discovery
+ Enumeration and Discovery
!Idrivers/rapidio/rio-scan.c
- Driver functionality
+ Driver functionality
!Idrivers/rapidio/rio.c
!Idrivers/rapidio/rio-access.c
- Device model support
+ Device model support
!Idrivers/rapidio/rio-driver.c
- Sysfs support
+ Sysfs support
!Idrivers/rapidio/rio-sysfs.c
- PPC32 support
+ PPC32 support
!Iarch/powerpc/kernel/rio.c
!Earch/powerpc/sysdev/fsl_rio.c
!Iarch/powerpc/sysdev/fsl_rio.c
diff --git a/trunk/Documentation/DocBook/videobook.tmpl b/trunk/Documentation/DocBook/videobook.tmpl
index 89817795e668..b3d93ee27693 100644
--- a/trunk/Documentation/DocBook/videobook.tmpl
+++ b/trunk/Documentation/DocBook/videobook.tmpl
@@ -170,7 +170,7 @@ int __init myradio_init(struct video_init *v)
The types available are
- Device Types
+ Device Types
@@ -291,7 +291,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
allows the applications to find out what sort of a card they have found and
to figure out what they want to do about it. The fields in the structure are
- struct video_capability fields
+ struct video_capability fields
@@ -365,7 +365,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
The video_tuner structure has the following fields
- struct video_tuner fields
+ struct video_tuner fields
@@ -398,7 +398,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
- struct video_tuner flags
+ struct video_tuner flags
@@ -421,7 +421,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
- struct video_tuner modes
+ struct video_tuner modes
@@ -572,7 +572,7 @@ static int current_volume=0;
Then we fill in the video_audio structure. This has the following format
- struct video_audio fields
+ struct video_audio fields
@@ -607,7 +607,7 @@ static int current_volume=0;
- struct video_audio flags
+ struct video_audio flags
@@ -625,7 +625,7 @@ static int current_volume=0;
- struct video_audio modes
+ struct video_audio modes
@@ -775,7 +775,7 @@ module_exit(cleanup);
-
+
Video Capture Devices
Video Capture Device Types
@@ -855,7 +855,7 @@ static struct video_device my_camera
We use the extra video capability flags that did not apply to the
radio interface. The video related flags are
- Capture Capabilities
+ Capture Capabilities
@@ -1195,7 +1195,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
inputs to the video card). Our example card has a single camera input. The
fields in the structure are
- struct video_channel fields
+ struct video_channel fields
@@ -1218,7 +1218,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
- struct video_channel flags
+ struct video_channel flags
@@ -1229,7 +1229,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
- struct video_channel types
+ struct video_channel types
@@ -1242,7 +1242,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
- struct video_channel norms
+ struct video_channel norms
@@ -1328,7 +1328,7 @@ static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
for every other pixel in the image. The other common formats the interface
defines are
- Framebuffer Encodings
+ Framebuffer Encodings
@@ -1466,7 +1466,7 @@ static struct video_buffer capture_fb;
display. The video_window structure is used to describe the way the image
should be displayed.
- struct video_window fields
+ struct video_window fields
@@ -1503,7 +1503,7 @@ static struct video_buffer capture_fb;
Each clip is a struct video_clip which has the following fields
- video_clip fields
+ video_clip fields
diff --git a/trunk/Documentation/DocBook/z8530book.tmpl b/trunk/Documentation/DocBook/z8530book.tmpl
index 42c75ba71ba2..a507876447aa 100644
--- a/trunk/Documentation/DocBook/z8530book.tmpl
+++ b/trunk/Documentation/DocBook/z8530book.tmpl
@@ -77,7 +77,7 @@
-
+
Driver Modes
The Z85230 driver layer can drive Z8530, Z85C30 and Z85230 devices
@@ -108,7 +108,7 @@
-
+
Using the Z85230 driver
The Z85230 driver provides the back end interface to your board. To
@@ -174,7 +174,7 @@
-
+
Attaching Network Interfaces
If you wish to use the network interface facilities of the driver,
@@ -216,7 +216,7 @@
-
+
Configuring And Activating The Port
The Z85230 driver provides helper functions and tables to load the
@@ -300,7 +300,7 @@
-
+
Network Layer Functions
The Z8530 layer provides functions to queue packets for
@@ -327,7 +327,7 @@
-
+
Porting The Z8530 Driver
The Z8530 driver is written to be portable. In DMA mode it makes
diff --git a/trunk/Documentation/cgroups.txt b/trunk/Documentation/cgroups.txt
index 42d7c4cb39cd..98a26f81fa75 100644
--- a/trunk/Documentation/cgroups.txt
+++ b/trunk/Documentation/cgroups.txt
@@ -456,7 +456,7 @@ methods are create/destroy. Any others that are null are presumed to
be successful no-ops.
struct cgroup_subsys_state *create(struct cgroup *cont)
-(cgroup_mutex held by caller)
+LL=cgroup_mutex
Called to create a subsystem state object for a cgroup. The
subsystem should allocate its subsystem state object for the passed
@@ -471,19 +471,14 @@ it's the root of the hierarchy) and may be an appropriate place for
initialization code.
void destroy(struct cgroup *cont)
-(cgroup_mutex held by caller)
+LL=cgroup_mutex
-The cgroup system is about to destroy the passed cgroup; the subsystem
-should do any necessary cleanup and free its subsystem state
-object. By the time this method is called, the cgroup has already been
-unlinked from the file system and from the child list of its parent;
-cgroup->parent is still valid. (Note - can also be called for a
-newly-created cgroup if an error occurs after this subsystem's
-create() method has been called for the new cgroup).
+The cgroup system is about to destroy the passed cgroup; the
+subsystem should do any necessary cleanup
int can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
struct task_struct *task)
-(cgroup_mutex held by caller)
+LL=cgroup_mutex
Called prior to moving a task into a cgroup; if the subsystem
returns an error, this will abort the attach operation. If a NULL
@@ -494,20 +489,25 @@ remain valid while the caller holds cgroup_mutex.
void attach(struct cgroup_subsys *ss, struct cgroup *cont,
struct cgroup *old_cont, struct task_struct *task)
+LL=cgroup_mutex
+
Called after the task has been attached to the cgroup, to allow any
post-attachment activity that requires memory allocations or blocking.
void fork(struct cgroup_subsy *ss, struct task_struct *task)
+LL=callback_mutex, maybe read_lock(tasklist_lock)
Called when a task is forked into a cgroup. Also called during
registration for all existing tasks.
void exit(struct cgroup_subsys *ss, struct task_struct *task)
+LL=callback_mutex
Called during task exit
int populate(struct cgroup_subsys *ss, struct cgroup *cont)
+LL=none
Called after creation of a cgroup to allow a subsystem to populate
the cgroup directory with file entries. The subsystem should make
@@ -524,7 +524,7 @@ example in cpusets, no task may attach before 'cpus' and 'mems' are set
up.
void bind(struct cgroup_subsys *ss, struct cgroup *root)
-(cgroup_mutex held by caller)
+LL=callback_mutex
Called when a cgroup subsystem is rebound to a different hierarchy
and root cgroup. Currently this will only involve movement between
diff --git a/trunk/Documentation/controllers/memory.txt b/trunk/Documentation/controllers/memory.txt
deleted file mode 100644
index b5bbea92a61a..000000000000
--- a/trunk/Documentation/controllers/memory.txt
+++ /dev/null
@@ -1,279 +0,0 @@
-Memory Controller
-
-Salient features
-
-a. Enable control of both RSS (mapped) and Page Cache (unmapped) pages
-b. The infrastructure allows easy addition of other types of memory to control
-c. Provides *zero overhead* for non memory controller users
-d. Provides a double LRU: global memory pressure causes reclaim from the
- global LRU; a cgroup on hitting a limit, reclaims from the per
- cgroup LRU
-
-NOTE: Swap Cache (unmapped) is not accounted now.
-
-Benefits and Purpose of the memory controller
-
-The memory controller isolates the memory behaviour of a group of tasks
-from the rest of the system. The article on LWN [12] mentions some probable
-uses of the memory controller. The memory controller can be used to
-
-a. Isolate an application or a group of applications
- Memory hungry applications can be isolated and limited to a smaller
- amount of memory.
-b. Create a cgroup with limited amount of memory, this can be used
- as a good alternative to booting with mem=XXXX.
-c. Virtualization solutions can control the amount of memory they want
- to assign to a virtual machine instance.
-d. A CD/DVD burner could control the amount of memory used by the
- rest of the system to ensure that burning does not fail due to lack
- of available memory.
-e. There are several other use cases, find one or use the controller just
- for fun (to learn and hack on the VM subsystem).
-
-1. History
-
-The memory controller has a long history. A request for comments for the memory
-controller was posted by Balbir Singh [1]. At the time the RFC was posted
-there were several implementations for memory control. The goal of the
-RFC was to build consensus and agreement for the minimal features required
-for memory control. The first RSS controller was posted by Balbir Singh[2]
-in Feb 2007. Pavel Emelianov [3][4][5] has since posted three versions of the
-RSS controller. At OLS, at the resource management BoF, everyone suggested
-that we handle both page cache and RSS together. Another request was raised
-to allow user space handling of OOM. The current memory controller is
-at version 6; it combines both mapped (RSS) and unmapped Page
-Cache Control [11].
-
-2. Memory Control
-
-Memory is a unique resource in the sense that it is present in a limited
-amount. If a task requires a lot of CPU processing, the task can spread
-its processing over a period of hours, days, months or years, but with
-memory, the same physical memory needs to be reused to accomplish the task.
-
-The memory controller implementation has been divided into phases. These
-are:
-
-1. Memory controller
-2. mlock(2) controller
-3. Kernel user memory accounting and slab control
-4. user mappings length controller
-
-The memory controller is the first controller developed.
-
-2.1. Design
-
-The core of the design is a counter called the res_counter. The res_counter
-tracks the current memory usage and limit of the group of processes associated
-with the controller. Each cgroup has a memory controller specific data
-structure (mem_cgroup) associated with it.
-
-2.2. Accounting
-
- +--------------------+
- | mem_cgroup |
- | (res_counter) |
- +--------------------+
- / ^ \
- / | \
- +---------------+ | +---------------+
- | mm_struct | |.... | mm_struct |
- | | | | |
- +---------------+ | +---------------+
- |
- + --------------+
- |
- +---------------+ +------+--------+
- | page +----------> page_cgroup|
- | | | |
- +---------------+ +---------------+
-
- (Figure 1: Hierarchy of Accounting)
-
-
-Figure 1 shows the important aspects of the controller
-
-1. Accounting happens per cgroup
-2. Each mm_struct knows about which cgroup it belongs to
-3. Each page has a pointer to the page_cgroup, which in turn knows the
- cgroup it belongs to
-
-The accounting is done as follows: mem_cgroup_charge() is invoked to setup
-the necessary data structures and check if the cgroup that is being charged
-is over its limit. If it is then reclaim is invoked on the cgroup.
-More details can be found in the reclaim section of this document.
-If everything goes well, a page meta-data-structure called page_cgroup is
-allocated and associated with the page. This routine also adds the page to
-the per cgroup LRU.
-
-2.2.1 Accounting details
-
-All mapped pages (RSS) and unmapped user pages (Page Cache) are accounted.
-RSS pages are accounted at the time of page_add_*_rmap() unless they've already
-been accounted for earlier. A file page will be accounted for as Page Cache;
-it's mapped into the page tables of a process, duplicate accounting is carefully
-avoided. Page Cache pages are accounted at the time of add_to_page_cache().
-The corresponding routines that remove a page from the page tables or removes
-a page from Page Cache is used to decrement the accounting counters of the
-cgroup.
-
-2.3 Shared Page Accounting
-
-Shared pages are accounted on the basis of the first touch approach. The
-cgroup that first touches a page is accounted for the page. The principle
-behind this approach is that a cgroup that aggressively uses a shared
-page will eventually get charged for it (once it is uncharged from
-the cgroup that brought it in -- this will happen on memory pressure).
-
-2.4 Reclaim
-
-Each cgroup maintains a per cgroup LRU that consists of an active
-and inactive list. When a cgroup goes over its limit, we first try
-to reclaim memory from the cgroup so as to make space for the new
-pages that the cgroup has touched. If the reclaim is unsuccessful,
-an OOM routine is invoked to select and kill the bulkiest task in the
-cgroup.
-
-The reclaim algorithm has not been modified for cgroups, except that
-pages that are selected for reclaiming come from the per cgroup LRU
-list.
-
-2. Locking
-
-The memory controller uses the following hierarchy
-
-1. zone->lru_lock is used for selecting pages to be isolated
-2. mem->per_zone->lru_lock protects the per cgroup LRU (per zone)
-3. lock_page_cgroup() is used to protect page->page_cgroup
-
-3. User Interface
-
-0. Configuration
-
-a. Enable CONFIG_CGROUPS
-b. Enable CONFIG_RESOURCE_COUNTERS
-c. Enable CONFIG_CGROUP_MEM_CONT
-
-1. Prepare the cgroups
-# mkdir -p /cgroups
-# mount -t cgroup none /cgroups -o memory
-
-2. Make the new group and move bash into it
-# mkdir /cgroups/0
-# echo $$ > /cgroups/0/tasks
-
-Since now we're in the 0 cgroup,
-We can alter the memory limit:
-# echo -n 4M > /cgroups/0/memory.limit_in_bytes
-
-NOTE: We can use a suffix (k, K, m, M, g or G) to indicate values in kilo,
-mega or gigabytes.
-
-# cat /cgroups/0/memory.limit_in_bytes
-4194304 Bytes
-
-NOTE: The interface has now changed to display the usage in bytes
-instead of pages
-
-We can check the usage:
-# cat /cgroups/0/memory.usage_in_bytes
-1216512 Bytes
-
-A successful write to this file does not guarantee a successful set of
-this limit to the value written into the file. This can be due to a
-number of factors, such as rounding up to page boundaries or the total
-availability of memory on the system. The user is required to re-read
-this file after a write to guarantee the value committed by the kernel.
-
-# echo -n 1 > memory.limit_in_bytes
-# cat memory.limit_in_bytes
-4096 Bytes
-
-The memory.failcnt field gives the number of times that the cgroup limit was
-exceeded.
-
-The memory.stat file gives accounting information. Now, the number of
-caches, RSS and Active pages/Inactive pages are shown.
-
-The memory.force_empty gives an interface to drop *all* charges by force.
-
-# echo -n 1 > memory.force_empty
-
-will drop all charges in cgroup. Currently, this is maintained for test.
-
-4. Testing
-
-Balbir posted lmbench, AIM9, LTP and vmmstress results [10] and [11].
-Apart from that v6 has been tested with several applications and regular
-daily use. The controller has also been tested on the PPC64, x86_64 and
-UML platforms.
-
-4.1 Troubleshooting
-
-Sometimes a user might find that the application under a cgroup is
-terminated. There are several causes for this:
-
-1. The cgroup limit is too low (just too low to do anything useful)
-2. The user is using anonymous memory and swap is turned off or too low
-
-A sync followed by echo 1 > /proc/sys/vm/drop_caches will help get rid of
-some of the pages cached in the cgroup (page cache pages).
-
-4.2 Task migration
-
-When a task migrates from one cgroup to another, it's charge is not
-carried forward. The pages allocated from the original cgroup still
-remain charged to it, the charge is dropped when the page is freed or
-reclaimed.
-
-4.3 Removing a cgroup
-
-A cgroup can be removed by rmdir, but as discussed in sections 4.1 and 4.2, a
-cgroup might have some charge associated with it, even though all
-tasks have migrated away from it. Such charges are automatically dropped at
-rmdir() if there are no tasks.
-
-4.4 Choosing what to account -- Page Cache (unmapped) vs RSS (mapped)?
-
-The type of memory accounted by the cgroup can be limited to just
-mapped pages by writing "1" to memory.control_type field
-
-echo -n 1 > memory.control_type
-
-5. TODO
-
-1. Add support for accounting huge pages (as a separate controller)
-2. Make per-cgroup scanner reclaim not-shared pages first
-3. Teach controller to account for shared-pages
-4. Start reclamation when the limit is lowered
-5. Start reclamation in the background when the limit is
- not yet hit but the usage is getting closer
-
-Summary
-
-Overall, the memory controller has been a stable controller and has been
-commented and discussed quite extensively in the community.
-
-References
-
-1. Singh, Balbir. RFC: Memory Controller, http://lwn.net/Articles/206697/
-2. Singh, Balbir. Memory Controller (RSS Control),
- http://lwn.net/Articles/222762/
-3. Emelianov, Pavel. Resource controllers based on process cgroups
- http://lkml.org/lkml/2007/3/6/198
-4. Emelianov, Pavel. RSS controller based on process cgroups (v2)
- http://lkml.org/lkml/2007/4/9/74
-5. Emelianov, Pavel. RSS controller based on process cgroups (v3)
- http://lkml.org/lkml/2007/5/30/244
-6. Menage, Paul. Control Groups v10, http://lwn.net/Articles/236032/
-7. Vaidyanathan, Srinivasan, Control Groups: Pagecache accounting and control
- subsystem (v3), http://lwn.net/Articles/235534/
-8. Singh, Balbir. RSS controller V2 test results (lmbench),
- http://lkml.org/lkml/2007/5/17/232
-9. Singh, Balbir. RSS controller V2 AIM9 results
- http://lkml.org/lkml/2007/5/18/1
-10. Singh, Balbir. Memory controller v6 results,
- http://lkml.org/lkml/2007/8/19/36
-11. Singh, Balbir. Memory controller v6, http://lkml.org/lkml/2007/8/17/69
-12. Corbet, Jonathan, Controlling memory use in cgroups,
- http://lwn.net/Articles/243795/
diff --git a/trunk/Documentation/cpusets.txt b/trunk/Documentation/cpusets.txt
index 43db6fe12814..141bef1c8599 100644
--- a/trunk/Documentation/cpusets.txt
+++ b/trunk/Documentation/cpusets.txt
@@ -523,14 +523,21 @@ from one cpuset to another, then the kernel will adjust the tasks
memory placement, as above, the next time that the kernel attempts
to allocate a page of memory for that task.
-If a cpuset has its 'cpus' modified, then each task in that cpuset
-will have its allowed CPU placement changed immediately. Similarly,
-if a tasks pid is written to a cpusets 'tasks' file, in either its
-current cpuset or another cpuset, then its allowed CPU placement is
-changed immediately. If such a task had been bound to some subset
-of its cpuset using the sched_setaffinity() call, the task will be
-allowed to run on any CPU allowed in its new cpuset, negating the
-affect of the prior sched_setaffinity() call.
+If a cpuset has its CPUs modified, then each task using that
+cpuset does _not_ change its behavior automatically. In order to
+minimize the impact on the critical scheduling code in the kernel,
+tasks will continue to use their prior CPU placement until they
+are rebound to their cpuset, by rewriting their pid to the 'tasks'
+file of their cpuset. If a task had been bound to some subset of its
+cpuset using the sched_setaffinity() call, and if any of that subset
+is still allowed in its new cpuset settings, then the task will be
+restricted to the intersection of the CPUs it was allowed on before,
+and its new cpuset CPU placement. If, on the other hand, there is
+no overlap between a tasks prior placement and its new cpuset CPU
+placement, then the task will be allowed to run on any CPU allowed
+in its new cpuset. If a task is moved from one cpuset to another,
+its CPU placement is updated in the same way as if the tasks pid is
+rewritten to the 'tasks' file of its current cpuset.
In summary, the memory placement of a task whose cpuset is changed is
updated by the kernel, on the next allocation of a page for that task,
diff --git a/trunk/Documentation/filesystems/dnotify.txt b/trunk/Documentation/dnotify.txt
similarity index 99%
rename from trunk/Documentation/filesystems/dnotify.txt
rename to trunk/Documentation/dnotify.txt
index 9f5d338ddbb8..6984fca6002a 100644
--- a/trunk/Documentation/filesystems/dnotify.txt
+++ b/trunk/Documentation/dnotify.txt
@@ -69,24 +69,24 @@ Example
#include
#include
#include
-
+
static volatile int event_fd;
-
+
static void handler(int sig, siginfo_t *si, void *data)
{
event_fd = si->si_fd;
}
-
+
int main(void)
{
struct sigaction act;
int fd;
-
+
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN + 1, &act, NULL);
-
+
fd = open(".", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN + 1);
fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
diff --git a/trunk/Documentation/edac.txt b/trunk/Documentation/drivers/edac/edac.txt
similarity index 100%
rename from trunk/Documentation/edac.txt
rename to trunk/Documentation/drivers/edac/edac.txt
diff --git a/trunk/Documentation/email-clients.txt b/trunk/Documentation/email-clients.txt
index 2ebb94d6ed8e..113165b48305 100644
--- a/trunk/Documentation/email-clients.txt
+++ b/trunk/Documentation/email-clients.txt
@@ -170,6 +170,7 @@ Sylpheed (GUI)
- Works well for inlining text (or using attachments).
- Allows use of an external editor.
+- Not good for IMAP.
- Is slow on large folders.
- Won't do TLS SMTP auth over a non-SSL connection.
- Has a helpful ruler bar in the compose window.
diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt
index 17b1659bd3f8..68ce1300a360 100644
--- a/trunk/Documentation/feature-removal-schedule.txt
+++ b/trunk/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,14 @@ be removed from this file.
---------------------------
+What: MXSER
+When: December 2007
+Why: Old mxser driver is obsoleted by the mxser_new. Give it some time yet
+ and remove it.
+Who: Jiri Slaby
+
+---------------------------
+
What: dev->power.power_state
When: July 2007
Why: Broken design for runtime control over driver power states, confusing
diff --git a/trunk/Documentation/filesystems/00-INDEX b/trunk/Documentation/filesystems/00-INDEX
index e68021c08fbd..1de155e2dc36 100644
--- a/trunk/Documentation/filesystems/00-INDEX
+++ b/trunk/Documentation/filesystems/00-INDEX
@@ -32,8 +32,6 @@ directory-locking
- info about the locking scheme used for directory operations.
dlmfs.txt
- info on the userspace interface to the OCFS2 DLM.
-dnotify.txt
- - info about directory notification in Linux.
ecryptfs.txt
- docs on eCryptfs: stacked cryptographic filesystem for Linux.
ext2.txt
@@ -82,8 +80,6 @@ relay.txt
- info on relay, for efficient streaming from kernel to user space.
romfs.txt
- description of the ROMFS filesystem.
-sharedsubtree.txt
- - a description of shared subtrees for namespaces.
smbfs.txt
- info on using filesystems with the SMB protocol (Win 3.11 and NT).
spufs.txt
diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking
index 42d4b30b1045..37c10cba7177 100644
--- a/trunk/Documentation/filesystems/Locking
+++ b/trunk/Documentation/filesystems/Locking
@@ -90,6 +90,7 @@ of the locking scheme for directory operations.
prototypes:
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
+ void (*read_inode) (struct inode *);
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
@@ -113,6 +114,7 @@ locking rules:
BKL s_lock s_umount
alloc_inode: no no no
destroy_inode: no
+read_inode: no (see below)
dirty_inode: no (must not sleep)
write_inode: no
put_inode: no
@@ -131,6 +133,7 @@ show_options: no (vfsmount->sem)
quota_read: no no no (see below)
quota_write: no no no (see below)
+->read_inode() is not a method - it's a callback used in iget().
->remount_fs() will have the s_umount lock if it's already mounted.
When called from get_sb_single, it does NOT have the s_umount lock.
->quota_read() and ->quota_write() functions are both guaranteed to
diff --git a/trunk/Documentation/filesystems/porting b/trunk/Documentation/filesystems/porting
index 92b888d540a6..0f33c77bc14b 100644
--- a/trunk/Documentation/filesystems/porting
+++ b/trunk/Documentation/filesystems/porting
@@ -34,8 +34,8 @@ FOO_I(inode) (see in-tree filesystems for examples).
Make them ->alloc_inode and ->destroy_inode in your super_operations.
-Keep in mind that now you need explicit initialization of private data
-typically between calling iget_locked() and unlocking the inode.
+Keep in mind that now you need explicit initialization of private data -
+typically in ->read_inode() and after getting an inode from new_inode().
At some point that will become mandatory.
@@ -173,10 +173,10 @@ should be a non-blocking function that initializes those parts of a
newly created inode to allow the test function to succeed. 'data' is
passed as an opaque value to both test and set functions.
-When the inode has been created by iget5_locked(), it will be returned with the
-I_NEW flag set and will still be locked. The filesystem then needs to finalize
-the initialization. Once the inode is initialized it must be unlocked by
-calling unlock_new_inode().
+When the inode has been created by iget5_locked(), it will be returned with
+the I_NEW flag set and will still be locked. read_inode has not been
+called so the file system still has to finalize the initialization. Once
+the inode is initialized it must be unlocked by calling unlock_new_inode().
The filesystem is responsible for setting (and possibly testing) i_ino
when appropriate. There is also a simpler iget_locked function that
@@ -184,19 +184,11 @@ just takes the superblock and inode number as arguments and does the
test and set for you.
e.g.
- inode = iget_locked(sb, ino);
- if (inode->i_state & I_NEW) {
- err = read_inode_from_disk(inode);
- if (err < 0) {
- iget_failed(inode);
- return err;
- }
- unlock_new_inode(inode);
- }
-
-Note that if the process of setting up a new inode fails, then iget_failed()
-should be called on the inode to render it dead, and an appropriate error
-should be passed back to the caller.
+ inode = iget_locked(sb, ino);
+ if (inode->i_state & I_NEW) {
+ read_inode_from_disk(inode);
+ unlock_new_inode(inode);
+ }
---
[recommended]
diff --git a/trunk/Documentation/filesystems/vfs.txt b/trunk/Documentation/filesystems/vfs.txt
index bd55038b56f5..9d019d35728f 100644
--- a/trunk/Documentation/filesystems/vfs.txt
+++ b/trunk/Documentation/filesystems/vfs.txt
@@ -203,6 +203,8 @@ struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
+ void (*read_inode) (struct inode *);
+
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
@@ -240,6 +242,15 @@ or bottom half).
->alloc_inode was defined and simply undoes anything done by
->alloc_inode.
+ read_inode: this method is called to read a specific inode from the
+ mounted filesystem. The i_ino member in the struct inode is
+ initialized by the VFS to indicate which inode to read. Other
+ members are filled in by this method.
+
+ You can set this to NULL and use iget5_locked() instead of iget()
+ to read inodes. This is necessary for filesystems for which the
+ inode number is not sufficient to identify an inode.
+
dirty_inode: this method is called by the VFS to mark an inode dirty.
write_inode: this method is called when the VFS needs to write an
@@ -297,9 +308,9 @@ or bottom half).
quota_write: called by the VFS to write to filesystem quota file.
-Whoever sets up the inode is responsible for filling in the "i_op" field. This
-is a pointer to a "struct inode_operations" which describes the methods that
-can be performed on individual inodes.
+The read_inode() method is responsible for filling in the "i_op"
+field. This is a pointer to a "struct inode_operations" which
+describes the methods that can be performed on individual inodes.
The Inode Object
diff --git a/trunk/Documentation/powerpc/booting-without-of.txt b/trunk/Documentation/powerpc/booting-without-of.txt
index 7b4e8a70882c..b5e46efeba84 100644
--- a/trunk/Documentation/powerpc/booting-without-of.txt
+++ b/trunk/Documentation/powerpc/booting-without-of.txt
@@ -57,7 +57,6 @@ Table of Contents
n) 4xx/Axon EMAC ethernet nodes
o) Xilinx IP cores
p) Freescale Synchronous Serial Interface
- q) USB EHCI controllers
VII - Specifying interrupt information for devices
1) interrupts property
@@ -2578,20 +2577,6 @@ platforms are moved over to use the flattened-device-tree model.
Requred properties:
- current-speed : Baud rate of uartlite
- v) Xilinx hwicap
-
- Xilinx hwicap devices provide access to the configuration logic
- of the FPGA through the Internal Configuration Access Port
- (ICAP). The ICAP enables partial reconfiguration of the FPGA,
- readback of the configuration information, and some control over
- 'warm boots' of the FPGA fabric.
-
- Required properties:
- - xlnx,family : The family of the FPGA, necessary since the
- capabilities of the underlying ICAP hardware
- differ between different families. May be
- 'virtex2p', 'virtex4', or 'virtex5'.
-
p) Freescale Synchronous Serial Interface
The SSI is a serial device that communicates with audio codecs. It can
@@ -2790,33 +2775,6 @@ platforms are moved over to use the flattened-device-tree model.
interrupt-parent = < &ipic >;
};
- q) USB EHCI controllers
-
- Required properties:
- - compatible : should be "usb-ehci".
- - reg : should contain at least address and length of the standard EHCI
- register set for the device. Optional platform-dependent registers
- (debug-port or other) can be also specified here, but only after
- definition of standard EHCI registers.
- - interrupts : one EHCI interrupt should be described here.
- If device registers are implemented in big endian mode, the device
- node should have "big-endian-regs" property.
- If controller implementation operates with big endian descriptors,
- "big-endian-desc" property should be specified.
- If both big endian registers and descriptors are used by the controller
- implementation, "big-endian" property can be specified instead of having
- both "big-endian-regs" and "big-endian-desc".
-
- Example (Sequoia 440EPx):
- ehci@e0000300 {
- compatible = "ibm,usb-ehci-440epx", "usb-ehci";
- interrupt-parent = <&UIC0>;
- interrupts = <1a 4>;
- reg = <0 e0000300 90 0 e0000390 70>;
- big-endian;
- };
-
-
More devices will be defined as this spec matures.
VII - Specifying interrupt information for devices
diff --git a/trunk/Documentation/scheduler/sched-arch.txt b/trunk/Documentation/sched-arch.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-arch.txt
rename to trunk/Documentation/sched-arch.txt
diff --git a/trunk/Documentation/scheduler/sched-coding.txt b/trunk/Documentation/sched-coding.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-coding.txt
rename to trunk/Documentation/sched-coding.txt
diff --git a/trunk/Documentation/scheduler/sched-design-CFS.txt b/trunk/Documentation/sched-design-CFS.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-design-CFS.txt
rename to trunk/Documentation/sched-design-CFS.txt
diff --git a/trunk/Documentation/scheduler/sched-design.txt b/trunk/Documentation/sched-design.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-design.txt
rename to trunk/Documentation/sched-design.txt
diff --git a/trunk/Documentation/scheduler/sched-domains.txt b/trunk/Documentation/sched-domains.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-domains.txt
rename to trunk/Documentation/sched-domains.txt
diff --git a/trunk/Documentation/scheduler/sched-nice-design.txt b/trunk/Documentation/sched-nice-design.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-nice-design.txt
rename to trunk/Documentation/sched-nice-design.txt
diff --git a/trunk/Documentation/scheduler/sched-stats.txt b/trunk/Documentation/sched-stats.txt
similarity index 100%
rename from trunk/Documentation/scheduler/sched-stats.txt
rename to trunk/Documentation/sched-stats.txt
diff --git a/trunk/Documentation/scheduler/00-INDEX b/trunk/Documentation/scheduler/00-INDEX
deleted file mode 100644
index b5f5ca069b2d..000000000000
--- a/trunk/Documentation/scheduler/00-INDEX
+++ /dev/null
@@ -1,16 +0,0 @@
-00-INDEX
- - this file.
-sched-arch.txt
- - CPU Scheduler implementation hints for architecture specific code.
-sched-coding.txt
- - reference for various scheduler-related methods in the O(1) scheduler.
-sched-design.txt
- - goals, design and implementation of the Linux O(1) scheduler.
-sched-design-CFS.txt
- - goals, design and implementation of the Complete Fair Scheduler.
-sched-domains.txt
- - information on scheduling domains.
-sched-nice-design.txt
- - How and why the scheduler's nice levels are implemented.
-sched-stats.txt
- - information on schedstats (Linux Scheduler Statistics).
diff --git a/trunk/Documentation/filesystems/sharedsubtree.txt b/trunk/Documentation/sharedsubtree.txt
similarity index 100%
rename from trunk/Documentation/filesystems/sharedsubtree.txt
rename to trunk/Documentation/sharedsubtree.txt
diff --git a/trunk/Documentation/sysctl/vm.txt b/trunk/Documentation/sysctl/vm.txt
index 8a4863c4edd4..24eac1bc735d 100644
--- a/trunk/Documentation/sysctl/vm.txt
+++ b/trunk/Documentation/sysctl/vm.txt
@@ -32,7 +32,6 @@ Currently, these files are in /proc/sys/vm:
- min_unmapped_ratio
- min_slab_ratio
- panic_on_oom
-- oom_dump_tasks
- oom_kill_allocating_task
- mmap_min_address
- numa_zonelist_order
@@ -233,27 +232,6 @@ according to your policy of failover.
=============================================================
-oom_dump_tasks
-
-Enables a system-wide task dump (excluding kernel threads) to be
-produced when the kernel performs an OOM-killing and includes such
-information as pid, uid, tgid, vm size, rss, cpu, oom_adj score, and
-name. This is helpful to determine why the OOM killer was invoked
-and to identify the rogue task that caused it.
-
-If this is set to zero, this information is suppressed. On very
-large systems with thousands of tasks it may not be feasible to dump
-the memory state information for each one. Such systems should not
-be forced to incur a performance penalty in OOM conditions when the
-information may not be desired.
-
-If this is set to non-zero, this information is shown whenever the
-OOM killer actually kills a memory-hogging task.
-
-The default value is 0.
-
-=============================================================
-
oom_kill_allocating_task
This enables or disables killing the OOM-triggering task in
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index a372c86fd07b..0885aa2b095a 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -1371,11 +1371,6 @@ W: http://linuxtv.org/
T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
S: Maintained
-DZ DECSTATION DZ11 SERIAL DRIVER
-P: Maciej W. Rozycki
-M: macro@linux-mips.org
-S: Maintained
-
EATA-DMA SCSI DRIVER
P: Michael Neuffer
L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org
diff --git a/trunk/REPORTING-BUGS b/trunk/REPORTING-BUGS
index ab0c56630a8c..ac02e42a2627 100644
--- a/trunk/REPORTING-BUGS
+++ b/trunk/REPORTING-BUGS
@@ -10,12 +10,11 @@ bug report. This explains what you should do with the "Oops" information
to make it useful to the recipient.
Send the output to the maintainer of the kernel area that seems to
-be involved with the problem, and cc the relevant mailing list. Don't
-worry too much about getting the wrong person. If you are unsure send it
-to the person responsible for the code relevant to what you were doing.
-If it occurs repeatably try and describe how to recreate it. That is
-worth even more than the oops itself. The list of maintainers and
-mailing lists is in the MAINTAINERS file in this directory.
+be involved with the problem. Don't worry too much about getting the
+wrong person. If you are unsure send it to the person responsible for the
+code relevant to what you were doing. If it occurs repeatably try and
+describe how to recreate it. That is worth even more than the oops itself.
+The list of maintainers is in the MAINTAINERS file in this directory.
If it is a security bug, please copy the Security Contact listed
in the MAINTAINERS file. They can help coordinate bugfix and disclosure.
diff --git a/trunk/arch/alpha/kernel/core_irongate.c b/trunk/arch/alpha/kernel/core_irongate.c
index a872078497be..e4a0bcf1d28b 100644
--- a/trunk/arch/alpha/kernel/core_irongate.c
+++ b/trunk/arch/alpha/kernel/core_irongate.c
@@ -241,8 +241,7 @@ albacore_init_arch(void)
size / 1024);
}
#endif
- reserve_bootmem_node(NODE_DATA(0), pci_mem, memtop -
- pci_mem, BOOTMEM_DEFAULT);
+ reserve_bootmem_node(NODE_DATA(0), pci_mem, memtop - pci_mem);
printk("irongate_init_arch: temporarily reserving "
"region %08lx-%08lx for PCI\n", pci_mem, memtop - 1);
}
diff --git a/trunk/arch/alpha/kernel/setup.c b/trunk/arch/alpha/kernel/setup.c
index 74c346625658..beff6297f788 100644
--- a/trunk/arch/alpha/kernel/setup.c
+++ b/trunk/arch/alpha/kernel/setup.c
@@ -428,8 +428,7 @@ setup_memory(void *kernel_end)
}
/* Reserve the bootmap memory. */
- reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size);
printk("reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size));
#ifdef CONFIG_BLK_DEV_INITRD
@@ -447,7 +446,7 @@ setup_memory(void *kernel_end)
phys_to_virt(PFN_PHYS(max_low_pfn)));
} else {
reserve_bootmem(virt_to_phys((void *)initrd_start),
- INITRD_SIZE, BOOTMEM_DEFAULT);
+ INITRD_SIZE);
}
}
#endif /* CONFIG_BLK_DEV_INITRD */
diff --git a/trunk/arch/alpha/mm/numa.c b/trunk/arch/alpha/mm/numa.c
index 10ab7833e83c..e3e3806a6f25 100644
--- a/trunk/arch/alpha/mm/numa.c
+++ b/trunk/arch/alpha/mm/numa.c
@@ -242,8 +242,7 @@ setup_memory_node(int nid, void *kernel_end)
}
/* Reserve the bootmap memory. */
- reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(bootmap_start),
- bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(bootmap_start), bootmap_size);
printk(" reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size));
node_set_online(nid);
@@ -282,7 +281,7 @@ setup_memory(void *kernel_end)
nid = kvaddr_to_nid(initrd_start);
reserve_bootmem_node(NODE_DATA(nid),
virt_to_phys((void *)initrd_start),
- INITRD_SIZE, BOOTMEM_DEFAULT);
+ INITRD_SIZE);
}
}
#endif /* CONFIG_BLK_DEV_INITRD */
diff --git a/trunk/arch/arm/mm/init.c b/trunk/arch/arm/mm/init.c
index ec00f26bffa4..c0ad7c0fbae0 100644
--- a/trunk/arch/arm/mm/init.c
+++ b/trunk/arch/arm/mm/init.c
@@ -239,7 +239,7 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
* Reserve the bootmem bitmap for this node.
*/
reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT,
- boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
+ boot_pages << PAGE_SHIFT);
#ifdef CONFIG_BLK_DEV_INITRD
/*
@@ -247,7 +247,7 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
*/
if (node == initrd_node) {
reserve_bootmem_node(pgdat, phys_initrd_start,
- phys_initrd_size, BOOTMEM_DEFAULT);
+ phys_initrd_size);
initrd_start = __phys_to_virt(phys_initrd_start);
initrd_end = initrd_start + phys_initrd_size;
}
diff --git a/trunk/arch/arm/mm/mmu.c b/trunk/arch/arm/mm/mmu.c
index d41a75ed3dce..e5d61ee3d4a1 100644
--- a/trunk/arch/arm/mm/mmu.c
+++ b/trunk/arch/arm/mm/mmu.c
@@ -605,11 +605,9 @@ void __init reserve_node_zero(pg_data_t *pgdat)
* Note that this can only be in node 0.
*/
#ifdef CONFIG_XIP_KERNEL
- reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
#else
- reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
#endif
/*
@@ -617,7 +615,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
* and can only be in node 0.
*/
reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
- PTRS_PER_PGD * sizeof(pgd_t), BOOTMEM_DEFAULT);
+ PTRS_PER_PGD * sizeof(pgd_t));
/*
* Hmm... This should go elsewhere, but we really really need to
@@ -640,10 +638,8 @@ void __init reserve_node_zero(pg_data_t *pgdat)
/* H1940 and RX3715 need to reserve this for suspend */
if (machine_is_h1940() || machine_is_rx3715()) {
- reserve_bootmem_node(pgdat, 0x30003000, 0x1000,
- BOOTMEM_DEFAULT);
- reserve_bootmem_node(pgdat, 0x30081000, 0x1000,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, 0x30003000, 0x1000);
+ reserve_bootmem_node(pgdat, 0x30081000, 0x1000);
}
#ifdef CONFIG_SA1111
@@ -654,8 +650,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
#endif
if (res_size)
- reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
}
/*
diff --git a/trunk/arch/arm/mm/nommu.c b/trunk/arch/arm/mm/nommu.c
index 63c62fdea521..8cd3a60954f0 100644
--- a/trunk/arch/arm/mm/nommu.c
+++ b/trunk/arch/arm/mm/nommu.c
@@ -27,11 +27,9 @@ void __init reserve_node_zero(pg_data_t *pgdat)
* Note that this can only be in node 0.
*/
#ifdef CONFIG_XIP_KERNEL
- reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
#else
- reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
#endif
/*
@@ -39,8 +37,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
* some architectures which the DRAM is the exception vector to trap,
* alloc_page breaks with error, although it is not NULL, but "0."
*/
- reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE);
}
/*
diff --git a/trunk/arch/arm/plat-omap/fb.c b/trunk/arch/arm/plat-omap/fb.c
index 7854f19b77cf..ee40c1a0b83d 100644
--- a/trunk/arch/arm/plat-omap/fb.c
+++ b/trunk/arch/arm/plat-omap/fb.c
@@ -207,7 +207,7 @@ void __init omapfb_reserve_sdram(void)
return;
}
if (rg.paddr)
- reserve_bootmem(rg.paddr, rg.size, BOOTMEM_DEFAULT);
+ reserve_bootmem(rg.paddr, rg.size);
reserved += rg.size;
omapfb_config.mem_desc.region[i] = rg;
configured_regions++;
diff --git a/trunk/arch/avr32/kernel/setup.c b/trunk/arch/avr32/kernel/setup.c
index e66a07a928cd..4b4c1884e1c5 100644
--- a/trunk/arch/avr32/kernel/setup.c
+++ b/trunk/arch/avr32/kernel/setup.c
@@ -489,8 +489,7 @@ static void __init setup_bootmem(void)
/* Reserve space for the bootmem bitmap... */
reserve_bootmem_node(NODE_DATA(node),
PFN_PHYS(bootmap_pfn),
- bootmap_size,
- BOOTMEM_DEFAULT);
+ bootmap_size);
/* ...and any other reserved regions. */
for (res = reserved; res; res = res->sibling) {
@@ -506,8 +505,7 @@ static void __init setup_bootmem(void)
&& res->end < PFN_PHYS(max_pfn))
reserve_bootmem_node(
NODE_DATA(node), res->start,
- res->end - res->start + 1,
- BOOTMEM_DEFAULT);
+ res->end - res->start + 1);
}
node_set_online(node);
diff --git a/trunk/arch/blackfin/kernel/setup.c b/trunk/arch/blackfin/kernel/setup.c
index 6e106b3d7729..462cae893757 100644
--- a/trunk/arch/blackfin/kernel/setup.c
+++ b/trunk/arch/blackfin/kernel/setup.c
@@ -406,7 +406,7 @@ void __init setup_arch(char **cmdline_p)
*/
free_bootmem(memory_start, memory_end - memory_start);
- reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(memory_start, bootmap_size);
/*
* get kmalloc into gear
*/
diff --git a/trunk/arch/cris/kernel/setup.c b/trunk/arch/cris/kernel/setup.c
index 4da042e100a0..65466c49d7a9 100644
--- a/trunk/arch/cris/kernel/setup.c
+++ b/trunk/arch/cris/kernel/setup.c
@@ -137,7 +137,7 @@ setup_arch(char **cmdline_p)
* Arguments are start, size
*/
- reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size);
/* paging_init() sets up the MMU and marks all pages as reserved */
diff --git a/trunk/arch/frv/kernel/setup.c b/trunk/arch/frv/kernel/setup.c
index 6c01464db699..b38ae1fc15fd 100644
--- a/trunk/arch/frv/kernel/setup.c
+++ b/trunk/arch/frv/kernel/setup.c
@@ -925,15 +925,13 @@ static void __init setup_linux_memory(void)
#endif
/* take back the memory occupied by the kernel image and the bootmem alloc map */
- reserve_bootmem(kstart, kend - kstart + bootmap_size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(kstart, kend - kstart + bootmap_size);
/* reserve the memory occupied by the initial ramdisk */
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= (low_top_pfn << PAGE_SHIFT)) {
- reserve_bootmem(INITRD_START, INITRD_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start = INITRD_START + PAGE_OFFSET;
initrd_end = initrd_start + INITRD_SIZE;
}
@@ -988,10 +986,9 @@ static void __init setup_uclinux_memory(void)
/* now take back the bits the core kernel is occupying */
#ifndef CONFIG_PROTECT_KERNEL
- reserve_bootmem(kend, bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(kend, bootmap_size);
reserve_bootmem((unsigned long) &__kernel_image_start,
- kend - (unsigned long) &__kernel_image_start,
- BOOTMEM_DEFAULT);
+ kend - (unsigned long) &__kernel_image_start);
#else
dampr = __get_DAMPR(0);
@@ -999,15 +996,14 @@ static void __init setup_uclinux_memory(void)
dampr = (dampr >> 4) + 17;
dampr = 1 << dampr;
- reserve_bootmem(__get_DAMPR(0) & xAMPRx_PPFN, dampr, BOOTMEM_DEFAULT);
+ reserve_bootmem(__get_DAMPR(0) & xAMPRx_PPFN, dampr);
#endif
/* reserve some memory to do uncached DMA through if requested */
#ifdef CONFIG_RESERVE_DMA_COHERENT
if (dma_coherent_mem_start)
reserve_bootmem(dma_coherent_mem_start,
- dma_coherent_mem_end - dma_coherent_mem_start,
- BOOTMEM_DEFAULT);
+ dma_coherent_mem_end - dma_coherent_mem_start);
#endif
} /* end setup_uclinux_memory() */
diff --git a/trunk/arch/h8300/kernel/setup.c b/trunk/arch/h8300/kernel/setup.c
index cd3734614d9d..b2e86d0255e6 100644
--- a/trunk/arch/h8300/kernel/setup.c
+++ b/trunk/arch/h8300/kernel/setup.c
@@ -173,7 +173,7 @@ void __init setup_arch(char **cmdline_p)
* the bootmem bitmap so we then reserve it after freeing it :-)
*/
free_bootmem(memory_start, memory_end - memory_start);
- reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(memory_start, bootmap_size);
/*
* get kmalloc into gear
*/
diff --git a/trunk/arch/ia64/kernel/machine_kexec.c b/trunk/arch/ia64/kernel/machine_kexec.c
index 0823de1f6ebe..d6cd45f4c6c7 100644
--- a/trunk/arch/ia64/kernel/machine_kexec.c
+++ b/trunk/arch/ia64/kernel/machine_kexec.c
@@ -129,14 +129,13 @@ void machine_kexec(struct kimage *image)
void arch_crash_save_vmcoreinfo(void)
{
-#if defined(CONFIG_DISCONTIGMEM) || defined(CONFIG_SPARSEMEM)
+#if defined(CONFIG_ARCH_DISCONTIGMEM_ENABLE) && defined(CONFIG_NUMA)
VMCOREINFO_SYMBOL(pgdat_list);
VMCOREINFO_LENGTH(pgdat_list, MAX_NUMNODES);
-#endif
-#ifdef CONFIG_NUMA
+
VMCOREINFO_SYMBOL(node_memblk);
VMCOREINFO_LENGTH(node_memblk, NR_NODE_MEMBLKS);
- VMCOREINFO_STRUCT_SIZE(node_memblk_s);
+ VMCOREINFO_SIZE(node_memblk_s);
VMCOREINFO_OFFSET(node_memblk_s, start_paddr);
VMCOREINFO_OFFSET(node_memblk_s, size);
#endif
diff --git a/trunk/arch/ia64/mm/contig.c b/trunk/arch/ia64/mm/contig.c
index 344f64eca7a9..7e9c275ea148 100644
--- a/trunk/arch/ia64/mm/contig.c
+++ b/trunk/arch/ia64/mm/contig.c
@@ -218,7 +218,7 @@ find_memory (void)
/* Free all available memory, then mark bootmem-map as being in use. */
efi_memmap_walk(filter_rsvd_memory, free_bootmem);
- reserve_bootmem(bootmap_start, bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(bootmap_start, bootmap_size);
find_initrd();
diff --git a/trunk/arch/ia64/mm/discontig.c b/trunk/arch/ia64/mm/discontig.c
index ee5e68b2af94..0b567398f38e 100644
--- a/trunk/arch/ia64/mm/discontig.c
+++ b/trunk/arch/ia64/mm/discontig.c
@@ -299,12 +299,12 @@ static void __init reserve_pernode_space(void)
pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
base = __pa(bdp->node_bootmem_map);
- reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pdp, base, size);
/* Now the per-node space */
size = mem_data[node].pernode_size;
base = __pa(mem_data[node].pernode_addr);
- reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
+ reserve_bootmem_node(pdp, base, size);
}
}
diff --git a/trunk/arch/m32r/kernel/setup.c b/trunk/arch/m32r/kernel/setup.c
index f1f5db0c4084..d64814385d70 100644
--- a/trunk/arch/m32r/kernel/setup.c
+++ b/trunk/arch/m32r/kernel/setup.c
@@ -177,28 +177,25 @@ static unsigned long __init setup_memory(void)
*/
reserve_bootmem(CONFIG_MEMORY_START + PAGE_SIZE,
(PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE - 1)
- - CONFIG_MEMORY_START,
- BOOTMEM_DEFAULT);
+ - CONFIG_MEMORY_START);
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
* enabling clean reboots, SMP operation, laptop functions.
*/
- reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE);
/*
* reserve memory hole
*/
#ifdef CONFIG_MEMHOLE
- reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
- reserve_bootmem(INITRD_START, INITRD_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start = INITRD_START + PAGE_OFFSET;
initrd_end = initrd_start + INITRD_SIZE;
printk("initrd:start[%08lx],size[%08lx]\n",
diff --git a/trunk/arch/m32r/kernel/smpboot.c b/trunk/arch/m32r/kernel/smpboot.c
index 2c03ac1d005f..0e383da158e9 100644
--- a/trunk/arch/m32r/kernel/smpboot.c
+++ b/trunk/arch/m32r/kernel/smpboot.c
@@ -43,7 +43,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/trunk/arch/m32r/mm/discontig.c b/trunk/arch/m32r/mm/discontig.c
index 07c1af7dc0e2..c7efdb0aefc5 100644
--- a/trunk/arch/m32r/mm/discontig.c
+++ b/trunk/arch/m32r/mm/discontig.c
@@ -91,8 +91,7 @@ unsigned long __init setup_memory(void)
PFN_PHYS(mp->pages));
reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn),
- PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size,
- BOOTMEM_DEFAULT);
+ PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size);
if (max_low_pfn < max_pfn)
max_low_pfn = max_pfn;
@@ -105,7 +104,7 @@ unsigned long __init setup_memory(void)
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= PFN_PHYS(max_low_pfn)) {
reserve_bootmem_node(NODE_DATA(0), INITRD_START,
- INITRD_SIZE, BOOTMEM_DEFAULT);
+ INITRD_SIZE);
initrd_start = INITRD_START + PAGE_OFFSET;
initrd_end = initrd_start + INITRD_SIZE;
printk("initrd:start[%08lx],size[%08lx]\n",
diff --git a/trunk/arch/m68k/atari/stram.c b/trunk/arch/m68k/atari/stram.c
index 0055a6c06f75..8dda6515887a 100644
--- a/trunk/arch/m68k/atari/stram.c
+++ b/trunk/arch/m68k/atari/stram.c
@@ -154,7 +154,7 @@ void __init atari_stram_reserve_pages(void *start_mem)
/* always reserve first page of ST-RAM, the first 2 kB are
* supervisor-only! */
if (!kernel_in_stram)
- reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem (0, PAGE_SIZE);
}
diff --git a/trunk/arch/m68k/kernel/setup.c b/trunk/arch/m68k/kernel/setup.c
index 9a06c48edcb3..ed3a4caec620 100644
--- a/trunk/arch/m68k/kernel/setup.c
+++ b/trunk/arch/m68k/kernel/setup.c
@@ -323,8 +323,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_BLK_DEV_INITRD
if (m68k_ramdisk.size) {
reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
- m68k_ramdisk.addr, m68k_ramdisk.size,
- BOOTMEM_DEFAULT);
+ m68k_ramdisk.addr, m68k_ramdisk.size);
initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
initrd_end = initrd_start + m68k_ramdisk.size;
printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
diff --git a/trunk/arch/m68knommu/kernel/setup.c b/trunk/arch/m68knommu/kernel/setup.c
index 156c6c662c7e..81507c53d4a9 100644
--- a/trunk/arch/m68knommu/kernel/setup.c
+++ b/trunk/arch/m68knommu/kernel/setup.c
@@ -203,7 +203,7 @@ void __init setup_arch(char **cmdline_p)
* the bootmem bitmap so we then reserve it after freeing it :-)
*/
free_bootmem(memory_start, memory_end - memory_start);
- reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(memory_start, bootmap_size);
/*
* Get kmalloc into gear.
diff --git a/trunk/arch/mips/kernel/setup.c b/trunk/arch/mips/kernel/setup.c
index 39f3dfe134fb..c032409cba9b 100644
--- a/trunk/arch/mips/kernel/setup.c
+++ b/trunk/arch/mips/kernel/setup.c
@@ -232,7 +232,7 @@ static void __init finalize_initrd(void)
goto disable;
}
- reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
+ reserve_bootmem(__pa(initrd_start), size);
initrd_below_start_ok = 1;
printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n",
@@ -413,7 +413,7 @@ static void __init bootmem_init(void)
/*
* Reserve the bootmap memory.
*/
- reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(PFN_PHYS(mapstart), bootmap_size);
/*
* Reserve initrd memory if needed.
diff --git a/trunk/arch/mips/sgi-ip27/ip27-memory.c b/trunk/arch/mips/sgi-ip27/ip27-memory.c
index bf438d02366e..e5e023f50a07 100644
--- a/trunk/arch/mips/sgi-ip27/ip27-memory.c
+++ b/trunk/arch/mips/sgi-ip27/ip27-memory.c
@@ -465,8 +465,7 @@ static void __init node_mem_init(cnodeid_t node)
free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
(slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
- ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size,
- BOOTMEM_DEFAULT);
+ ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
}
/*
diff --git a/trunk/arch/parisc/mm/init.c b/trunk/arch/parisc/mm/init.c
index eb80f5e33d7d..aa875fa43488 100644
--- a/trunk/arch/parisc/mm/init.c
+++ b/trunk/arch/parisc/mm/init.c
@@ -315,13 +315,11 @@ static void __init setup_bootmem(void)
#define PDC_CONSOLE_IO_IODC_SIZE 32768
reserve_bootmem_node(NODE_DATA(0), 0UL,
- (unsigned long)(PAGE0->mem_free +
- PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT);
+ (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
- (unsigned long)(_end - _text), BOOTMEM_DEFAULT);
+ (unsigned long)(_end - _text));
reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
- ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT),
- BOOTMEM_DEFAULT);
+ ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
#ifndef CONFIG_DISCONTIGMEM
@@ -330,8 +328,7 @@ static void __init setup_bootmem(void)
for (i = 0; i < npmem_holes; i++) {
reserve_bootmem_node(NODE_DATA(0),
(pmem_holes[i].start_pfn << PAGE_SHIFT),
- (pmem_holes[i].pages << PAGE_SHIFT),
- BOOTMEM_DEFAULT);
+ (pmem_holes[i].pages << PAGE_SHIFT));
}
#endif
@@ -349,8 +346,7 @@ static void __init setup_bootmem(void)
initrd_below_start_ok = 1;
printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
- reserve_bootmem_node(NODE_DATA(0), __pa(initrd_start),
- initrd_reserve, BOOTMEM_DEFAULT);
+ reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_reserve);
}
}
#endif
diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig
index 8dcac0b22d68..cf030b004415 100644
--- a/trunk/arch/powerpc/Kconfig
+++ b/trunk/arch/powerpc/Kconfig
@@ -97,7 +97,6 @@ config EARLY_PRINTK
config COMPAT
bool
default y if PPC64
- select COMPAT_BINFMT_ELF
config SYSVIPC_COMPAT
bool
@@ -439,6 +438,25 @@ config WANT_DEVICE_TREE
bool
default n
+config DEVICE_TREE
+ string "Static device tree source file"
+ depends on WANT_DEVICE_TREE
+ help
+ This specifies the device tree source (.dts) file to be
+ compiled and included when building the bootwrapper. If a
+ relative filename is given, then it will be relative to
+ arch/powerpc/boot/dts. If you are not using the bootwrapper,
+ or do not need to build a dts into the bootwrapper, this
+ field is ignored.
+
+ For example, this is required when building a cuImage target
+ for an older U-Boot, which cannot pass a device tree itself.
+ Such a kernel will not work with a newer U-Boot that tries to
+ pass a device tree (unless you tell it not to). If your U-Boot
+ does not mention a device tree in "help bootm", then use the
+ cuImage target and specify a device tree here. Otherwise, use
+ the uImage target and leave this field blank.
+
endmenu
config ISA_DMA_API
@@ -494,7 +512,7 @@ config PCI
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
|| PPC_PS3 || 44x
- default y if !40x && !CPM2 && !8xx && !PPC_MPC512x && !PPC_83xx \
+ default y if !40x && !CPM2 && !8xx && !PPC_83xx \
&& !PPC_85xx && !PPC_86xx
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
default PCI_QSPAN if !4xx && !CPM2 && 8xx
diff --git a/trunk/arch/powerpc/Makefile b/trunk/arch/powerpc/Makefile
index 6845482f0093..f70df9b64f8f 100644
--- a/trunk/arch/powerpc/Makefile
+++ b/trunk/arch/powerpc/Makefile
@@ -151,11 +151,14 @@ core-$(CONFIG_XMON) += arch/powerpc/xmon/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
# Default to zImage, override when needed
-all: zImage
+defaultimage-y := zImage
+defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage
+KBUILD_IMAGE := $(defaultimage-y)
+all: $(KBUILD_IMAGE)
CPPFLAGS_vmlinux.lds := -Upowerpc
-BOOT_TARGETS = zImage zImage.initrd uImage treeImage.% cuImage.%
+BOOT_TARGETS = zImage zImage.initrd uImage
PHONY += $(BOOT_TARGETS)
@@ -177,7 +180,7 @@ define archhelp
endef
install: vdso_install
- $(Q)$(MAKE) $(build)=$(boot) install
+ $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
vdso_install:
ifeq ($(CONFIG_PPC64),y)
diff --git a/trunk/arch/powerpc/boot/Makefile b/trunk/arch/powerpc/boot/Makefile
index 49797a45416c..122a27078998 100644
--- a/trunk/arch/powerpc/boot/Makefile
+++ b/trunk/arch/powerpc/boot/Makefile
@@ -60,9 +60,8 @@ src-wlib := string.S crt0.S stdio.c main.c \
src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
- cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
- cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \
- fixed-head.S ep88xc.c ep405.c \
+ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
+ fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c \
cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
cuboot-warp.c cuboot-85xx-cpm2.c
src-boot := $(src-wlib) $(src-plat) empty.c
@@ -124,8 +123,6 @@ targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds
-dtstree := $(srctree)/$(src)/dts
-
wrapper :=$(srctree)/$(src)/wrapper
wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \
$(wrapper) FORCE
@@ -184,7 +181,7 @@ quiet_cmd_wrap = WRAP $@
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
-image-$(CONFIG_PPC_PS3) += zImage-dtb.ps3
+image-$(CONFIG_PPC_PS3) += zImage.ps3
image-$(CONFIG_PPC_CELLEB) += zImage.pseries
image-$(CONFIG_PPC_CHRP) += zImage.chrp
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
@@ -194,69 +191,33 @@ image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800
image-$(CONFIG_PPC_ISERIES) += zImage.iseries
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
-#
-# Targets which embed a device tree blob
-#
-# Theses are default targets to build images which embed device tree blobs.
-# They are only required on boards which do not have FDT support in firmware.
-# Boards with newish u-boot firmare can use the uImage target above
-#
-
-# Board ports in arch/powerpc/platform/40x/Kconfig
-image-$(CONFIG_EP405) += zImage-dtb.ep405
-image-$(CONFIG_WALNUT) += treeImage.walnut
-
-# Board ports in arch/powerpc/platform/44x/Kconfig
+ifneq ($(CONFIG_DEVICE_TREE),"")
+image-$(CONFIG_PPC_8xx) += cuImage.8xx
+image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc
+image-$(CONFIG_EP405) += zImage.ep405
+image-$(CONFIG_8260) += cuImage.pq2
+image-$(CONFIG_EP8248E) += zImage.ep8248e
+image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx
+image-$(CONFIG_STORCENTER) += cuImage.824x
+image-$(CONFIG_PPC_83xx) += cuImage.83xx
+image-$(CONFIG_PPC_85xx) += cuImage.85xx
+ifeq ($(CONFIG_CPM2),y)
+image-$(CONFIG_PPC_85xx) += cuImage.85xx-cpm2
+endif
+image-$(CONFIG_MPC7448HPC2) += cuImage.hpc2
image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo
image-$(CONFIG_SEQUOIA) += cuImage.sequoia
image-$(CONFIG_RAINIER) += cuImage.rainier
+image-$(CONFIG_WALNUT) += treeImage.walnut
image-$(CONFIG_TAISHAN) += cuImage.taishan
image-$(CONFIG_KATMAI) += cuImage.katmai
image-$(CONFIG_WARP) += cuImage.warp
+endif
-# Board ports in arch/powerpc/platform/8xx/Kconfig
-image-$(CONFIG_PPC_MPC86XADS) += cuImage.mpc866ads
-image-$(CONFIG_PPC_MPC885ADS) += cuImage.mpc885ads
-image-$(CONFIG_PPC_EP88XC) += zImage-dtb.ep88xc
-image-$(CONFIG_PPC_ADDER875) += cuImage.adder875-uboot \
- zImage-dtb.adder875-redboot
-
-# Board ports in arch/powerpc/platform/52xx/Kconfig
-image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200 cuImage.lite5200b
-
-# Board ports in arch/powerpc/platform/82xx/Kconfig
-image-$(CONFIG_MPC8272_ADS) += cuImage.mpc8272ads
-image-$(CONFIG_PQ2FADS) += cuImage.pq2fads
-image-$(CONFIG_EP8248E) += zImage-dtb.ep8248e
-
-# Board ports in arch/powerpc/platform/83xx/Kconfig
-image-$(CONFIG_MPC832x_MDS) += cuImage.mpc832x_mds
-image-$(CONFIG_MPC832x_RDB) += cuImage.mpc832x_rdb
-image-$(CONFIG_MPC834x_ITX) += cuImage.mpc8349emitx \
- cuImage.mpc8349emitxgp
-image-$(CONFIG_MPC834x_MDS) += cuImage.mpc834x_mds
-image-$(CONFIG_MPC836x_MDS) += cuImage.mpc836x_mds
-
-# Board ports in arch/powerpc/platform/85xx/Kconfig
-image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads
-image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads
-image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \
- cuImage.mpc8548cds \
- cuImage.mpc8555cds
-image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds
-image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \
- cuImage.mpc8572ds
-image-$(CONFIG_TQM8540) += cuImage.tqm8540
-image-$(CONFIG_TQM8541) += cuImage.tqm8541
-image-$(CONFIG_TQM8555) += cuImage.tqm8555
-image-$(CONFIG_TQM8560) += cuImage.tqm8560
-image-$(CONFIG_SBC8548) += cuImage.tqm8548
-image-$(CONFIG_SBC8560) += cuImage.tqm8560
-
-# Board ports in arch/powerpc/platform/embedded6xx/Kconfig
-image-$(CONFIG_STORCENTER) += cuImage.storcenter
-image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2
+ifneq ($(CONFIG_REDBOOT),"")
+image-$(CONFIG_PPC_8xx) += zImage.redboot-8xx
+endif
# For 32-bit powermacs, build the COFF and miboot images
# as well as the ELF images.
@@ -272,20 +233,24 @@ targets += $(image-y) $(initrd-y)
$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
+# If CONFIG_WANT_DEVICE_TREE is set and CONFIG_DEVICE_TREE isn't an
+# empty string, define 'dts' to be path to the dts
+# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
+ifeq ($(CONFIG_WANT_DEVICE_TREE),y)
+ifneq ($(CONFIG_DEVICE_TREE),"")
+dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
+ ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
+endif
+endif
+
# Don't put the ramdisk on the pattern rule; when its missing make will try
# the pattern rule with less dependencies that also matches (even with the
# hard dependency listed).
-$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
- $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
+$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts)
+ $(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz)
-$(obj)/zImage.%: vmlinux $(wrapperbits)
- $(call if_changed,wrap,$*)
-
-$(obj)/zImage-dtb.initrd.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
- $(call if_changed,wrap,$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
-
-$(obj)/zImage-dtb.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
- $(call if_changed,wrap,$*,$(dtstree)/$*.dts)
+$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts)
+ $(call if_changed,wrap,$*,$(dts))
# This cannot be in the root of $(src) as the zImage rule always adds a $(obj)
# prefix
@@ -295,17 +260,24 @@ $(obj)/vmlinux.strip: vmlinux
$(obj)/zImage.iseries: vmlinux
$(STRIP) -s -R .comment $< -o $@
+$(obj)/zImage.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts
+ $(STRIP) -s -R .comment $< -o vmlinux.strip
+ $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,)
+
+$(obj)/zImage.initrd.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts $(obj)/ramdisk.image.gz
+ $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,$(obj)/ramdisk.image.gz)
+
$(obj)/uImage: vmlinux $(wrapperbits)
$(call if_changed,wrap,uboot)
-$(obj)/cuImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
- $(call if_changed,wrap,cuboot-$*,$(dtstree)/$*.dts)
+$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
+ $(call if_changed,wrap,cuboot-$*,$(dts))
-$(obj)/treeImage.initrd.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
- $(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
+$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
+ $(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz)
-$(obj)/treeImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
- $(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts)
+$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
+ $(call if_changed,wrap,treeboot-$*,$(dts))
# If there isn't a platform selected then just strip the vmlinux.
ifeq (,$(image-y))
diff --git a/trunk/arch/powerpc/boot/cuboot-mpc7448hpc2.c b/trunk/arch/powerpc/boot/cuboot-hpc2.c
similarity index 100%
rename from trunk/arch/powerpc/boot/cuboot-mpc7448hpc2.c
rename to trunk/arch/powerpc/boot/cuboot-hpc2.c
diff --git a/trunk/arch/powerpc/boot/dts/adder875-redboot.dts b/trunk/arch/powerpc/boot/dts/adder875-redboot.dts
index 28e9cd3d7a21..930bfb3894eb 100644
--- a/trunk/arch/powerpc/boot/dts/adder875-redboot.dts
+++ b/trunk/arch/powerpc/boot/dts/adder875-redboot.dts
@@ -151,7 +151,6 @@
compatible = "fsl,mpc875-brg",
"fsl,cpm1-brg",
"fsl,cpm-brg";
- clock-frequency = <50000000>;
reg = <0x9f0 0x10>;
};
diff --git a/trunk/arch/powerpc/boot/dts/adder875-uboot.dts b/trunk/arch/powerpc/boot/dts/adder875-uboot.dts
index 54fb60ec03e5..0197242dacfb 100644
--- a/trunk/arch/powerpc/boot/dts/adder875-uboot.dts
+++ b/trunk/arch/powerpc/boot/dts/adder875-uboot.dts
@@ -150,7 +150,6 @@
compatible = "fsl,mpc875-brg",
"fsl,cpm1-brg",
"fsl,cpm-brg";
- clock-frequency = <50000000>;
reg = <0x9f0 0x10>;
};
diff --git a/trunk/arch/powerpc/boot/dts/mpc5121ads.dts b/trunk/arch/powerpc/boot/dts/mpc5121ads.dts
deleted file mode 100644
index 94ad7b2b241e..000000000000
--- a/trunk/arch/powerpc/boot/dts/mpc5121ads.dts
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * MPC5121E MDS Device Tree Source
- *
- * Copyright 2007 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 as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-/dts-v1/;
-
-/ {
- model = "mpc5121ads";
- compatible = "fsl,mpc5121ads";
- #address-cells = <1>;
- #size-cells = <1>;
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,5121@0 {
- device_type = "cpu";
- reg = <0>;
- d-cache-line-size = <0x20>; // 32 bytes
- i-cache-line-size = <0x20>; // 32 bytes
- d-cache-size = <0x8000>; // L1, 32K
- i-cache-size = <0x8000>; // L1, 32K
- timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
- bus-frequency = <198000000>; // 198 MHz csb bus
- clock-frequency = <396000000>; // 396 MHz ppc core
- };
- };
-
- memory {
- device_type = "memory";
- reg = <0x00000000 0x10000000>; // 256MB at 0
- };
-
- localbus@80000020 {
- compatible = "fsl,mpc5121ads-localbus";
- #address-cells = <2>;
- #size-cells = <1>;
- reg = <0x80000020 0x40>;
-
- ranges = <0x0 0x0 0xfc000000 0x04000000
- 0x2 0x0 0x82000000 0x00008000>;
-
- flash@0,0 {
- compatible = "cfi-flash";
- reg = <0 0x0 0x4000000>;
- bank-width = <4>;
- device-width = <1>;
- };
-
- board-control@2,0 {
- compatible = "fsl,mpc5121ads-cpld";
- reg = <0x2 0x0 0x8000>;
- };
- };
-
- soc@80000000 {
- compatible = "fsl,mpc5121-immr";
- #address-cells = <1>;
- #size-cells = <1>;
- #interrupt-cells = <2>;
- ranges = <0x0 0x80000000 0x400000>;
- reg = <0x80000000 0x400000>;
- bus-frequency = <66000000>; // 66 MHz ips bus
-
-
- // IPIC
- // interrupts cell =
- // sense values match linux IORESOURCE_IRQ_* defines:
- // sense == 8: Level, low assertion
- // sense == 2: Edge, high-to-low change
- //
- ipic: interrupt-controller@c00 {
- compatible = "fsl,mpc5121-ipic", "fsl,ipic";
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0xc00 0x100>;
- };
-
- // 512x PSCs are not 52xx PSCs compatible
- // PSC3 serial port A aka ttyPSC0
- serial@11300 {
- device_type = "serial";
- compatible = "fsl,mpc5121-psc-uart";
- // Logical port assignment needed until driver
- // learns to use aliases
- port-number = <0>;
- cell-index = <3>;
- reg = <0x11300 0x100>;
- interrupts = <0x28 0x8>; // actually the fifo irq
- interrupt-parent = < &ipic >;
- };
-
- // PSC4 serial port B aka ttyPSC1
- serial@11400 {
- device_type = "serial";
- compatible = "fsl,mpc5121-psc-uart";
- // Logical port assignment needed until driver
- // learns to use aliases
- port-number = <1>;
- cell-index = <4>;
- reg = <0x11400 0x100>;
- interrupts = <0x28 0x8>; // actually the fifo irq
- interrupt-parent = < &ipic >;
- };
-
- pscsfifo@11f00 {
- compatible = "fsl,mpc5121-psc-fifo";
- reg = <0x11f00 0x100>;
- interrupts = <0x28 0x8>;
- interrupt-parent = < &ipic >;
- };
- };
-};
diff --git a/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts b/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts
index e1f0dca8ac39..2d6653fe72ff 100644
--- a/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -118,10 +118,6 @@
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
- rtc@68 {
- compatible = "dallas,ds1339";
- reg = <0x68>;
- };
};
i2c@3100 {
diff --git a/trunk/arch/powerpc/boot/dts/mpc8315erdb.dts b/trunk/arch/powerpc/boot/dts/mpc8315erdb.dts
index d7a1ececa30f..b582032ba3d6 100644
--- a/trunk/arch/powerpc/boot/dts/mpc8315erdb.dts
+++ b/trunk/arch/powerpc/boot/dts/mpc8315erdb.dts
@@ -96,7 +96,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
- compatible = "fsl,mpc8315-immr", "simple-bus";
+ compatible = "simple-bus";
ranges = <0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts
index 0199c5c548d8..7480edae85ed 100644
--- a/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -332,7 +332,7 @@
0xc000 0x0 0x0 0x3 &ipic 23 0x8
0xc000 0x0 0x0 0x4 &ipic 20 0x8>;
interrupt-parent = <&ipic>;
- interrupts = <67 0x8>;
+ interrupts = <66 0x8>;
bus-range = <0 0>;
ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
diff --git a/trunk/arch/powerpc/boot/dts/mpc8572ds.dts b/trunk/arch/powerpc/boot/dts/mpc8572ds.dts
index db37214aee37..813c259abbe5 100644
--- a/trunk/arch/powerpc/boot/dts/mpc8572ds.dts
+++ b/trunk/arch/powerpc/boot/dts/mpc8572ds.dts
@@ -42,18 +42,6 @@
bus-frequency = <0>;
clock-frequency = <0>;
};
-
- PowerPC,8572@1 {
- device_type = "cpu";
- reg = <1>;
- d-cache-line-size = <20>; // 32 bytes
- i-cache-line-size = <20>; // 32 bytes
- d-cache-size = <8000>; // L1, 32K
- i-cache-size = <8000>; // L1, 32K
- timebase-frequency = <0>;
- bus-frequency = <0>;
- clock-frequency = <0>;
- };
};
memory {
diff --git a/trunk/arch/powerpc/boot/dts/mpc885ads.dts b/trunk/arch/powerpc/boot/dts/mpc885ads.dts
index d84a012c2aaf..8848e637293e 100644
--- a/trunk/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/trunk/arch/powerpc/boot/dts/mpc885ads.dts
@@ -166,7 +166,6 @@
compatible = "fsl,mpc885-brg",
"fsl,cpm1-brg",
"fsl,cpm-brg";
- clock-frequency = <0>;
reg = <9f0 10>;
};
diff --git a/trunk/arch/powerpc/boot/dts/sequoia.dts b/trunk/arch/powerpc/boot/dts/sequoia.dts
index 5c13d46f441d..d9046c1adcbe 100644
--- a/trunk/arch/powerpc/boot/dts/sequoia.dts
+++ b/trunk/arch/powerpc/boot/dts/sequoia.dts
@@ -138,14 +138,6 @@
interrupts = <15 8>;
};
- USB0: ehci@e0000300 {
- compatible = "ibm,usb-ehci-440epx", "usb-ehci";
- interrupt-parent = <&UIC0>;
- interrupts = <1a 4>;
- reg = <0 e0000300 90 0 e0000390 70>;
- big-endian;
- };
-
POB0: opb {
compatible = "ibm,opb-440epx", "ibm,opb";
#address-cells = <1>;
diff --git a/trunk/arch/powerpc/boot/dts/storcenter.dts b/trunk/arch/powerpc/boot/dts/storcenter.dts
index 5893816c0bce..2204874ac5f3 100644
--- a/trunk/arch/powerpc/boot/dts/storcenter.dts
+++ b/trunk/arch/powerpc/boot/dts/storcenter.dts
@@ -15,7 +15,7 @@
/ {
model = "StorCenter";
- compatible = "iomega,storcenter";
+ compatible = "storcenter";
#address-cells = <1>;
#size-cells = <1>;
@@ -62,12 +62,12 @@
#size-cells = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
- interrupts = <17 2>;
+ interrupts = <5 2>;
interrupt-parent = <&mpic>;
rtc@68 {
compatible = "dallas,ds1337";
- reg = <0x68>;
+ reg = <68>;
};
};
@@ -78,7 +78,7 @@
reg = <0x4500 0x20>;
clock-frequency = <97553800>; /* Hz */
current-speed = <115200>;
- interrupts = <25 2>;
+ interrupts = <9 2>;
interrupt-parent = <&mpic>;
};
@@ -89,7 +89,7 @@
reg = <0x4600 0x20>;
clock-frequency = <97553800>; /* Hz */
current-speed = <9600>;
- interrupts = <26 2>;
+ interrupts = <10 2>;
interrupt-parent = <&mpic>;
};
@@ -136,6 +136,6 @@
};
chosen {
- linux,stdout-path = &serial0;
+ linux,stdout-path = "/soc/serial@4500";
};
};
diff --git a/trunk/arch/powerpc/boot/wrapper b/trunk/arch/powerpc/boot/wrapper
index c3178155311b..763a0c46f441 100755
--- a/trunk/arch/powerpc/boot/wrapper
+++ b/trunk/arch/powerpc/boot/wrapper
@@ -158,29 +158,6 @@ miboot|uboot)
cuboot*)
binary=y
gzip=
- case "$platform" in
- *-mpc885ads|*-adder875*|*-ep88xc)
- platformo=$object/cuboot-8xx.o
- ;;
- *5200*|*-motionpro)
- platformo=$object/cuboot-52xx.o
- ;;
- *-pq2fads|*-ep8248e|*-mpc8272*|*-storcenter)
- platformo=$object/cuboot-pq2.o
- ;;
- *-mpc824*)
- platformo=$object/cuboot-824x.o
- ;;
- *-mpc83*)
- platformo=$object/cuboot-83xx.o
- ;;
- *-tqm8541|*-mpc8560*|*-tqm8560|*-tqm8555*)
- platformo=$object/cuboot-85xx-cpm2.o
- ;;
- *-mpc85*)
- platformo=$object/cuboot-85xx.o
- ;;
- esac
;;
ps3)
platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
diff --git a/trunk/arch/powerpc/configs/mpc83xx_defconfig b/trunk/arch/powerpc/configs/mpc83xx_defconfig
index a9807f083bc4..31bdbf3f7566 100644
--- a/trunk/arch/powerpc/configs/mpc83xx_defconfig
+++ b/trunk/arch/powerpc/configs/mpc83xx_defconfig
@@ -186,7 +186,7 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT is not set
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
-CONFIG_MATH_EMULATION=y
+# CONFIG_MATH_EMULATION is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
@@ -416,14 +416,14 @@ CONFIG_PHYLIB=y
# MII PHY device drivers
#
CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
+# CONFIG_DAVICOM_PHY is not set
# CONFIG_QSEMI_PHY is not set
# CONFIG_LXT_PHY is not set
# CONFIG_CICADA_PHY is not set
-CONFIG_VITESSE_PHY=y
+# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
# CONFIG_BROADCOM_PHY is not set
-CONFIG_ICPLUS_PHY=y
+# CONFIG_ICPLUS_PHY is not set
# CONFIG_FIXED_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
@@ -436,7 +436,7 @@ CONFIG_MII=y
CONFIG_NETDEV_1000=y
CONFIG_GIANFAR=y
# CONFIG_GFAR_NAPI is not set
-CONFIG_UCC_GETH=y
+# CONFIG_UCC_GETH is not set
CONFIG_NETDEV_10000=y
#
diff --git a/trunk/arch/powerpc/kernel/Makefile b/trunk/arch/powerpc/kernel/Makefile
index 0662ae46f724..58dbfeff9b4d 100644
--- a/trunk/arch/powerpc/kernel/Makefile
+++ b/trunk/arch/powerpc/kernel/Makefile
@@ -2,8 +2,6 @@
# Makefile for the linux kernel.
#
-CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
-
ifeq ($(CONFIG_PPC64),y)
CFLAGS_prom_init.o += -mno-minimal-toc
endif
@@ -17,7 +15,7 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
init_task.o process.o systbl.o idle.o \
signal.o
obj-y += vdso32/
-obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
+obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
signal_64.o ptrace32.o \
paca.o cpu_setup_ppc970.o \
cpu_setup_pa6t.o \
diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c
index e6e49289f788..ed083feaf6f9 100644
--- a/trunk/arch/powerpc/kernel/asm-offsets.c
+++ b/trunk/arch/powerpc/kernel/asm-offsets.c
@@ -22,7 +22,6 @@
#include
#include
#include
-#include
#ifdef CONFIG_PPC64
#include
#include
@@ -313,7 +312,7 @@ int main(void)
DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
- DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64);
+ DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
#ifdef CONFIG_BUG
DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
diff --git a/trunk/arch/powerpc/kernel/binfmt_elf32.c b/trunk/arch/powerpc/kernel/binfmt_elf32.c
new file mode 100644
index 000000000000..1d45d7782d4e
--- /dev/null
+++ b/trunk/arch/powerpc/kernel/binfmt_elf32.c
@@ -0,0 +1,69 @@
+/*
+ * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons.
+ * based on the SPARC64 version.
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp
+ * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM
+ *
+ * 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
+#include
+#include
+#include
+
+#undef ELF_ARCH
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_PPC
+
+#undef elfhdr
+#undef elf_phdr
+#undef elf_note
+#undef elf_addr_t
+#define elfhdr elf32_hdr
+#define elf_phdr elf32_phdr
+#define elf_note elf32_note
+#define elf_addr_t Elf32_Off
+
+#define elf_prstatus compat_elf_prstatus
+#define elf_prpsinfo compat_elf_prpsinfo
+
+#define elf_core_copy_regs compat_elf_core_copy_regs
+static inline void compat_elf_core_copy_regs(compat_elf_gregset_t *elf_regs,
+ struct pt_regs *regs)
+{
+ PPC_ELF_CORE_COPY_REGS((*elf_regs), regs);
+}
+
+#define elf_core_copy_task_regs compat_elf_core_copy_task_regs
+static int compat_elf_core_copy_task_regs(struct task_struct *tsk,
+ compat_elf_gregset_t *elf_regs)
+{
+ struct pt_regs *regs = tsk->thread.regs;
+ if (regs)
+ compat_elf_core_copy_regs(elf_regs, regs);
+ return 1;
+}
+
+#include
+
+#undef cputime_to_timeval
+#define cputime_to_timeval cputime_to_compat_timeval
+static __inline__ void
+cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
+{
+ unsigned long jiffies = cputime_to_jiffies(cputime);
+ value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
+ value->tv_sec = jiffies / HZ;
+}
+
+#define init_elf_binfmt init_elf32_binfmt
+
+#include "../../../fs/binfmt_elf.c"
diff --git a/trunk/arch/powerpc/kernel/cputable.c b/trunk/arch/powerpc/kernel/cputable.c
index 2a8f5cc5184f..a4c2771b5e62 100644
--- a/trunk/arch/powerpc/kernel/cputable.c
+++ b/trunk/arch/powerpc/kernel/cputable.c
@@ -959,9 +959,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.cpu_setup = __setup_cpu_603,
- .num_pmcs = 4,
- .oprofile_cpu_type = "ppc/e300",
- .oprofile_type = PPC_OPROFILE_FSL_EMB,
.platform = "ppc603",
},
{ /* e300c4 (e300c1, plus one IU) */
@@ -974,9 +971,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.dcache_bsize = 32,
.cpu_setup = __setup_cpu_603,
.machine_check = machine_check_generic,
- .num_pmcs = 4,
- .oprofile_cpu_type = "ppc/e300",
- .oprofile_type = PPC_OPROFILE_FSL_EMB,
.platform = "ppc603",
},
{ /* default match, we assume split I/D cache & TB (non-601)... */
@@ -1441,7 +1435,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.dcache_bsize = 32,
.num_pmcs = 4,
.oprofile_cpu_type = "ppc/e500",
- .oprofile_type = PPC_OPROFILE_FSL_EMB,
+ .oprofile_type = PPC_OPROFILE_BOOKE,
.machine_check = machine_check_e500,
.platform = "ppc8540",
},
@@ -1459,7 +1453,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.dcache_bsize = 32,
.num_pmcs = 4,
.oprofile_cpu_type = "ppc/e500",
- .oprofile_type = PPC_OPROFILE_FSL_EMB,
+ .oprofile_type = PPC_OPROFILE_BOOKE,
.machine_check = machine_check_e500,
.platform = "ppc8548",
},
diff --git a/trunk/arch/powerpc/kernel/legacy_serial.c b/trunk/arch/powerpc/kernel/legacy_serial.c
index 61dd17449ddc..76b862bd1fe9 100644
--- a/trunk/arch/powerpc/kernel/legacy_serial.c
+++ b/trunk/arch/powerpc/kernel/legacy_serial.c
@@ -36,8 +36,7 @@ static struct legacy_serial_info {
static struct __initdata of_device_id parents[] = {
{.type = "soc",},
{.type = "tsi-bridge",},
- {.type = "opb", },
- {.compatible = "ibm,opb",},
+ {.type = "opb", .compatible = "ibm,opb",},
{.compatible = "simple-bus",},
{.compatible = "wrs,epld-localbus",},
};
diff --git a/trunk/arch/powerpc/kernel/pmc.c b/trunk/arch/powerpc/kernel/pmc.c
index 0516e2d3e02e..ea04e0ab3f2f 100644
--- a/trunk/arch/powerpc/kernel/pmc.c
+++ b/trunk/arch/powerpc/kernel/pmc.c
@@ -26,7 +26,7 @@
static void dummy_perf(struct pt_regs *regs)
{
-#if defined(CONFIG_FSL_EMB_PERFMON)
+#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
diff --git a/trunk/arch/powerpc/kernel/ptrace.c b/trunk/arch/powerpc/kernel/ptrace.c
index 7673e9865733..8b056d2295cc 100644
--- a/trunk/arch/powerpc/kernel/ptrace.c
+++ b/trunk/arch/powerpc/kernel/ptrace.c
@@ -21,8 +21,6 @@
#include
#include
#include
-#include
-#include
#include
#include
#include
@@ -60,38 +58,20 @@
#define PT_MAX_PUT_REG PT_CCR
#endif
-static unsigned long get_user_msr(struct task_struct *task)
-{
- return task->thread.regs->msr | task->thread.fpexc_mode;
-}
-
-static int set_user_msr(struct task_struct *task, unsigned long msr)
-{
- task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
- task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
- return 0;
-}
-
-/*
- * We prevent mucking around with the reserved area of trap
- * which are used internally by the kernel.
- */
-static int set_user_trap(struct task_struct *task, unsigned long trap)
-{
- task->thread.regs->trap = trap & 0xfff0;
- return 0;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
unsigned long ptrace_get_reg(struct task_struct *task, int regno)
{
+ unsigned long tmp = 0;
+
if (task->thread.regs == NULL)
return -EIO;
- if (regno == PT_MSR)
- return get_user_msr(task);
+ if (regno == PT_MSR) {
+ tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
+ return tmp | task->thread.fpexc_mode;
+ }
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
return ((unsigned long *)task->thread.regs)[regno];
@@ -107,134 +87,40 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
if (task->thread.regs == NULL)
return -EIO;
- if (regno == PT_MSR)
- return set_user_msr(task, data);
- if (regno == PT_TRAP)
- return set_user_trap(task, data);
-
- if (regno <= PT_MAX_PUT_REG) {
+ if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
+ if (regno == PT_MSR)
+ data = (data & MSR_DEBUGCHANGE)
+ | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
+ /* We prevent mucking around with the reserved area of trap
+ * which are used internally by the kernel
+ */
+ if (regno == PT_TRAP)
+ data &= 0xfff0;
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
return -EIO;
}
-static int gpr_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
-{
- int ret;
-
- if (target->thread.regs == NULL)
- return -EIO;
-
- CHECK_FULL_REGS(target->thread.regs);
-
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- target->thread.regs,
- 0, offsetof(struct pt_regs, msr));
- if (!ret) {
- unsigned long msr = get_user_msr(target);
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
- offsetof(struct pt_regs, msr),
- offsetof(struct pt_regs, msr) +
- sizeof(msr));
- }
-
- BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
- offsetof(struct pt_regs, msr) + sizeof(long));
-
- if (!ret)
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.regs->orig_gpr3,
- offsetof(struct pt_regs, orig_gpr3),
- sizeof(struct pt_regs));
- if (!ret)
- ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
- sizeof(struct pt_regs), -1);
-
- return ret;
-}
-
-static int gpr_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
-{
- unsigned long reg;
- int ret;
-
- if (target->thread.regs == NULL)
- return -EIO;
-
- CHECK_FULL_REGS(target->thread.regs);
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- target->thread.regs,
- 0, PT_MSR * sizeof(reg));
- if (!ret && count > 0) {
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
- PT_MSR * sizeof(reg),
- (PT_MSR + 1) * sizeof(reg));
- if (!ret)
- ret = set_user_msr(target, reg);
- }
-
- BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
- offsetof(struct pt_regs, msr) + sizeof(long));
-
- if (!ret)
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.regs->orig_gpr3,
- PT_ORIG_R3 * sizeof(reg),
- (PT_MAX_PUT_REG + 1) * sizeof(reg));
-
- if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
- ret = user_regset_copyin_ignore(
- &pos, &count, &kbuf, &ubuf,
- (PT_MAX_PUT_REG + 1) * sizeof(reg),
- PT_TRAP * sizeof(reg));
-
- if (!ret && count > 0) {
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
- PT_TRAP * sizeof(reg),
- (PT_TRAP + 1) * sizeof(reg));
- if (!ret)
- ret = set_user_trap(target, reg);
- }
-
- if (!ret)
- ret = user_regset_copyin_ignore(
- &pos, &count, &kbuf, &ubuf,
- (PT_TRAP + 1) * sizeof(reg), -1);
-
- return ret;
-}
-
-static int fpr_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
+static int get_fpregs(void __user *data, struct task_struct *task,
+ int has_fpscr)
{
- flush_fp_to_thread(target);
-
- BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
- offsetof(struct thread_struct, fpr[32]));
+ unsigned int count = has_fpscr ? 33 : 32;
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpr, 0, -1);
+ if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
+ return -EFAULT;
+ return 0;
}
-static int fpr_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
+static int set_fpregs(void __user *data, struct task_struct *task,
+ int has_fpscr)
{
- flush_fp_to_thread(target);
-
- BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
- offsetof(struct thread_struct, fpr[32]));
+ unsigned int count = has_fpscr ? 33 : 32;
- return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpr, 0, -1);
+ if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
+ return -EFAULT;
+ return 0;
}
@@ -252,74 +138,56 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
* (combined (32- and 64-bit) gdb.
*/
-static int vr_active(struct task_struct *target,
- const struct user_regset *regset)
+/*
+ * Get contents of AltiVec register state in task TASK
+ */
+static int get_vrregs(unsigned long __user *data, struct task_struct *task)
{
- flush_altivec_to_thread(target);
- return target->thread.used_vr ? regset->n : 0;
-}
+ unsigned long regsize;
-static int vr_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
-{
- int ret;
+ /* copy AltiVec registers VR[0] .. VR[31] */
+ regsize = 32 * sizeof(vector128);
+ if (copy_to_user(data, task->thread.vr, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
- flush_altivec_to_thread(target);
+ /* copy VSCR */
+ regsize = 1 * sizeof(vector128);
+ if (copy_to_user(data, &task->thread.vscr, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
- BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
- offsetof(struct thread_struct, vr[32]));
+ /* copy VRSAVE */
+ if (put_user(task->thread.vrsave, (u32 __user *)data))
+ return -EFAULT;
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr, 0,
- 33 * sizeof(vector128));
- if (!ret) {
- /*
- * Copy out only the low-order word of vrsave.
- */
- union {
- elf_vrreg_t reg;
- u32 word;
- } vrsave;
- memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
- 33 * sizeof(vector128), -1);
- }
-
- return ret;
+ return 0;
}
-static int vr_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
+/*
+ * Write contents of AltiVec register state into task TASK.
+ */
+static int set_vrregs(struct task_struct *task, unsigned long __user *data)
{
- int ret;
+ unsigned long regsize;
- flush_altivec_to_thread(target);
+ /* copy AltiVec registers VR[0] .. VR[31] */
+ regsize = 32 * sizeof(vector128);
+ if (copy_from_user(task->thread.vr, data, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
- BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
- offsetof(struct thread_struct, vr[32]));
+ /* copy VSCR */
+ regsize = 1 * sizeof(vector128);
+ if (copy_from_user(&task->thread.vscr, data, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr, 0, 33 * sizeof(vector128));
- if (!ret && count > 0) {
- /*
- * We use only the first word of vrsave.
- */
- union {
- elf_vrreg_t reg;
- u32 word;
- } vrsave;
- memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
- 33 * sizeof(vector128), -1);
- if (!ret)
- target->thread.vrsave = vrsave.word;
- }
+ /* copy VRSAVE */
+ if (get_user(task->thread.vrsave, (u32 __user *)data))
+ return -EFAULT;
- return ret;
+ return 0;
}
#endif /* CONFIG_ALTIVEC */
@@ -335,273 +203,57 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
* }
*/
-static int evr_active(struct task_struct *target,
- const struct user_regset *regset)
-{
- flush_spe_to_thread(target);
- return target->thread.used_spe ? regset->n : 0;
-}
-
-static int evr_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
-{
- int ret;
-
- flush_spe_to_thread(target);
-
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.evr,
- 0, sizeof(target->thread.evr));
-
- BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
- offsetof(struct thread_struct, spefscr));
-
- if (!ret)
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.acc,
- sizeof(target->thread.evr), -1);
-
- return ret;
-}
-
-static int evr_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
-{
- int ret;
-
- flush_spe_to_thread(target);
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.evr,
- 0, sizeof(target->thread.evr));
-
- BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
- offsetof(struct thread_struct, spefscr));
-
- if (!ret)
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.acc,
- sizeof(target->thread.evr), -1);
-
- return ret;
-}
-#endif /* CONFIG_SPE */
-
-
/*
- * These are our native regset flavors.
+ * Get contents of SPE register state in task TASK.
*/
-enum powerpc_regset {
- REGSET_GPR,
- REGSET_FPR,
-#ifdef CONFIG_ALTIVEC
- REGSET_VMX,
-#endif
-#ifdef CONFIG_SPE
- REGSET_SPE,
-#endif
-};
-
-static const struct user_regset native_regsets[] = {
- [REGSET_GPR] = {
- .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
- .size = sizeof(long), .align = sizeof(long),
- .get = gpr_get, .set = gpr_set
- },
- [REGSET_FPR] = {
- .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
- .size = sizeof(double), .align = sizeof(double),
- .get = fpr_get, .set = fpr_set
- },
-#ifdef CONFIG_ALTIVEC
- [REGSET_VMX] = {
- .core_note_type = NT_PPC_VMX, .n = 34,
- .size = sizeof(vector128), .align = sizeof(vector128),
- .active = vr_active, .get = vr_get, .set = vr_set
- },
-#endif
-#ifdef CONFIG_SPE
- [REGSET_SPE] = {
- .n = 35,
- .size = sizeof(u32), .align = sizeof(u32),
- .active = evr_active, .get = evr_get, .set = evr_set
- },
-#endif
-};
-
-static const struct user_regset_view user_ppc_native_view = {
- .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
- .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
-};
-
-#ifdef CONFIG_PPC64
-#include
-
-static int gpr32_get(struct task_struct *target,
- const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
+static int get_evrregs(unsigned long *data, struct task_struct *task)
{
- const unsigned long *regs = &target->thread.regs->gpr[0];
- compat_ulong_t *k = kbuf;
- compat_ulong_t __user *u = ubuf;
- compat_ulong_t reg;
-
- if (target->thread.regs == NULL)
- return -EIO;
+ int i;
- CHECK_FULL_REGS(target->thread.regs);
+ if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
+ return -EFAULT;
- pos /= sizeof(reg);
- count /= sizeof(reg);
+ /* copy SPEFSCR */
+ if (__put_user(task->thread.spefscr, &data[34]))
+ return -EFAULT;
- if (kbuf)
- for (; count > 0 && pos < PT_MSR; --count)
- *k++ = regs[pos++];
- else
- for (; count > 0 && pos < PT_MSR; --count)
- if (__put_user((compat_ulong_t) regs[pos++], u++))
- return -EFAULT;
-
- if (count > 0 && pos == PT_MSR) {
- reg = get_user_msr(target);
- if (kbuf)
- *k++ = reg;
- else if (__put_user(reg, u++))
+ /* copy SPE registers EVR[0] .. EVR[31] */
+ for (i = 0; i < 32; i++, data++)
+ if (__put_user(task->thread.evr[i], data))
return -EFAULT;
- ++pos;
- --count;
- }
- if (kbuf)
- for (; count > 0 && pos < PT_REGS_COUNT; --count)
- *k++ = regs[pos++];
- else
- for (; count > 0 && pos < PT_REGS_COUNT; --count)
- if (__put_user((compat_ulong_t) regs[pos++], u++))
- return -EFAULT;
-
- kbuf = k;
- ubuf = u;
- pos *= sizeof(reg);
- count *= sizeof(reg);
- return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
- PT_REGS_COUNT * sizeof(reg), -1);
+ /* copy ACC */
+ if (__put_user64(task->thread.acc, (unsigned long long *)data))
+ return -EFAULT;
+
+ return 0;
}
-static int gpr32_set(struct task_struct *target,
- const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
+/*
+ * Write contents of SPE register state into task TASK.
+ */
+static int set_evrregs(struct task_struct *task, unsigned long *data)
{
- unsigned long *regs = &target->thread.regs->gpr[0];
- const compat_ulong_t *k = kbuf;
- const compat_ulong_t __user *u = ubuf;
- compat_ulong_t reg;
-
- if (target->thread.regs == NULL)
- return -EIO;
-
- CHECK_FULL_REGS(target->thread.regs);
-
- pos /= sizeof(reg);
- count /= sizeof(reg);
-
- if (kbuf)
- for (; count > 0 && pos < PT_MSR; --count)
- regs[pos++] = *k++;
- else
- for (; count > 0 && pos < PT_MSR; --count) {
- if (__get_user(reg, u++))
- return -EFAULT;
- regs[pos++] = reg;
- }
-
+ int i;
- if (count > 0 && pos == PT_MSR) {
- if (kbuf)
- reg = *k++;
- else if (__get_user(reg, u++))
- return -EFAULT;
- set_user_msr(target, reg);
- ++pos;
- --count;
- }
+ if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
+ return -EFAULT;
- if (kbuf)
- for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
- regs[pos++] = *k++;
- else
- for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
- if (__get_user(reg, u++))
- return -EFAULT;
- regs[pos++] = reg;
- }
+ /* copy SPEFSCR */
+ if (__get_user(task->thread.spefscr, &data[34]))
+ return -EFAULT;
- if (count > 0 && pos == PT_TRAP) {
- if (kbuf)
- reg = *k++;
- else if (__get_user(reg, u++))
+ /* copy SPE registers EVR[0] .. EVR[31] */
+ for (i = 0; i < 32; i++, data++)
+ if (__get_user(task->thread.evr[i], data))
return -EFAULT;
- set_user_trap(target, reg);
- ++pos;
- --count;
- }
-
- kbuf = k;
- ubuf = u;
- pos *= sizeof(reg);
- count *= sizeof(reg);
- return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
- (PT_TRAP + 1) * sizeof(reg), -1);
-}
-
-/*
- * These are the regset flavors matching the CONFIG_PPC32 native set.
- */
-static const struct user_regset compat_regsets[] = {
- [REGSET_GPR] = {
- .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
- .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
- .get = gpr32_get, .set = gpr32_set
- },
- [REGSET_FPR] = {
- .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
- .size = sizeof(double), .align = sizeof(double),
- .get = fpr_get, .set = fpr_set
- },
-#ifdef CONFIG_ALTIVEC
- [REGSET_VMX] = {
- .core_note_type = NT_PPC_VMX, .n = 34,
- .size = sizeof(vector128), .align = sizeof(vector128),
- .active = vr_active, .get = vr_get, .set = vr_set
- },
-#endif
-#ifdef CONFIG_SPE
- [REGSET_SPE] = {
- .core_note_type = NT_PPC_SPE, .n = 35,
- .size = sizeof(u32), .align = sizeof(u32),
- .active = evr_active, .get = evr_get, .set = evr_set
- },
-#endif
-};
-
-static const struct user_regset_view user_ppc_compat_view = {
- .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
- .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
-};
-#endif /* CONFIG_PPC64 */
+ /* copy ACC */
+ if (__get_user64(task->thread.acc, (unsigned long long*)data))
+ return -EFAULT;
-const struct user_regset_view *task_user_regset_view(struct task_struct *task)
-{
-#ifdef CONFIG_PPC64
- if (test_tsk_thread_flag(task, TIF_32BIT))
- return &user_ppc_compat_view;
-#endif
- return &user_ppc_native_view;
+ return 0;
}
+#endif /* CONFIG_SPE */
void user_enable_single_step(struct task_struct *task)
@@ -671,29 +323,55 @@ void ptrace_disable(struct task_struct *child)
static long arch_ptrace_old(struct task_struct *child, long request, long addr,
long data)
{
- switch (request) {
- case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_GPR, 0, 32 * sizeof(long),
- (void __user *) data);
-
- case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_GPR, 0, 32 * sizeof(long),
- (const void __user *) data);
-
- case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_FPR, 0, 32 * sizeof(double),
- (void __user *) data);
-
- case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_FPR, 0, 32 * sizeof(double),
- (const void __user *) data);
+ int ret = -EPERM;
+
+ switch(request) {
+ case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned long __user *tmp = (unsigned long __user *)addr;
+
+ CHECK_FULL_REGS(child->thread.regs);
+ for (i = 0; i < 32; i++) {
+ ret = put_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned long __user *tmp = (unsigned long __user *)addr;
+
+ CHECK_FULL_REGS(child->thread.regs);
+ for (i = 0; i < 32; i++) {
+ ret = get_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
+ flush_fp_to_thread(child);
+ ret = get_fpregs((void __user *)addr, child, 0);
+ break;
+ }
+
+ case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
+ flush_fp_to_thread(child);
+ ret = set_fpregs((void __user *)addr, child, 0);
+ break;
}
- return -EPERM;
+ }
+ return ret;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -701,6 +379,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int ret = -EPERM;
switch (request) {
+ /* when I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
+ break;
+
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long index, tmp;
@@ -728,6 +412,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
+ /* If I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ ret = generic_ptrace_pokedata(child, addr, data);
+ break;
+
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR: {
unsigned long index;
@@ -772,60 +462,85 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef CONFIG_PPC64
case PTRACE_GETREGS64:
#endif
- case PTRACE_GETREGS: /* Get all pt_regs from the child. */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_GPR,
- 0, sizeof(struct pt_regs),
- (void __user *) data);
+ case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
+ int ui;
+ if (!access_ok(VERIFY_WRITE, (void __user *)data,
+ sizeof(struct pt_regs))) {
+ ret = -EIO;
+ break;
+ }
+ CHECK_FULL_REGS(child->thread.regs);
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret |= __put_user(ptrace_get_reg(child, ui),
+ (unsigned long __user *) data);
+ data += sizeof(long);
+ }
+ break;
+ }
#ifdef CONFIG_PPC64
case PTRACE_SETREGS64:
#endif
- case PTRACE_SETREGS: /* Set all gp regs in the child. */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_GPR,
- 0, sizeof(struct pt_regs),
- (const void __user *) data);
-
- case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_FPR,
- 0, sizeof(elf_fpregset_t),
- (void __user *) data);
-
- case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_FPR,
- 0, sizeof(elf_fpregset_t),
- (const void __user *) data);
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ unsigned long tmp;
+ int ui;
+ if (!access_ok(VERIFY_READ, (void __user *)data,
+ sizeof(struct pt_regs))) {
+ ret = -EIO;
+ break;
+ }
+ CHECK_FULL_REGS(child->thread.regs);
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret = __get_user(tmp, (unsigned long __user *) data);
+ if (ret)
+ break;
+ ptrace_put_reg(child, ui, tmp);
+ data += sizeof(long);
+ }
+ break;
+ }
+
+ case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
+ flush_fp_to_thread(child);
+ ret = get_fpregs((void __user *)data, child, 1);
+ break;
+ }
+
+ case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
+ flush_fp_to_thread(child);
+ ret = set_fpregs((void __user *)data, child, 1);
+ break;
+ }
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_VMX,
- 0, (33 * sizeof(vector128) +
- sizeof(u32)),
- (void __user *) data);
+ /* Get the child altivec register state. */
+ flush_altivec_to_thread(child);
+ ret = get_vrregs((unsigned long __user *)data, child);
+ break;
case PTRACE_SETVRREGS:
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_VMX,
- 0, (33 * sizeof(vector128) +
- sizeof(u32)),
- (const void __user *) data);
+ /* Set the child altivec register state. */
+ flush_altivec_to_thread(child);
+ ret = set_vrregs(child, (unsigned long __user *)data);
+ break;
#endif
#ifdef CONFIG_SPE
case PTRACE_GETEVRREGS:
/* Get the child spe register state. */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_SPE, 0, 35 * sizeof(u32),
- (void __user *) data);
+ flush_spe_to_thread(child);
+ ret = get_evrregs((unsigned long __user *)data, child);
+ break;
case PTRACE_SETEVRREGS:
/* Set the child spe register state. */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_SPE, 0, 35 * sizeof(u32),
- (const void __user *) data);
+ /* this is to clear the MSR_SPE bit to force a reload
+ * of register state from memory */
+ flush_spe_to_thread(child);
+ ret = set_evrregs(child, (unsigned long __user *)data);
+ break;
#endif
/* Old reverse args ptrace callss */
diff --git a/trunk/arch/powerpc/kernel/ptrace32.c b/trunk/arch/powerpc/kernel/ptrace32.c
index 4c1de6af4c09..fea6206ff90f 100644
--- a/trunk/arch/powerpc/kernel/ptrace32.c
+++ b/trunk/arch/powerpc/kernel/ptrace32.c
@@ -24,11 +24,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
#include
#include
@@ -47,31 +45,87 @@
static long compat_ptrace_old(struct task_struct *child, long request,
long addr, long data)
{
- switch (request) {
- case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
- return copy_regset_to_user(child,
- task_user_regset_view(current), 0,
- 0, 32 * sizeof(compat_long_t),
- compat_ptr(data));
-
- case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
- return copy_regset_from_user(child,
- task_user_regset_view(current), 0,
- 0, 32 * sizeof(compat_long_t),
- compat_ptr(data));
+ int ret = -EPERM;
+
+ switch(request) {
+ case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned int __user *tmp = (unsigned int __user *)addr;
+
+ CHECK_FULL_REGS(child->thread.regs);
+ for (i = 0; i < 32; i++) {
+ ret = put_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned int __user *tmp = (unsigned int __user *)addr;
+
+ CHECK_FULL_REGS(child->thread.regs);
+ for (i = 0; i < 32; i++) {
+ ret = get_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
}
- return -EPERM;
+ }
+ return ret;
}
-long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
- compat_ulong_t caddr, compat_ulong_t cdata)
+long compat_sys_ptrace(int request, int pid, unsigned long addr,
+ unsigned long data)
{
- unsigned long addr = caddr;
- unsigned long data = cdata;
+ struct task_struct *child;
int ret;
+ lock_kernel();
+ if (request == PTRACE_TRACEME) {
+ ret = ptrace_traceme();
+ goto out;
+ }
+
+ child = ptrace_get_task_struct(pid);
+ if (IS_ERR(child)) {
+ ret = PTR_ERR(child);
+ goto out;
+ }
+
+ if (request == PTRACE_ATTACH) {
+ ret = ptrace_attach(child);
+ goto out_tsk;
+ }
+
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0)
+ goto out_tsk;
+
switch (request) {
+ /* when I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
+ unsigned int tmp;
+ int copied;
+
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ break;
+ ret = put_user(tmp, (u32 __user *)data);
+ break;
+ }
+
/*
* Read 4 bytes of the other process' storage
* data is a pointer specifying where the user wants the
@@ -171,6 +225,19 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;
}
+ /* If I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA: {
+ unsigned int tmp;
+ tmp = data;
+ ret = 0;
+ if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
+ == sizeof(tmp))
+ break;
+ ret = -EIO;
+ break;
+ }
+
/*
* Write 4 bytes into the other process' storage
* data is the 4 bytes that the user wants written
@@ -270,17 +337,46 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;
}
- case PTRACE_GETREGS: /* Get all pt_regs from the child. */
- return copy_regset_to_user(
- child, task_user_regset_view(current), 0,
- 0, PT_REGS_COUNT * sizeof(compat_long_t),
- compat_ptr(data));
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message, (unsigned int __user *) data);
+ break;
- case PTRACE_SETREGS: /* Set all gp regs in the child. */
- return copy_regset_from_user(
- child, task_user_regset_view(current), 0,
- 0, PT_REGS_COUNT * sizeof(compat_long_t),
- compat_ptr(data));
+ case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
+ int ui;
+ if (!access_ok(VERIFY_WRITE, (void __user *)data,
+ PT_REGS_COUNT * sizeof(int))) {
+ ret = -EIO;
+ break;
+ }
+ CHECK_FULL_REGS(child->thread.regs);
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret |= __put_user(ptrace_get_reg(child, ui),
+ (unsigned int __user *) data);
+ data += sizeof(int);
+ }
+ break;
+ }
+
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ unsigned long tmp;
+ int ui;
+ if (!access_ok(VERIFY_READ, (void __user *)data,
+ PT_REGS_COUNT * sizeof(int))) {
+ ret = -EIO;
+ break;
+ }
+ CHECK_FULL_REGS(child->thread.regs);
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret = __get_user(tmp, (unsigned int __user *) data);
+ if (ret)
+ break;
+ ptrace_put_reg(child, ui, tmp);
+ data += sizeof(int);
+ }
+ break;
+ }
case PTRACE_GETFPREGS:
case PTRACE_SETFPREGS:
@@ -306,9 +402,12 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;
default:
- ret = compat_ptrace_request(child, request, addr, data);
+ ret = ptrace_request(child, request, addr, data);
break;
}
-
+out_tsk:
+ put_task_struct(child);
+out:
+ unlock_kernel();
return ret;
}
diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c
index 4b5b7ff4f78b..848a20475db8 100644
--- a/trunk/arch/powerpc/kernel/traps.c
+++ b/trunk/arch/powerpc/kernel/traps.c
@@ -54,7 +54,7 @@
#endif
#include
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+#ifdef CONFIG_DEBUGGER
int (*__debugger)(struct pt_regs *regs);
int (*__debugger_ipi)(struct pt_regs *regs);
int (*__debugger_bpt)(struct pt_regs *regs);
diff --git a/trunk/arch/powerpc/kernel/vio.c b/trunk/arch/powerpc/kernel/vio.c
index f98867252ee2..f0bad7070fb5 100644
--- a/trunk/arch/powerpc/kernel/vio.c
+++ b/trunk/arch/powerpc/kernel/vio.c
@@ -176,7 +176,7 @@ static void __devinit vio_dev_release(struct device *dev)
* Returns a pointer to the created vio_dev or NULL if node has
* NULL device_type or compatible fields.
*/
-struct vio_dev *vio_register_device_node(struct device_node *of_node)
+struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
{
struct vio_dev *viodev;
const unsigned int *unit_address;
diff --git a/trunk/arch/powerpc/mm/mem.c b/trunk/arch/powerpc/mm/mem.c
index 93a5c53e3423..e8122447f019 100644
--- a/trunk/arch/powerpc/mm/mem.c
+++ b/trunk/arch/powerpc/mm/mem.c
@@ -220,13 +220,12 @@ void __init do_init_bootmem(void)
lmb_size_bytes(&lmb.reserved, i) - 1;
if (addr < total_lowmem)
reserve_bootmem(lmb.reserved.region[i].base,
- lmb_size_bytes(&lmb.reserved, i),
- BOOTMEM_DEFAULT);
+ lmb_size_bytes(&lmb.reserved, i));
else if (lmb.reserved.region[i].base < total_lowmem) {
unsigned long adjusted_size = total_lowmem -
lmb.reserved.region[i].base;
reserve_bootmem(lmb.reserved.region[i].base,
- adjusted_size, BOOTMEM_DEFAULT);
+ adjusted_size);
}
}
#else
@@ -235,8 +234,7 @@ void __init do_init_bootmem(void)
/* reserve the sections we're already using */
for (i = 0; i < lmb.reserved.cnt; i++)
reserve_bootmem(lmb.reserved.region[i].base,
- lmb_size_bytes(&lmb.reserved, i),
- BOOTMEM_DEFAULT);
+ lmb_size_bytes(&lmb.reserved, i));
#endif
/* XXX need to clip this if using highmem? */
@@ -485,12 +483,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
*/
_tlbie(address, 0 /* 8xx doesn't care about PID */);
#endif
- /* The _PAGE_USER test should really be _PAGE_EXEC, but
- * older glibc versions execute some code from no-exec
- * pages, which for now we are supporting. If exec-only
- * pages are ever implemented, this will have to change.
- */
- if (!PageReserved(page) && (pte_val(pte) & _PAGE_USER)
+ if (!PageReserved(page)
&& !test_bit(PG_arch_1, &page->flags)) {
if (vma->vm_mm == current->active_mm) {
__flush_dcache_icache((void *) address);
diff --git a/trunk/arch/powerpc/mm/numa.c b/trunk/arch/powerpc/mm/numa.c
index a300d254aac6..c12adc3ddffd 100644
--- a/trunk/arch/powerpc/mm/numa.c
+++ b/trunk/arch/powerpc/mm/numa.c
@@ -24,8 +24,6 @@
static int numa_enabled = 1;
-static char *cmdline __initdata;
-
static int numa_debug;
#define dbg(args...) if (numa_debug) { printk(KERN_INFO args); }
@@ -41,53 +39,6 @@ static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
static int min_common_depth;
static int n_mem_addr_cells, n_mem_size_cells;
-static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
- unsigned int *nid)
-{
- unsigned long long mem;
- char *p = cmdline;
- static unsigned int fake_nid;
- static unsigned long long curr_boundary;
-
- /*
- * Modify node id, iff we started creating NUMA nodes
- * We want to continue from where we left of the last time
- */
- if (fake_nid)
- *nid = fake_nid;
- /*
- * In case there are no more arguments to parse, the
- * node_id should be the same as the last fake node id
- * (we've handled this above).
- */
- if (!p)
- return 0;
-
- mem = memparse(p, &p);
- if (!mem)
- return 0;
-
- if (mem < curr_boundary)
- return 0;
-
- curr_boundary = mem;
-
- if ((end_pfn << PAGE_SHIFT) > mem) {
- /*
- * Skip commas and spaces
- */
- while (*p == ',' || *p == ' ' || *p == '\t')
- p++;
-
- cmdline = p;
- fake_nid++;
- *nid = fake_nid;
- dbg("created new fake_node with id %d\n", fake_nid);
- return 1;
- }
- return 0;
-}
-
static void __cpuinit map_cpu_to_node(int cpu, int node)
{
numa_cpu_lookup_table[cpu] = node;
@@ -393,9 +344,6 @@ static void __init parse_drconf_memory(struct device_node *memory)
if (nid == 0xffff || nid >= MAX_NUMNODES)
nid = default_nid;
}
-
- fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT),
- &nid);
node_set_online(nid);
size = numa_enforce_memory_limit(start, lmb_size);
@@ -481,8 +429,6 @@ static int __init parse_numa_properties(void)
nid = of_node_to_nid_single(memory);
if (nid < 0)
nid = default_nid;
-
- fake_numa_create_new_node(((start + size) >> PAGE_SHIFT), &nid);
node_set_online(nid);
if (!(size = numa_enforce_memory_limit(start, size))) {
@@ -515,7 +461,7 @@ static void __init setup_nonnuma(void)
unsigned long top_of_ram = lmb_end_of_DRAM();
unsigned long total_ram = lmb_phys_mem_size();
unsigned long start_pfn, end_pfn;
- unsigned int i, nid = 0;
+ unsigned int i;
printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
top_of_ram, total_ram);
@@ -525,11 +471,9 @@ static void __init setup_nonnuma(void)
for (i = 0; i < lmb.memory.cnt; ++i) {
start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
-
- fake_numa_create_new_node(end_pfn, &nid);
- add_active_range(nid, start_pfn, end_pfn);
- node_set_online(nid);
+ add_active_range(0, start_pfn, end_pfn);
}
+ node_set_online(0);
}
void __init dump_numa_cpu_topology(void)
@@ -731,7 +675,7 @@ void __init do_init_bootmem(void)
dbg("reserve_bootmem %lx %lx\n", physbase,
size);
reserve_bootmem_node(NODE_DATA(nid), physbase,
- size, BOOTMEM_DEFAULT);
+ size);
}
}
@@ -758,10 +702,6 @@ static int __init early_numa(char *p)
if (strstr(p, "debug"))
numa_debug = 1;
- p = strstr(p, "fake=");
- if (p)
- cmdline = p + strlen("fake=");
-
return 0;
}
early_param("numa", early_numa);
diff --git a/trunk/arch/powerpc/oprofile/Makefile b/trunk/arch/powerpc/oprofile/Makefile
index 2ef6b0dddd8c..c5f64c3bd668 100644
--- a/trunk/arch/powerpc/oprofile/Makefile
+++ b/trunk/arch/powerpc/oprofile/Makefile
@@ -15,5 +15,5 @@ oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
cell/spu_profiler.o cell/vma_map.o \
cell/spu_task_sync.o
oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
-oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o
+oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/trunk/arch/powerpc/oprofile/common.c b/trunk/arch/powerpc/oprofile/common.c
index 4908dc98f9ca..a28cce1d6c24 100644
--- a/trunk/arch/powerpc/oprofile/common.c
+++ b/trunk/arch/powerpc/oprofile/common.c
@@ -202,9 +202,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
model = &op_model_7450;
break;
#endif
-#if defined(CONFIG_FSL_EMB_PERFMON)
- case PPC_OPROFILE_FSL_EMB:
- model = &op_model_fsl_emb;
+#ifdef CONFIG_FSL_BOOKE
+ case PPC_OPROFILE_BOOKE:
+ model = &op_model_fsl_booke;
break;
#endif
default:
diff --git a/trunk/arch/powerpc/oprofile/op_model_fsl_emb.c b/trunk/arch/powerpc/oprofile/op_model_fsl_booke.c
similarity index 90%
rename from trunk/arch/powerpc/oprofile/op_model_fsl_emb.c
rename to trunk/arch/powerpc/oprofile/op_model_fsl_booke.c
index 91596f6ba1f4..183a28bb1812 100644
--- a/trunk/arch/powerpc/oprofile/op_model_fsl_emb.c
+++ b/trunk/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -1,5 +1,7 @@
/*
- * Freescale Embedded oprofile support, based on ppc64 oprofile support
+ * arch/powerpc/oprofile/op_model_fsl_booke.c
+ *
+ * Freescale Book-E oprofile support, based on ppc64 oprofile support
* Copyright (C) 2004 Anton Blanchard , IBM
*
* Copyright (c) 2004 Freescale Semiconductor, Inc
@@ -20,7 +22,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -242,7 +244,7 @@ static void dump_pmcs(void)
mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
}
-static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
+static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
{
int i;
@@ -260,7 +262,7 @@ static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
return 0;
}
-static int fsl_emb_reg_setup(struct op_counter_config *ctr,
+static int fsl_booke_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -279,7 +281,7 @@ static int fsl_emb_reg_setup(struct op_counter_config *ctr,
return 0;
}
-static int fsl_emb_start(struct op_counter_config *ctr)
+static int fsl_booke_start(struct op_counter_config *ctr)
{
int i;
@@ -313,7 +315,7 @@ static int fsl_emb_start(struct op_counter_config *ctr)
return 0;
}
-static void fsl_emb_stop(void)
+static void fsl_booke_stop(void)
{
/* freeze counters */
pmc_stop_ctrs();
@@ -327,7 +329,7 @@ static void fsl_emb_stop(void)
}
-static void fsl_emb_handle_interrupt(struct pt_regs *regs,
+static void fsl_booke_handle_interrupt(struct pt_regs *regs,
struct op_counter_config *ctr)
{
unsigned long pc;
@@ -360,10 +362,10 @@ static void fsl_emb_handle_interrupt(struct pt_regs *regs,
pmc_start_ctrs(1);
}
-struct op_powerpc_model op_model_fsl_emb = {
- .reg_setup = fsl_emb_reg_setup,
- .cpu_setup = fsl_emb_cpu_setup,
- .start = fsl_emb_start,
- .stop = fsl_emb_stop,
- .handle_interrupt = fsl_emb_handle_interrupt,
+struct op_powerpc_model op_model_fsl_booke = {
+ .reg_setup = fsl_booke_reg_setup,
+ .cpu_setup = fsl_booke_cpu_setup,
+ .start = fsl_booke_start,
+ .stop = fsl_booke_stop,
+ .handle_interrupt = fsl_booke_handle_interrupt,
};
diff --git a/trunk/arch/powerpc/platforms/40x/Kconfig b/trunk/arch/powerpc/platforms/40x/Kconfig
index a9260e21451e..74f31177e47a 100644
--- a/trunk/arch/powerpc/platforms/40x/Kconfig
+++ b/trunk/arch/powerpc/platforms/40x/Kconfig
@@ -72,7 +72,6 @@ config WALNUT
default y
select 405GP
select PCI
- select OF_RTC
help
This option enables support for the IBM PPC405GP evaluation board.
diff --git a/trunk/arch/powerpc/platforms/40x/virtex.c b/trunk/arch/powerpc/platforms/40x/virtex.c
index 0422590040db..88b66444dfb2 100644
--- a/trunk/arch/powerpc/platforms/40x/virtex.c
+++ b/trunk/arch/powerpc/platforms/40x/virtex.c
@@ -37,7 +37,7 @@ static int __init virtex_probe(void)
{
unsigned long root = of_get_flat_dt_root();
- if (!of_flat_dt_is_compatible(root, "xlnx,virtex"))
+ if (!of_flat_dt_is_compatible(root, "xilinx,virtex"))
return 0;
return 1;
diff --git a/trunk/arch/powerpc/platforms/40x/walnut.c b/trunk/arch/powerpc/platforms/40x/walnut.c
index b8b257efeb77..5d9edd917f92 100644
--- a/trunk/arch/powerpc/platforms/40x/walnut.c
+++ b/trunk/arch/powerpc/platforms/40x/walnut.c
@@ -18,7 +18,6 @@
#include
#include
-#include
#include
#include
diff --git a/trunk/arch/powerpc/platforms/44x/warp.c b/trunk/arch/powerpc/platforms/44x/warp.c
index da5b7b7599db..8f01563dbd2a 100644
--- a/trunk/arch/powerpc/platforms/44x/warp.c
+++ b/trunk/arch/powerpc/platforms/44x/warp.c
@@ -137,7 +137,7 @@ static int __init pika_dtm_start(void)
}
of_node_put(np);
- fpga = ioremap(res.start, 0x24);
+ fpga = ioremap(res.start + 0x20, 4);
if (fpga == NULL)
return -ENOENT;
diff --git a/trunk/arch/powerpc/platforms/512x/Kconfig b/trunk/arch/powerpc/platforms/512x/Kconfig
deleted file mode 100644
index c6fa49e23dc0..000000000000
--- a/trunk/arch/powerpc/platforms/512x/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-config PPC_MPC512x
- bool
- select FSL_SOC
- select IPIC
- default n
-
-config PPC_MPC5121
- bool
- select PPC_MPC512x
- default n
-
-config MPC5121_ADS
- bool "Freescale MPC5121E ADS"
- depends on PPC_MULTIPLATFORM && PPC32
- select DEFAULT_UIMAGE
- select WANT_DEVICE_TREE
- select PPC_MPC5121
- help
- This option enables support for the MPC5121E ADS board.
- default n
diff --git a/trunk/arch/powerpc/platforms/512x/Makefile b/trunk/arch/powerpc/platforms/512x/Makefile
deleted file mode 100644
index 232c89f2039a..000000000000
--- a/trunk/arch/powerpc/platforms/512x/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# Makefile for the Freescale PowerPC 512x linux kernel.
-#
-obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o
diff --git a/trunk/arch/powerpc/platforms/512x/mpc5121_ads.c b/trunk/arch/powerpc/platforms/512x/mpc5121_ads.c
deleted file mode 100644
index 50bd3a319022..000000000000
--- a/trunk/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: John Rigby, , Thur Mar 29 2007
- *
- * Description:
- * MPC5121 ADS board setup
- *
- * This 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
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-/**
- * mpc512x_find_ips_freq - Find the IPS bus frequency for a device
- * @node: device node
- *
- * Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
- */
-unsigned long
-mpc512x_find_ips_freq(struct device_node *node)
-{
- struct device_node *np;
- const unsigned int *p_ips_freq = NULL;
-
- of_node_get(node);
- while (node) {
- p_ips_freq = of_get_property(node, "bus-frequency", NULL);
- if (p_ips_freq)
- break;
-
- np = of_get_parent(node);
- of_node_put(node);
- node = np;
- }
- if (node)
- of_node_put(node);
-
- return p_ips_freq ? *p_ips_freq : 0;
-}
-EXPORT_SYMBOL(mpc512x_find_ips_freq);
-
-static struct of_device_id __initdata of_bus_ids[] = {
- { .name = "soc", },
- { .name = "localbus", },
- {},
-};
-
-static void __init mpc5121_ads_declare_of_platform_devices(void)
-{
- /* Find every child of the SOC node and add it to of_platform */
- if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
- printk(KERN_ERR __FILE__ ": "
- "Error while probing of_platform bus\n");
-}
-
-static void __init mpc5121_ads_init_IRQ(void)
-{
- struct device_node *np;
-
- np = of_find_compatible_node(NULL, NULL, "fsl,ipic");
- if (!np)
- return;
-
- ipic_init(np, 0);
- of_node_put(np);
-
- /*
- * Initialize the default interrupt mapping priorities,
- * in case the boot rom changed something on us.
- */
- ipic_set_default_priority();
-}
-
-/*
- * Called very early, MMU is off, device-tree isn't unflattened
- */
-static int __init mpc5121_ads_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
-}
-
-define_machine(mpc5121_ads) {
- .name = "MPC5121 ADS",
- .probe = mpc5121_ads_probe,
- .init = mpc5121_ads_declare_of_platform_devices,
- .init_IRQ = mpc5121_ads_init_IRQ,
- .get_irq = ipic_get_irq,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/trunk/arch/powerpc/platforms/82xx/mpc8272_ads.c b/trunk/arch/powerpc/platforms/82xx/mpc8272_ads.c
index 7d3018751988..3fce6b375dbc 100644
--- a/trunk/arch/powerpc/platforms/82xx/mpc8272_ads.c
+++ b/trunk/arch/powerpc/platforms/82xx/mpc8272_ads.c
@@ -134,12 +134,13 @@ static void __init mpc8272_ads_setup_arch(void)
}
bcsr = of_iomap(np, 0);
- of_node_put(np);
if (!bcsr) {
printk(KERN_ERR "Cannot map BCSR registers\n");
return;
}
+ of_node_put(np);
+
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
setbits32(&bcsr[1], BCSR1_FETH_RST);
diff --git a/trunk/arch/powerpc/platforms/82xx/pq2fads.c b/trunk/arch/powerpc/platforms/82xx/pq2fads.c
index e1dceeec4994..68196e349994 100644
--- a/trunk/arch/powerpc/platforms/82xx/pq2fads.c
+++ b/trunk/arch/powerpc/platforms/82xx/pq2fads.c
@@ -130,12 +130,13 @@ static void __init pq2fads_setup_arch(void)
}
bcsr = of_iomap(np, 0);
- of_node_put(np);
if (!bcsr) {
printk(KERN_ERR "Cannot map BCSR registers\n");
return;
}
+ of_node_put(np);
+
/* Enable the serial and ethernet ports */
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
diff --git a/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index e7f706b624fe..9f0fd88b2b1f 100644
--- a/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -101,7 +101,7 @@ static void __init mpc832x_rdb_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
qe_reset();
- if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
+ if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
diff --git a/trunk/arch/powerpc/platforms/83xx/mpc83xx.h b/trunk/arch/powerpc/platforms/83xx/mpc83xx.h
index 68065e62fc3d..88bb748aff0d 100644
--- a/trunk/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/trunk/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -14,8 +14,6 @@
#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
-#define MPC8315_SCCR_USB_MASK 0x00c00000
-#define MPC8315_SCCR_USB_DRCM_11 0x00c00000
#define MPC837X_SCCR_USB_DRCM_11 0x00c00000
/* system i/o configuration register low */
diff --git a/trunk/arch/powerpc/platforms/83xx/usb.c b/trunk/arch/powerpc/platforms/83xx/usb.c
index 471fdd8f4108..681230a30acd 100644
--- a/trunk/arch/powerpc/platforms/83xx/usb.c
+++ b/trunk/arch/powerpc/platforms/83xx/usb.c
@@ -104,7 +104,6 @@ int mpc831x_usb_cfg(void)
u32 temp;
void __iomem *immap, *usb_regs;
struct device_node *np = NULL;
- struct device_node *immr_node = NULL;
const void *prop;
struct resource res;
int ret = 0;
@@ -125,15 +124,10 @@ int mpc831x_usb_cfg(void)
}
/* Configure clock */
- immr_node = of_get_parent(np);
- if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
- clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
- MPC8315_SCCR_USB_MASK,
- MPC8315_SCCR_USB_DRCM_11);
- else
- clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
- MPC83XX_SCCR_USB_MASK,
- MPC83XX_SCCR_USB_DRCM_11);
+ temp = in_be32(immap + MPC83XX_SCCR_OFFS);
+ temp &= ~MPC83XX_SCCR_USB_MASK;
+ temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
+ out_be32(immap + MPC83XX_SCCR_OFFS, temp);
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
if (prop && !strcmp(prop, "ulpi")) {
@@ -150,9 +144,6 @@ int mpc831x_usb_cfg(void)
iounmap(immap);
- if (immr_node)
- of_node_put(immr_node);
-
/* Map USB SOC space */
ret = of_address_to_resource(np, 0, &res);
if (ret) {
diff --git a/trunk/arch/powerpc/platforms/8xx/adder875.c b/trunk/arch/powerpc/platforms/8xx/adder875.c
index 82363e98f50e..c6bc0783c3b0 100644
--- a/trunk/arch/powerpc/platforms/8xx/adder875.c
+++ b/trunk/arch/powerpc/platforms/8xx/adder875.c
@@ -15,12 +15,12 @@
#include
#include
-#include
+#include
#include
#include
#include
-#include "mpc8xx.h"
+#include
struct cpm_pin {
int port, pin, flags;
@@ -108,7 +108,7 @@ define_machine(adder875) {
.name = "Adder MPC875",
.probe = adder875_probe,
.setup_arch = adder875_setup,
- .init_IRQ = mpc8xx_pics_init,
+ .init_IRQ = m8xx_pic_init,
.get_irq = mpc8xx_get_irq,
.restart = mpc8xx_restart,
.calibrate_decr = generic_calibrate_decr,
diff --git a/trunk/arch/powerpc/platforms/8xx/ep88xc.c b/trunk/arch/powerpc/platforms/8xx/ep88xc.c
index 7d9ac6040d63..a8dffa005775 100644
--- a/trunk/arch/powerpc/platforms/8xx/ep88xc.c
+++ b/trunk/arch/powerpc/platforms/8xx/ep88xc.c
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include "mpc8xx.h"
diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig
index fcedbec07f94..fdce10c4f074 100644
--- a/trunk/arch/powerpc/platforms/Kconfig
+++ b/trunk/arch/powerpc/platforms/Kconfig
@@ -24,7 +24,6 @@ config PPC_83xx
select MPC83xx
select IPIC
select WANT_DEVICE_TREE
- select FSL_EMB_PERFMON
config PPC_86xx
bool "Freescale 86xx"
@@ -42,7 +41,6 @@ config CLASSIC32
source "arch/powerpc/platforms/pseries/Kconfig"
source "arch/powerpc/platforms/iseries/Kconfig"
source "arch/powerpc/platforms/chrp/Kconfig"
-source "arch/powerpc/platforms/512x/Kconfig"
source "arch/powerpc/platforms/52xx/Kconfig"
source "arch/powerpc/platforms/powermac/Kconfig"
source "arch/powerpc/platforms/prep/Kconfig"
diff --git a/trunk/arch/powerpc/platforms/Kconfig.cputype b/trunk/arch/powerpc/platforms/Kconfig.cputype
index 69941ba70975..7fc41104d53e 100644
--- a/trunk/arch/powerpc/platforms/Kconfig.cputype
+++ b/trunk/arch/powerpc/platforms/Kconfig.cputype
@@ -14,7 +14,7 @@ choice
There are five families of 32 bit PowerPC chips supported.
The most common ones are the desktop and server CPUs (601, 603,
604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
- embedded 512x/52xx/82xx/83xx/86xx counterparts.
+ embedded 52xx/82xx/83xx/86xx counterparts.
The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
(85xx) each form a family of their own that is not compatible
with the others.
@@ -22,7 +22,7 @@ choice
If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
config 6xx
- bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
+ bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
select PPC_FPU
config PPC_85xx
@@ -94,7 +94,6 @@ config 8xx
bool
config E500
- select FSL_EMB_PERFMON
bool
config PPC_FPU
@@ -116,9 +115,6 @@ config FSL_BOOKE
depends on E200 || E500
default y
-config FSL_EMB_PERFMON
- bool
-
config PTE_64BIT
bool
depends on 44x || E500
@@ -225,7 +221,7 @@ config NR_CPUS
config NOT_COHERENT_CACHE
bool
- depends on 4xx || 8xx || E200 || PPC_MPC512x
+ depends on 4xx || 8xx || E200
default y
config CHECK_CACHE_COHERENCY
diff --git a/trunk/arch/powerpc/platforms/Makefile b/trunk/arch/powerpc/platforms/Makefile
index a984894466d9..6d9079da5f5a 100644
--- a/trunk/arch/powerpc/platforms/Makefile
+++ b/trunk/arch/powerpc/platforms/Makefile
@@ -11,7 +11,6 @@ endif
obj-$(CONFIG_PPC_CHRP) += chrp/
obj-$(CONFIG_40x) += 40x/
obj-$(CONFIG_44x) += 44x/
-obj-$(CONFIG_PPC_MPC512x) += 512x/
obj-$(CONFIG_PPC_MPC52xx) += 52xx/
obj-$(CONFIG_PPC_8xx) += 8xx/
obj-$(CONFIG_PPC_82xx) += 82xx/
diff --git a/trunk/arch/powerpc/platforms/cell/Kconfig b/trunk/arch/powerpc/platforms/cell/Kconfig
index 2f169991896d..3a963b4a9be0 100644
--- a/trunk/arch/powerpc/platforms/cell/Kconfig
+++ b/trunk/arch/powerpc/platforms/cell/Kconfig
@@ -54,13 +54,6 @@ config SPU_FS_64K_LS
uses 4K pages. This can improve performances of applications
using multiple SPEs by lowering the TLB pressure on them.
-config SPU_TRACE
- tristate "SPU event tracing support"
- depends on SPU_FS && MARKERS
- help
- This option allows reading a trace of spu-related events through
- the sputrace file in procfs.
-
config SPU_BASE
bool
default n
diff --git a/trunk/arch/powerpc/platforms/cell/axon_msi.c b/trunk/arch/powerpc/platforms/cell/axon_msi.c
index d95e71dee91f..095988f13bf4 100644
--- a/trunk/arch/powerpc/platforms/cell/axon_msi.c
+++ b/trunk/arch/powerpc/platforms/cell/axon_msi.c
@@ -13,7 +13,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -65,12 +65,14 @@
struct axon_msic {
struct irq_host *irq_host;
- __le32 *fifo_virt;
- dma_addr_t fifo_phys;
+ __le32 *fifo;
dcr_host_t dcr_host;
+ struct list_head list;
u32 read_offset;
};
+static LIST_HEAD(axon_msic_list);
+
static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
{
pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
@@ -92,7 +94,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
while (msic->read_offset != write_offset) {
idx = msic->read_offset / sizeof(__le32);
- msi = le32_to_cpu(msic->fifo_virt[idx]);
+ msi = le32_to_cpu(msic->fifo[idx]);
msi &= 0xFFFF;
pr_debug("axon_msi: woff %x roff %x msi %x\n",
@@ -137,7 +139,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
tmp = dn;
dn = of_find_node_by_phandle(*ph);
- of_node_put(tmp);
if (!dn) {
dev_dbg(&dev->dev,
"axon_msi: msi-translator doesn't point to a node\n");
@@ -155,6 +156,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
out_error:
of_node_put(dn);
+ of_node_put(tmp);
return msic;
}
@@ -290,24 +292,30 @@ static struct irq_host_ops msic_host_ops = {
.map = msic_host_map,
};
-static int axon_msi_shutdown(struct of_device *device)
+static int axon_msi_notify_reboot(struct notifier_block *nb,
+ unsigned long code, void *data)
{
- struct axon_msic *msic = device->dev.platform_data;
+ struct axon_msic *msic;
u32 tmp;
- pr_debug("axon_msi: disabling %s\n",
- msic->irq_host->of_node->full_name);
- tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
- tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
- msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
+ list_for_each_entry(msic, &axon_msic_list, list) {
+ pr_debug("axon_msi: disabling %s\n",
+ msic->irq_host->of_node->full_name);
+ tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
+ tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+ msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
+ }
return 0;
}
-static int axon_msi_probe(struct of_device *device,
- const struct of_device_id *device_id)
+static struct notifier_block axon_msi_reboot_notifier = {
+ .notifier_call = axon_msi_notify_reboot
+};
+
+static int axon_msi_setup_one(struct device_node *dn)
{
- struct device_node *dn = device->node;
+ struct page *page;
struct axon_msic *msic;
unsigned int virq;
int dcr_base, dcr_len;
@@ -338,14 +346,16 @@ static int axon_msi_probe(struct of_device *device,
goto out_free_msic;
}
- msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
- &msic->fifo_phys, GFP_KERNEL);
- if (!msic->fifo_virt) {
+ page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
+ get_order(MSIC_FIFO_SIZE_BYTES));
+ if (!page) {
printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
dn->full_name);
goto out_free_msic;
}
+ msic->fifo = page_address(page);
+
msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
NR_IRQS, &msic_host_ops, 0);
if (!msic->irq_host) {
@@ -368,18 +378,14 @@ static int axon_msi_probe(struct of_device *device,
pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
/* Enable the MSIC hardware */
- msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
+ msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
- msic->fifo_phys & 0xFFFFFFFF);
+ (u64)msic->fifo & 0xFFFFFFFF);
msic_dcr_write(msic, MSIC_CTRL_REG,
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
MSIC_CTRL_FIFO_SIZE);
- device->dev.platform_data = msic;
-
- ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
- ppc_md.msi_check_device = axon_msi_check_device;
+ list_add(&msic->list, &axon_msic_list);
printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
@@ -388,8 +394,7 @@ static int axon_msi_probe(struct of_device *device,
out_free_host:
kfree(msic->irq_host);
out_free_fifo:
- dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
- msic->fifo_phys);
+ __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
out_free_msic:
kfree(msic);
out:
@@ -397,24 +402,28 @@ static int axon_msi_probe(struct of_device *device,
return -1;
}
-static const struct of_device_id axon_msi_device_id[] = {
- {
- .compatible = "ibm,axon-msic"
- },
- {}
-};
+static int axon_msi_init(void)
+{
+ struct device_node *dn;
+ int found = 0;
-static struct of_platform_driver axon_msi_driver = {
- .match_table = axon_msi_device_id,
- .probe = axon_msi_probe,
- .shutdown = axon_msi_shutdown,
- .driver = {
- .name = "axon-msi"
- },
-};
+ pr_debug("axon_msi: initialising ...\n");
-static int __init axon_msi_init(void)
-{
- return of_register_platform_driver(&axon_msi_driver);
+ for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
+ if (axon_msi_setup_one(dn) == 0)
+ found++;
+ }
+
+ if (found) {
+ ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+ ppc_md.msi_check_device = axon_msi_check_device;
+
+ register_reboot_notifier(&axon_msi_reboot_notifier);
+
+ pr_debug("axon_msi: registered callbacks!\n");
+ }
+
+ return 0;
}
-subsys_initcall(axon_msi_init);
+arch_initcall(axon_msi_init);
diff --git a/trunk/arch/powerpc/platforms/cell/setup.c b/trunk/arch/powerpc/platforms/cell/setup.c
index a7f609b3b876..e6534b519c9a 100644
--- a/trunk/arch/powerpc/platforms/cell/setup.c
+++ b/trunk/arch/powerpc/platforms/cell/setup.c
@@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
}
return 0;
}
-machine_subsys_initcall(cell, cell_publish_devices);
+machine_device_initcall(cell, cell_publish_devices);
static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
{
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/Makefile b/trunk/arch/powerpc/platforms/cell/spufs/Makefile
index 99610a6361f2..d3a349fb42e5 100644
--- a/trunk/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/trunk/arch/powerpc/platforms/cell/spufs/Makefile
@@ -4,8 +4,6 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o
spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
spufs-y += switch.o fault.o lscsa_alloc.o
-obj-$(CONFIG_SPU_TRACE) += sputrace.o
-
# Rules to build switch.o with the help of SPU tool chain
SPU_CROSS := spu-
SPU_CC := $(SPU_CROSS)gcc
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/file.c b/trunk/arch/powerpc/platforms/cell/spufs/file.c
index 1018acd1746b..3fcd06418b01 100644
--- a/trunk/arch/powerpc/platforms/cell/spufs/file.c
+++ b/trunk/arch/powerpc/platforms/cell/spufs/file.c
@@ -29,7 +29,6 @@
#include
#include
#include
-#include
#include
#include
@@ -359,8 +358,6 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
struct spu_context *ctx = vma->vm_file->private_data;
unsigned long area, offset = address - vma->vm_start;
- spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx);
-
offset += vma->vm_pgoff << PAGE_SHIFT;
if (offset >= ps_size)
return NOPFN_SIGBUS;
@@ -378,14 +375,11 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
if (ctx->state == SPU_STATE_SAVED) {
up_read(¤t->mm->mmap_sem);
- spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx);
spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE);
- spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu);
down_read(¤t->mm->mmap_sem);
} else {
area = ctx->spu->problem_phys + ps_offs;
vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
- spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu);
}
spu_release(ctx);
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c
index 90784c029f25..c0e968a4c211 100644
--- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c
@@ -322,7 +322,7 @@ static struct spu_context *
spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
struct file *filp)
{
- struct spu_context *tmp, *neighbor, *err;
+ struct spu_context *tmp, *neighbor;
int count, node;
int aff_supp;
@@ -354,15 +354,11 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
!list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
!list_entry(neighbor->aff_list.next, struct spu_context,
- aff_list)->aff_head) {
- err = ERR_PTR(-EEXIST);
- goto out_put_neighbor;
- }
+ aff_list)->aff_head)
+ return ERR_PTR(-EEXIST);
- if (gang != neighbor->gang) {
- err = ERR_PTR(-EINVAL);
- goto out_put_neighbor;
- }
+ if (gang != neighbor->gang)
+ return ERR_PTR(-EINVAL);
count = 1;
list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
@@ -376,17 +372,11 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
break;
}
- if (node == MAX_NUMNODES) {
- err = ERR_PTR(-EEXIST);
- goto out_put_neighbor;
- }
+ if (node == MAX_NUMNODES)
+ return ERR_PTR(-EEXIST);
}
return neighbor;
-
-out_put_neighbor:
- put_spu_context(neighbor);
- return err;
}
static void
@@ -464,12 +454,9 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
if (ret)
goto out_aff_unlock;
- if (affinity) {
+ if (affinity)
spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
neighbor);
- if (neighbor)
- put_spu_context(neighbor);
- }
/*
* get references for dget and mntget, will be released
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/run.c b/trunk/arch/powerpc/platforms/cell/spufs/run.c
index b4814c740d8a..c01a09da1e56 100644
--- a/trunk/arch/powerpc/platforms/cell/spufs/run.c
+++ b/trunk/arch/powerpc/platforms/cell/spufs/run.c
@@ -410,11 +410,8 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
* since we have TIF_SINGLESTEP set, thus the kernel will do
* it upon return from the syscall anyawy
*/
- if (unlikely(status & SPU_STATUS_SINGLE_STEP))
- ret = -ERESTARTSYS;
-
- else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP)
- && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) {
+ if ((status & SPU_STATUS_STOPPED_BY_STOP)
+ && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
force_sig(SIGTRAP, current);
ret = -ERESTARTSYS;
}
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/sched.c b/trunk/arch/powerpc/platforms/cell/spufs/sched.c
index 5915343e2599..00d914232af1 100644
--- a/trunk/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/trunk/arch/powerpc/platforms/cell/spufs/sched.c
@@ -39,7 +39,6 @@
#include
#include
#include
-#include
#include
#include
@@ -217,8 +216,8 @@ void do_notify_spus_active(void)
*/
static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
{
- spu_context_trace(spu_bind_context__enter, ctx, spu);
-
+ pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
+ spu->number, spu->node);
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
if (ctx->flags & SPU_CREATE_NOSCHED)
@@ -400,8 +399,8 @@ static int has_affinity(struct spu_context *ctx)
*/
static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
{
- spu_context_trace(spu_unbind_context__enter, ctx, spu);
-
+ pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
+ spu->pid, spu->number, spu->node);
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
if (spu->ctx->flags & SPU_CREATE_NOSCHED)
@@ -529,8 +528,6 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
struct spu *spu, *aff_ref_spu;
int node, n;
- spu_context_nospu_trace(spu_get_idle__enter, ctx);
-
if (ctx->gang) {
mutex_lock(&ctx->gang->aff_mutex);
if (has_affinity(ctx)) {
@@ -549,7 +546,8 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
ctx->gang->aff_ref_spu = NULL;
mutex_unlock(&ctx->gang->aff_mutex);
- goto not_found;
+
+ return NULL;
}
mutex_unlock(&ctx->gang->aff_mutex);
}
@@ -567,14 +565,12 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
mutex_unlock(&cbe_spu_info[node].list_mutex);
}
- not_found:
- spu_context_nospu_trace(spu_get_idle__not_found, ctx);
return NULL;
found:
spu->alloc_state = SPU_USED;
mutex_unlock(&cbe_spu_info[node].list_mutex);
- spu_context_trace(spu_get_idle__found, ctx, spu);
+ pr_debug("Got SPU %d %d\n", spu->number, spu->node);
spu_init_channels(spu);
return spu;
}
@@ -591,8 +587,6 @@ static struct spu *find_victim(struct spu_context *ctx)
struct spu *spu;
int node, n;
- spu_context_nospu_trace(spu_find_vitim__enter, ctx);
-
/*
* Look for a possible preemption candidate on the local node first.
* If there is no candidate look at the other nodes. This isn't
@@ -646,8 +640,6 @@ static struct spu *find_victim(struct spu_context *ctx)
goto restart;
}
- spu_context_trace(__spu_deactivate__unload, ctx, spu);
-
mutex_lock(&cbe_spu_info[node].list_mutex);
cbe_spu_info[node].nr_active--;
spu_unbind_context(spu, victim);
@@ -830,7 +822,6 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
*/
void spu_deactivate(struct spu_context *ctx)
{
- spu_context_nospu_trace(spu_deactivate__enter, ctx);
__spu_deactivate(ctx, 1, MAX_PRIO);
}
@@ -844,7 +835,6 @@ void spu_deactivate(struct spu_context *ctx)
*/
void spu_yield(struct spu_context *ctx)
{
- spu_context_nospu_trace(spu_yield__enter, ctx);
if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
mutex_lock(&ctx->state_mutex);
__spu_deactivate(ctx, 0, MAX_PRIO);
@@ -874,15 +864,11 @@ static noinline void spusched_tick(struct spu_context *ctx)
goto out;
spu = ctx->spu;
-
- spu_context_trace(spusched_tick__preempt, ctx, spu);
-
new = grab_runnable_context(ctx->prio + 1, spu->node);
if (new) {
spu_unschedule(spu, ctx);
spu_add_to_rq(ctx);
} else {
- spu_context_nospu_trace(spusched_tick__newslice, ctx);
ctx->time_slice++;
}
out:
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h
index 795a1b52538b..0e114038ea6f 100644
--- a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -325,9 +325,4 @@ extern void spu_free_lscsa(struct spu_state *csa);
extern void spuctx_switch_state(struct spu_context *ctx,
enum spu_utilization_state new_state);
-#define spu_context_trace(name, ctx, spu) \
- trace_mark(name, "%p %p", ctx, spu);
-#define spu_context_nospu_trace(name, ctx) \
- trace_mark(name, "%p", ctx);
-
#endif
diff --git a/trunk/arch/powerpc/platforms/cell/spufs/sputrace.c b/trunk/arch/powerpc/platforms/cell/spufs/sputrace.c
deleted file mode 100644
index 2b1953f6f12e..000000000000
--- a/trunk/arch/powerpc/platforms/cell/spufs/sputrace.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2007 IBM Deutschland Entwicklung GmbH
- * Released under GPL v2.
- *
- * Partially based on net/ipv4/tcp_probe.c.
- *
- * Simple tracing facility for spu contexts.
- */
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "spufs.h"
-
-struct spu_probe {
- const char *name;
- const char *format;
- marker_probe_func *probe_func;
-};
-
-struct sputrace {
- ktime_t tstamp;
- int owner_tid; /* owner */
- int curr_tid;
- const char *name;
- int number;
-};
-
-static int bufsize __read_mostly = 16384;
-MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)");
-module_param(bufsize, int, 0);
-
-
-static DEFINE_SPINLOCK(sputrace_lock);
-static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait);
-static ktime_t sputrace_start;
-static unsigned long sputrace_head, sputrace_tail;
-static struct sputrace *sputrace_log;
-
-static int sputrace_used(void)
-{
- return (sputrace_head - sputrace_tail) % bufsize;
-}
-
-static inline int sputrace_avail(void)
-{
- return bufsize - sputrace_used();
-}
-
-static int sputrace_sprint(char *tbuf, int n)
-{
- const struct sputrace *t = sputrace_log + sputrace_tail % bufsize;
- struct timespec tv =
- ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start));
-
- return snprintf(tbuf, n,
- "[%lu.%09lu] %d: %s (thread = %d, spu = %d)\n",
- (unsigned long) tv.tv_sec,
- (unsigned long) tv.tv_nsec,
- t->owner_tid,
- t->name,
- t->curr_tid,
- t->number);
-}
-
-static ssize_t sputrace_read(struct file *file, char __user *buf,
- size_t len, loff_t *ppos)
-{
- int error = 0, cnt = 0;
-
- if (!buf || len < 0)
- return -EINVAL;
-
- while (cnt < len) {
- char tbuf[128];
- int width;
-
- error = wait_event_interruptible(sputrace_wait,
- sputrace_used() > 0);
- if (error)
- break;
-
- spin_lock(&sputrace_lock);
- if (sputrace_head == sputrace_tail) {
- spin_unlock(&sputrace_lock);
- continue;
- }
-
- width = sputrace_sprint(tbuf, sizeof(tbuf));
- if (width < len)
- sputrace_tail = (sputrace_tail + 1) % bufsize;
- spin_unlock(&sputrace_lock);
-
- if (width >= len)
- break;
-
- error = copy_to_user(buf + cnt, tbuf, width);
- if (error)
- break;
- cnt += width;
- }
-
- return cnt == 0 ? error : cnt;
-}
-
-static int sputrace_open(struct inode *inode, struct file *file)
-{
- spin_lock(&sputrace_lock);
- sputrace_head = sputrace_tail = 0;
- sputrace_start = ktime_get();
- spin_unlock(&sputrace_lock);
-
- return 0;
-}
-
-static const struct file_operations sputrace_fops = {
- .owner = THIS_MODULE,
- .open = sputrace_open,
- .read = sputrace_read,
-};
-
-static void sputrace_log_item(const char *name, struct spu_context *ctx,
- struct spu *spu)
-{
- spin_lock(&sputrace_lock);
- if (sputrace_avail() > 1) {
- struct sputrace *t = sputrace_log + sputrace_head;
-
- t->tstamp = ktime_get();
- t->owner_tid = ctx->tid;
- t->name = name;
- t->curr_tid = current->pid;
- t->number = spu ? spu->number : -1;
-
- sputrace_head = (sputrace_head + 1) % bufsize;
- } else {
- printk(KERN_WARNING
- "sputrace: lost samples due to full buffer.\n");
- }
- spin_unlock(&sputrace_lock);
-
- wake_up(&sputrace_wait);
-}
-
-static void spu_context_event(const struct marker *mdata,
- void *private, const char *format, ...)
-{
- struct spu_probe *p = mdata->private;
- va_list ap;
- struct spu_context *ctx;
- struct spu *spu;
-
- va_start(ap, format);
- ctx = va_arg(ap, struct spu_context *);
- spu = va_arg(ap, struct spu *);
-
- sputrace_log_item(p->name, ctx, spu);
- va_end(ap);
-}
-
-static void spu_context_nospu_event(const struct marker *mdata,
- void *private, const char *format, ...)
-{
- struct spu_probe *p = mdata->private;
- va_list ap;
- struct spu_context *ctx;
-
- va_start(ap, format);
- ctx = va_arg(ap, struct spu_context *);
-
- sputrace_log_item(p->name, ctx, NULL);
- va_end(ap);
-}
-
-struct spu_probe spu_probes[] = {
- { "spu_bind_context__enter", "%p %p", spu_context_event },
- { "spu_unbind_context__enter", "%p %p", spu_context_event },
- { "spu_get_idle__enter", "%p", spu_context_nospu_event },
- { "spu_get_idle__found", "%p %p", spu_context_event },
- { "spu_get_idle__not_found", "%p", spu_context_nospu_event },
- { "spu_find_victim__enter", "%p", spu_context_nospu_event },
- { "spusched_tick__preempt", "%p %p", spu_context_event },
- { "spusched_tick__newslice", "%p", spu_context_nospu_event },
- { "spu_yield__enter", "%p", spu_context_nospu_event },
- { "spu_deactivate__enter", "%p", spu_context_nospu_event },
- { "__spu_deactivate__unload", "%p %p", spu_context_event },
- { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event },
- { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event },
- { "spufs_ps_nopfn__wake", "%p %p", spu_context_event },
- { "spufs_ps_nopfn__insert", "%p %p", spu_context_event },
- { "spu_acquire_saved__enter", "%p", spu_context_nospu_event },
- { "destroy_spu_context__enter", "%p", spu_context_nospu_event },
-};
-
-static int __init sputrace_init(void)
-{
- struct proc_dir_entry *entry;
- int i, error = -ENOMEM;
-
- sputrace_log = kcalloc(sizeof(struct sputrace),
- bufsize, GFP_KERNEL);
- if (!sputrace_log)
- goto out;
-
- entry = create_proc_entry("sputrace", S_IRUSR, NULL);
- if (!entry)
- goto out_free_log;
- entry->proc_fops = &sputrace_fops;
-
- for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
- struct spu_probe *p = &spu_probes[i];
-
- error = marker_probe_register(p->name, p->format,
- p->probe_func, p);
- if (error)
- printk(KERN_INFO "Unable to register probe %s\n",
- p->name);
-
- error = marker_arm(p->name);
- if (error)
- printk(KERN_INFO "Unable to arm probe %s\n", p->name);
- }
-
- return 0;
-
-out_free_log:
- kfree(sputrace_log);
-out:
- return -ENOMEM;
-}
-
-static void __exit sputrace_exit(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
- marker_probe_unregister(spu_probes[i].name);
-
- remove_proc_entry("sputrace", NULL);
- kfree(sputrace_log);
-}
-
-module_init(sputrace_init);
-module_exit(sputrace_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c b/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c
index 8864e4884980..e12e9d298716 100644
--- a/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c
+++ b/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c
@@ -132,18 +132,33 @@ static void __init storcenter_init_IRQ(void)
paddr = (phys_addr_t)of_translate_address(dnp, prop);
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET,
- 16, 32, " OpenPIC ");
+ 4, 32, " EPIC ");
of_node_put(dnp);
BUG_ON(mpic == NULL);
+ /* PCI IRQs */
/*
- * 16 Serial Interrupts followed by 16 Internal Interrupts.
- * I2C is the second internal, so it is at 17, 0x11020.
+ * 2.6.12 patch:
+ * openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200);
+ * openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120);
+ * first_irq, num_irqs, __iomem first_ISR
+ * o_ss: i, src: 0, fdf50200
+ * o_ss: i, src: 1, fdf50220
+ * o_ss: i, src: 2, fdf50240
+ * o_ss: i, src: 3, fdf50260
+ * o_ss: i, src: 4, fdf50280
+ * o_ss: i, src: 5, fdf51120
+ * o_ss: i, src: 6, fdf51140
*/
mpic_assign_isu(mpic, 0, paddr + 0x10200);
- mpic_assign_isu(mpic, 1, paddr + 0x11000);
+ mpic_assign_isu(mpic, 1, paddr + 0x10220);
+ mpic_assign_isu(mpic, 2, paddr + 0x10240);
+ mpic_assign_isu(mpic, 3, paddr + 0x10260);
+ mpic_assign_isu(mpic, 4, paddr + 0x10280);
+ mpic_assign_isu(mpic, 5, paddr + 0x11120);
+ mpic_assign_isu(mpic, 6, paddr + 0x11140);
mpic_init(mpic);
}
@@ -163,7 +178,7 @@ static int __init storcenter_probe(void)
{
unsigned long root = of_get_flat_dt_root();
- return of_flat_dt_is_compatible(root, "iomega,storcenter");
+ return of_flat_dt_is_compatible(root, "storcenter");
}
define_machine(storcenter){
diff --git a/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c b/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 1f032483c026..c4ad54e0f288 100644
--- a/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -58,7 +58,7 @@ static void pseries_mach_cpu_die(void)
{
local_irq_disable();
idle_task_exit();
- xics_teardown_cpu();
+ xics_teardown_cpu(0);
unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
rtas_stop_self();
/* Should never get here... */
diff --git a/trunk/arch/powerpc/platforms/pseries/kexec.c b/trunk/arch/powerpc/platforms/pseries/kexec.c
index e9dd5fe081c9..412a5e7aff2d 100644
--- a/trunk/arch/powerpc/platforms/pseries/kexec.c
+++ b/trunk/arch/powerpc/platforms/pseries/kexec.c
@@ -54,7 +54,7 @@ void __init setup_kexec_cpu_down_mpic(void)
static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
{
pseries_kexec_cpu_down(crash_shutdown, secondary);
- xics_kexec_teardown_cpu(secondary);
+ xics_teardown_cpu(secondary);
}
void __init setup_kexec_cpu_down_xics(void)
diff --git a/trunk/arch/powerpc/platforms/pseries/reconfig.c b/trunk/arch/powerpc/platforms/pseries/reconfig.c
index 2800fced8c7c..c02f8742c54d 100644
--- a/trunk/arch/powerpc/platforms/pseries/reconfig.c
+++ b/trunk/arch/powerpc/platforms/pseries/reconfig.c
@@ -167,7 +167,6 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
if ((child = of_get_next_child(np, NULL))) {
of_node_put(child);
- of_node_put(parent);
return -EBUSY;
}
diff --git a/trunk/arch/powerpc/platforms/pseries/xics.c b/trunk/arch/powerpc/platforms/pseries/xics.c
index ca52b587166d..8f8dd9c3ca6b 100644
--- a/trunk/arch/powerpc/platforms/pseries/xics.c
+++ b/trunk/arch/powerpc/platforms/pseries/xics.c
@@ -160,46 +160,6 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
/* High level handlers and init code */
-static void xics_update_irq_servers(void)
-{
- int i, j;
- struct device_node *np;
- u32 ilen;
- const u32 *ireg, *isize;
- u32 hcpuid;
-
- /* Find the server numbers for the boot cpu. */
- np = of_get_cpu_node(boot_cpuid, NULL);
- BUG_ON(!np);
-
- ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
- if (!ireg) {
- of_node_put(np);
- return;
- }
-
- i = ilen / sizeof(int);
- hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
- /* Global interrupt distribution server is specified in the last
- * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
- * entry fom this property for current boot cpu id and use it as
- * default distribution server
- */
- for (j = 0; j < i; j += 2) {
- if (ireg[j] == hcpuid) {
- default_server = hcpuid;
- default_distrib_server = ireg[j+1];
-
- isize = of_get_property(np,
- "ibm,interrupt-server#-size", NULL);
- if (isize)
- interrupt_server_size = *isize;
- }
- }
-
- of_node_put(np);
-}
#ifdef CONFIG_SMP
static int get_irq_server(unsigned int virq, unsigned int strict_check)
@@ -209,9 +169,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
cpumask_t cpumask = irq_desc[virq].affinity;
cpumask_t tmp = CPU_MASK_NONE;
- if (! cpu_isset(default_server, cpu_online_map))
- xics_update_irq_servers();
-
if (!distribute_irqs)
return default_server;
@@ -701,11 +658,39 @@ static void __init xics_setup_8259_cascade(void)
set_irq_chained_handler(cascade, pseries_8259_cascade);
}
+static struct device_node *cpuid_to_of_node(int cpu)
+{
+ struct device_node *np;
+ u32 hcpuid = get_hard_smp_processor_id(cpu);
+
+ for_each_node_by_type(np, "cpu") {
+ int i, len;
+ const u32 *intserv;
+
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
+ &len);
+
+ if (!intserv)
+ intserv = of_get_property(np, "reg", &len);
+
+ i = len / sizeof(u32);
+
+ while (i--)
+ if (intserv[i] == hcpuid)
+ return np;
+ }
+
+ return NULL;
+}
+
void __init xics_init_IRQ(void)
{
+ int i, j;
struct device_node *np;
- u32 indx = 0;
+ u32 ilen, indx = 0;
+ const u32 *ireg, *isize;
int found = 0;
+ u32 hcpuid;
ppc64_boot_msg(0x20, "XICS Init");
@@ -724,7 +709,34 @@ void __init xics_init_IRQ(void)
return;
xics_init_host();
- xics_update_irq_servers();
+
+ /* Find the server numbers for the boot cpu. */
+ np = cpuid_to_of_node(boot_cpuid);
+ BUG_ON(!np);
+ ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+ if (!ireg)
+ goto skip_gserver_check;
+ i = ilen / sizeof(int);
+ hcpuid = get_hard_smp_processor_id(boot_cpuid);
+
+ /* Global interrupt distribution server is specified in the last
+ * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+ * entry fom this property for current boot cpu id and use it as
+ * default distribution server
+ */
+ for (j = 0; j < i; j += 2) {
+ if (ireg[j] == hcpuid) {
+ default_server = hcpuid;
+ default_distrib_server = ireg[j+1];
+
+ isize = of_get_property(np,
+ "ibm,interrupt-server#-size", NULL);
+ if (isize)
+ interrupt_server_size = *isize;
+ }
+ }
+skip_gserver_check:
+ of_node_put(np);
if (firmware_has_feature(FW_FEATURE_LPAR))
ppc_md.get_irq = xics_get_irq_lpar;
@@ -763,9 +775,11 @@ void xics_request_IPIs(void)
}
#endif /* CONFIG_SMP */
-void xics_teardown_cpu()
+void xics_teardown_cpu(int secondary)
{
int cpu = smp_processor_id();
+ unsigned int ipi;
+ struct irq_desc *desc;
xics_set_cpu_priority(0);
@@ -776,17 +790,9 @@ void xics_teardown_cpu()
lpar_qirr_info(cpu, 0xff);
else
direct_qirr_info(cpu, 0xff);
-}
-
-void xics_kexec_teardown_cpu(int secondary)
-{
- unsigned int ipi;
- struct irq_desc *desc;
-
- xics_teardown_cpu();
/*
- * we need to EOI the IPI
+ * we need to EOI the IPI if we got here from kexec down IPI
*
* probably need to check all the other interrupts too
* should we be flagging idle loop instead?
@@ -874,8 +880,8 @@ void xics_migrate_irqs_away(void)
virq, cpu);
/* Reset affinity to all cpus */
- irq_desc[virq].affinity = CPU_MASK_ALL;
desc->chip->set_affinity(virq, CPU_MASK_ALL);
+ irq_desc[irq].affinity = CPU_MASK_ALL;
unlock:
spin_unlock_irqrestore(&desc->lock, flags);
}
diff --git a/trunk/arch/powerpc/platforms/pseries/xics.h b/trunk/arch/powerpc/platforms/pseries/xics.h
index c26bcff47b6d..9ffd809d29e2 100644
--- a/trunk/arch/powerpc/platforms/pseries/xics.h
+++ b/trunk/arch/powerpc/platforms/pseries/xics.h
@@ -16,8 +16,7 @@
extern void xics_init_IRQ(void);
extern void xics_setup_cpu(void);
-extern void xics_teardown_cpu(void);
-extern void xics_kexec_teardown_cpu(int secondary);
+extern void xics_teardown_cpu(int secondary);
extern void xics_cause_IPI(int cpu);
extern void xics_request_IPIs(void);
extern void xics_migrate_irqs_away(void);
diff --git a/trunk/arch/powerpc/sysdev/dcr.c b/trunk/arch/powerpc/sysdev/dcr.c
index 437e48d3ae33..427027c7ea0f 100644
--- a/trunk/arch/powerpc/sysdev/dcr.c
+++ b/trunk/arch/powerpc/sysdev/dcr.c
@@ -137,6 +137,5 @@ void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
h.token = NULL;
}
EXPORT_SYMBOL_GPL(dcr_unmap);
-#else /* defined(CONFIG_PPC_DCR_NATIVE) */
-DEFINE_SPINLOCK(dcr_ind_lock);
-#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */
+
+#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */
diff --git a/trunk/arch/powerpc/sysdev/fsl_soc.c b/trunk/arch/powerpc/sysdev/fsl_soc.c
index 2c5388ce902a..e48b20e934ca 100644
--- a/trunk/arch/powerpc/sysdev/fsl_soc.c
+++ b/trunk/arch/powerpc/sysdev/fsl_soc.c
@@ -1342,7 +1342,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
if (ret)
goto unreg;
- ret = platform_device_add(pdev);
+ ret = platform_device_register(pdev);
if (ret)
goto unreg;
diff --git a/trunk/arch/powerpc/sysdev/mpc8xx_pic.c b/trunk/arch/powerpc/sysdev/mpc8xx_pic.c
index 5d2d5522ef41..0e74a4bd9827 100644
--- a/trunk/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/trunk/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -174,19 +174,15 @@ int mpc8xx_pic_init(void)
goto out;
siu_reg = ioremap(res.start, res.end - res.start + 1);
- if (siu_reg == NULL) {
- ret = -EINVAL;
- goto out;
- }
+ if (siu_reg == NULL)
+ return -EINVAL;
- mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
+ mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR,
64, &mpc8xx_pic_host_ops, 64);
if (mpc8xx_pic_host == NULL) {
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
ret = -ENOMEM;
- goto out;
}
- return 0;
out:
of_node_put(np);
diff --git a/trunk/arch/powerpc/sysdev/qe_lib/qe.c b/trunk/arch/powerpc/sysdev/qe_lib/qe.c
index 6efbd5e5bb1b..5ef844da9355 100644
--- a/trunk/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/trunk/arch/powerpc/sysdev/qe_lib/qe.c
@@ -66,7 +66,7 @@ phys_addr_t get_qe_base(void)
{
struct device_node *qe;
unsigned int size;
- const u32 *prop;
+ const void *prop;
if (qebase != -1)
return qebase;
@@ -79,8 +79,7 @@ phys_addr_t get_qe_base(void)
}
prop = of_get_property(qe, "reg", &size);
- if (prop && size >= sizeof(*prop))
- qebase = of_translate_address(qe, prop);
+ qebase = of_translate_address(qe, prop);
of_node_put(qe);
return qebase;
@@ -173,9 +172,10 @@ unsigned int get_brg_clk(void)
}
prop = of_get_property(qe, "brg-frequency", &size);
- if (prop && size == sizeof(*prop))
- brg_clk = *prop;
+ if (!prop || size != sizeof(*prop))
+ return brg_clk;
+ brg_clk = *prop;
of_node_put(qe);
return brg_clk;
diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c
index f9f8779022a0..29ae165d1749 100644
--- a/trunk/arch/s390/kernel/setup.c
+++ b/trunk/arch/s390/kernel/setup.c
@@ -649,24 +649,21 @@ setup_memory(void)
/*
* Reserve memory used for lowcore/command line/kernel image.
*/
- reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT);
+ reserve_bootmem(0, (unsigned long)_ehead);
reserve_bootmem((unsigned long)_stext,
- PFN_PHYS(start_pfn) - (unsigned long)_stext,
- BOOTMEM_DEFAULT);
+ PFN_PHYS(start_pfn) - (unsigned long)_stext);
/*
* Reserve the bootmem bitmap itself as well. We do this in two
* steps (first step was init_bootmem()) because this catches
* the (very unlikely) case of us accidentally initializing the
* bootmem allocator with an invalid RAM area.
*/
- reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
#ifdef CONFIG_BLK_DEV_INITRD
if (INITRD_START && INITRD_SIZE) {
if (INITRD_START + INITRD_SIZE <= memory_end) {
- reserve_bootmem(INITRD_START, INITRD_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start = INITRD_START;
initrd_end = initrd_start + INITRD_SIZE;
} else {
diff --git a/trunk/arch/sh/kernel/setup.c b/trunk/arch/sh/kernel/setup.c
index 18a5baf2cbad..855cdf9d85b1 100644
--- a/trunk/arch/sh/kernel/setup.c
+++ b/trunk/arch/sh/kernel/setup.c
@@ -140,26 +140,18 @@ static void __init reserve_crashkernel(void)
ret = parse_crashkernel(boot_command_line, free_mem,
&crash_size, &crash_base);
if (ret == 0 && crash_size) {
- if (crash_base <= 0) {
+ if (crash_base > 0) {
+ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+ "for crashkernel (System RAM: %ldMB)\n",
+ (unsigned long)(crash_size >> 20),
+ (unsigned long)(crash_base >> 20),
+ (unsigned long)(free_mem >> 20));
+ crashk_res.start = crash_base;
+ crashk_res.end = crash_base + crash_size - 1;
+ reserve_bootmem(crash_base, crash_size);
+ } else
printk(KERN_INFO "crashkernel reservation failed - "
"you have to specify a base address\n");
- return;
- }
-
- if (reserve_bootmem(crash_base, crash_size,
- BOOTMEM_EXCLUSIVE) < 0) {
- printk(KERN_INFO "crashkernel reservation failed - "
- "memory is in use\n");
- return;
- }
-
- printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
- "for crashkernel (System RAM: %ldMB)\n",
- (unsigned long)(crash_size >> 20),
- (unsigned long)(crash_base >> 20),
- (unsigned long)(free_mem >> 20));
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
}
}
#else
@@ -192,14 +184,13 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
* an invalid RAM area.
*/
reserve_bootmem(__MEMORY_START+PAGE_SIZE,
- (PFN_PHYS(free_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START,
- BOOTMEM_DEFAULT);
+ (PFN_PHYS(free_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
* enabling clean reboots, SMP operation, laptop functions.
*/
- reserve_bootmem(__MEMORY_START, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem(__MEMORY_START, PAGE_SIZE);
sparse_memory_present_with_active_regions(0);
@@ -209,7 +200,7 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
reserve_bootmem(INITRD_START + __MEMORY_START,
- INITRD_SIZE, BOOTMEM_DEFAULT);
+ INITRD_SIZE);
initrd_start = INITRD_START + PAGE_OFFSET +
__MEMORY_START;
initrd_end = initrd_start + INITRD_SIZE;
diff --git a/trunk/arch/sh/mm/numa.c b/trunk/arch/sh/mm/numa.c
index 2de7302724fc..8aff065dd307 100644
--- a/trunk/arch/sh/mm/numa.c
+++ b/trunk/arch/sh/mm/numa.c
@@ -80,9 +80,9 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
/* Reserve the pgdat and bootmap space with the bootmem allocator */
reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
- sizeof(struct pglist_data), BOOTMEM_DEFAULT);
+ sizeof(struct pglist_data));
reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
- bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
+ bootmap_pages << PAGE_SHIFT);
/* It's up */
node_set_online(nid);
diff --git a/trunk/arch/sparc/mm/init.c b/trunk/arch/sparc/mm/init.c
index b89837accc88..a1bef07755a9 100644
--- a/trunk/arch/sparc/mm/init.c
+++ b/trunk/arch/sparc/mm/init.c
@@ -259,7 +259,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
if (initrd_start) {
/* Reserve the initrd image area. */
size = initrd_end - initrd_start;
- reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
+ reserve_bootmem(initrd_start, size);
*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
initrd_start = (initrd_start - phys_base) + PAGE_OFFSET;
@@ -268,7 +268,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
#endif
/* Reserve the kernel text/data/bss. */
size = (start_pfn << PAGE_SHIFT) - phys_base;
- reserve_bootmem(phys_base, size, BOOTMEM_DEFAULT);
+ reserve_bootmem(phys_base, size);
*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
/* Reserve the bootmem map. We do not account for it
@@ -276,7 +276,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
* in free_all_bootmem.
*/
size = bootmap_size;
- reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
+ reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
return max_pfn;
diff --git a/trunk/arch/sparc64/mm/init.c b/trunk/arch/sparc64/mm/init.c
index e726c45645ff..523e993ee90c 100644
--- a/trunk/arch/sparc64/mm/init.c
+++ b/trunk/arch/sparc64/mm/init.c
@@ -997,7 +997,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n",
initrd_start, initrd_end);
#endif
- reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
+ reserve_bootmem(initrd_start, size);
initrd_start += PAGE_OFFSET;
initrd_end += PAGE_OFFSET;
@@ -1007,7 +1007,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
#ifdef CONFIG_DEBUG_BOOTMEM
prom_printf("reserve_bootmem(kernel): base[%lx] size[%lx]\n", kern_base, kern_size);
#endif
- reserve_bootmem(kern_base, kern_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(kern_base, kern_size);
*pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT;
/* Add back in the initmem pages. */
@@ -1024,7 +1024,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
prom_printf("reserve_bootmem(bootmap): base[%lx] size[%lx]\n",
(bootmap_pfn << PAGE_SHIFT), size);
#endif
- reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
+ reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
for (i = 0; i < pavail_ents; i++) {
unsigned long start_pfn, end_pfn;
@@ -1489,7 +1489,7 @@ static void __init taint_real_pages(void)
goto do_next_page;
}
}
- reserve_bootmem(old_start, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem(old_start, PAGE_SIZE);
do_next_page:
old_start += PAGE_SIZE;
diff --git a/trunk/arch/v850/kernel/anna.c b/trunk/arch/v850/kernel/anna.c
index 5978a25170fb..0e429041a117 100644
--- a/trunk/arch/v850/kernel/anna.c
+++ b/trunk/arch/v850/kernel/anna.c
@@ -85,8 +85,7 @@ void __init mach_reserve_bootmem ()
/* The space between SRAM and SDRAM is filled with duplicate
images of SRAM. Prevent the kernel from using them. */
reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
- SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE),
- BOOTMEM_DEFAULT);
+ SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
}
void mach_gettimeofday (struct timespec *tv)
diff --git a/trunk/arch/v850/kernel/as85ep1.c b/trunk/arch/v850/kernel/as85ep1.c
index b525ecf3aea4..18437bc5c3ad 100644
--- a/trunk/arch/v850/kernel/as85ep1.c
+++ b/trunk/arch/v850/kernel/as85ep1.c
@@ -116,8 +116,7 @@ void __init mach_reserve_bootmem ()
if (SDRAM_ADDR < RAM_END && SDRAM_ADDR > RAM_START)
/* We can't use the space between SRAM and SDRAM, so
prevent the kernel from trying. */
- reserve_bootmem(SRAM_END, SDRAM_ADDR - SRAM_END,
- BOOTMEM_DEFAULT);
+ reserve_bootmem (SRAM_END, SDRAM_ADDR - SRAM_END);
}
void mach_gettimeofday (struct timespec *tv)
diff --git a/trunk/arch/v850/kernel/rte_ma1_cb.c b/trunk/arch/v850/kernel/rte_ma1_cb.c
index 08abf3d5f8df..9a716f946421 100644
--- a/trunk/arch/v850/kernel/rte_ma1_cb.c
+++ b/trunk/arch/v850/kernel/rte_ma1_cb.c
@@ -46,15 +46,13 @@ void __init mach_reserve_bootmem ()
{
#ifdef CONFIG_RTE_CB_MULTI
/* Prevent the kernel from touching the monitor's scratch RAM. */
- reserve_bootmem(MON_SCRATCH_ADDR, MON_SCRATCH_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem (MON_SCRATCH_ADDR, MON_SCRATCH_SIZE);
#endif
/* The space between SRAM and SDRAM is filled with duplicate
images of SRAM. Prevent the kernel from using them. */
reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
- SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE),
- BOOTMEM_DEFAULT);
+ SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
}
void mach_gettimeofday (struct timespec *tv)
diff --git a/trunk/arch/v850/kernel/setup.c b/trunk/arch/v850/kernel/setup.c
index a0a8456a8430..a914f244f494 100644
--- a/trunk/arch/v850/kernel/setup.c
+++ b/trunk/arch/v850/kernel/setup.c
@@ -241,18 +241,15 @@ init_bootmem_alloc (unsigned long ram_start, unsigned long ram_len)
if (kram_end > kram_start)
/* Reserve the RAM part of the kernel's address space, so it
doesn't get allocated. */
- reserve_bootmem(kram_start, kram_end - kram_start,
- BOOTMEM_DEFAULT);
+ reserve_bootmem (kram_start, kram_end - kram_start);
if (intv_in_ram && !intv_in_kram)
/* Reserve the interrupt vector space. */
- reserve_bootmem(intv_start, intv_end - intv_start,
- BOOTMEM_DEFAULT);
+ reserve_bootmem (intv_start, intv_end - intv_start);
if (bootmap >= ram_start && bootmap < ram_end)
/* Reserve the bootmap space. */
- reserve_bootmem(bootmap, bootmap_len,
- BOOTMEM_DEFAULT);
+ reserve_bootmem (bootmap, bootmap_len);
/* Reserve the memory used by the root filesystem image if it's
in RAM. */
@@ -260,8 +257,7 @@ init_bootmem_alloc (unsigned long ram_start, unsigned long ram_len)
&& (unsigned long)&_root_fs_image_start >= ram_start
&& (unsigned long)&_root_fs_image_start < ram_end)
reserve_bootmem ((unsigned long)&_root_fs_image_start,
- &_root_fs_image_end - &_root_fs_image_start,
- BOOTMEM_DEFAULT);
+ &_root_fs_image_end - &_root_fs_image_start);
/* Let the platform-dependent code reserve some too. */
if (mrb)
diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig
index 923c3babd667..e6728bd61cc1 100644
--- a/trunk/arch/x86/Kconfig
+++ b/trunk/arch/x86/Kconfig
@@ -631,6 +631,7 @@ config TOSHIBA
config I8K
tristate "Dell laptop support"
+ depends on X86_32
---help---
This adds a driver to safely access the System Management Mode
of the CPU on the Dell Inspiron 8000. The System Management Mode
diff --git a/trunk/arch/x86/ia32/ia32_aout.c b/trunk/arch/x86/ia32/ia32_aout.c
index 58cccb6483b0..e4c12079171b 100644
--- a/trunk/arch/x86/ia32/ia32_aout.c
+++ b/trunk/arch/x86/ia32/ia32_aout.c
@@ -172,7 +172,8 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file,
has_dumped = 1;
current->flags |= PF_DUMPCORE;
strncpy(dump.u_comm, current->comm, sizeof(current->comm));
- dump.u_ar0 = offsetof(struct user32, regs);
+ dump.u_ar0 = (u32)(((unsigned long)(&dump.regs)) -
+ ((unsigned long)(&dump)));
dump.signal = signr;
dump_thread32(regs, &dump);
diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/Kconfig b/trunk/arch/x86/kernel/cpu/cpufreq/Kconfig
index 151eda0a23fc..cb7a5715596d 100644
--- a/trunk/arch/x86/kernel/cpu/cpufreq/Kconfig
+++ b/trunk/arch/x86/kernel/cpu/cpufreq/Kconfig
@@ -29,7 +29,7 @@ config X86_ACPI_CPUFREQ
config ELAN_CPUFREQ
tristate "AMD Elan SC400 and SC410"
select CPU_FREQ_TABLE
- depends on X86_32 && X86_ELAN
+ depends on X86_ELAN
---help---
This adds the CPUFreq driver for AMD Elan SC400 and SC410
processors.
@@ -45,7 +45,7 @@ config ELAN_CPUFREQ
config SC520_CPUFREQ
tristate "AMD Elan SC520"
select CPU_FREQ_TABLE
- depends on X86_32 && X86_ELAN
+ depends on X86_ELAN
---help---
This adds the CPUFreq driver for AMD Elan SC520 processor.
diff --git a/trunk/arch/x86/kernel/machine_kexec_32.c b/trunk/arch/x86/kernel/machine_kexec_32.c
index d0b234c9fc31..c1cfd60639d4 100644
--- a/trunk/arch/x86/kernel/machine_kexec_32.c
+++ b/trunk/arch/x86/kernel/machine_kexec_32.c
@@ -151,7 +151,7 @@ NORET_TYPE void machine_kexec(struct kimage *image)
void arch_crash_save_vmcoreinfo(void)
{
-#ifdef CONFIG_NUMA
+#ifdef CONFIG_ARCH_DISCONTIGMEM_ENABLE
VMCOREINFO_SYMBOL(node_data);
VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
#endif
diff --git a/trunk/arch/x86/kernel/machine_kexec_64.c b/trunk/arch/x86/kernel/machine_kexec_64.c
index 236d2f8f7ddc..a1fef42f8cdb 100644
--- a/trunk/arch/x86/kernel/machine_kexec_64.c
+++ b/trunk/arch/x86/kernel/machine_kexec_64.c
@@ -234,10 +234,5 @@ NORET_TYPE void machine_kexec(struct kimage *image)
void arch_crash_save_vmcoreinfo(void)
{
VMCOREINFO_SYMBOL(init_level4_pgt);
-
-#ifdef CONFIG_NUMA
- VMCOREINFO_SYMBOL(node_data);
- VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
-#endif
}
diff --git a/trunk/arch/x86/kernel/mpparse_32.c b/trunk/arch/x86/kernel/mpparse_32.c
index f349e68e45a0..67009cdd5eca 100644
--- a/trunk/arch/x86/kernel/mpparse_32.c
+++ b/trunk/arch/x86/kernel/mpparse_32.c
@@ -736,8 +736,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length)
smp_found_config = 1;
printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n",
mpf, virt_to_phys(mpf));
- reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
if (mpf->mpf_physptr) {
/*
* We cannot access to MPC table to compute
@@ -752,8 +751,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length)
unsigned long end = max_low_pfn * PAGE_SIZE;
if (mpf->mpf_physptr + size > end)
size = end - mpf->mpf_physptr;
- reserve_bootmem(mpf->mpf_physptr, size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(mpf->mpf_physptr, size);
}
mpf_found = mpf;
diff --git a/trunk/arch/x86/kernel/setup_32.c b/trunk/arch/x86/kernel/setup_32.c
index d1d8c347cc0b..62adc5f20be5 100644
--- a/trunk/arch/x86/kernel/setup_32.c
+++ b/trunk/arch/x86/kernel/setup_32.c
@@ -390,7 +390,7 @@ static void __init reserve_ebda_region(void)
unsigned int addr;
addr = get_bios_ebda();
if (addr)
- reserve_bootmem(addr, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem(addr, PAGE_SIZE);
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -484,8 +484,7 @@ static void __init reserve_crashkernel(void)
(unsigned long)(total_mem >> 20));
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
- reserve_bootmem(crash_base, crash_size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem(crash_base, crash_size);
} else
printk(KERN_INFO "crashkernel reservation failed - "
"you have to specify a base address\n");
@@ -526,7 +525,7 @@ static void __init reserve_initrd(void)
}
if (ramdisk_end <= end_of_lowmem) {
/* All in lowmem, easy case */
- reserve_bootmem(ramdisk_image, ramdisk_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(ramdisk_image, ramdisk_size);
initrd_start = ramdisk_image + PAGE_OFFSET;
initrd_end = initrd_start+ramdisk_size;
return;
@@ -537,7 +536,7 @@ static void __init reserve_initrd(void)
/* Note: this includes all the lowmem currently occupied by
the initrd, we rely on that fact to keep the data intact. */
- reserve_bootmem(ramdisk_here, ramdisk_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(ramdisk_here, ramdisk_size);
initrd_start = ramdisk_here + PAGE_OFFSET;
initrd_end = initrd_start + ramdisk_size;
@@ -607,14 +606,13 @@ void __init setup_bootmem_allocator(void)
* bootmem allocator with an invalid RAM area.
*/
reserve_bootmem(__pa_symbol(_text), (PFN_PHYS(min_low_pfn) +
- bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text),
- BOOTMEM_DEFAULT);
+ bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text));
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
* enabling clean reboots, SMP operation, laptop functions.
*/
- reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem(0, PAGE_SIZE);
/* reserve EBDA region, it's a 4K region */
reserve_ebda_region();
@@ -624,7 +622,7 @@ void __init setup_bootmem_allocator(void)
unless you have no PS/2 mouse plugged in. */
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
boot_cpu_data.x86 == 6)
- reserve_bootmem(0xa0000 - 4096, 4096, BOOTMEM_DEFAULT);
+ reserve_bootmem(0xa0000 - 4096, 4096);
#ifdef CONFIG_SMP
/*
@@ -632,7 +630,7 @@ void __init setup_bootmem_allocator(void)
* FIXME: Don't need the extra page at 4K, but need to fix
* trampoline before removing it. (see the GDT stuff)
*/
- reserve_bootmem(PAGE_SIZE, PAGE_SIZE, BOOTMEM_DEFAULT);
+ reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
#endif
#ifdef CONFIG_ACPI_SLEEP
/*
diff --git a/trunk/arch/x86/kernel/setup_64.c b/trunk/arch/x86/kernel/setup_64.c
index a49f5f734a5e..c8939dfddfba 100644
--- a/trunk/arch/x86/kernel/setup_64.c
+++ b/trunk/arch/x86/kernel/setup_64.c
@@ -189,7 +189,7 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
e820_register_active_regions(0, start_pfn, end_pfn);
free_bootmem_with_active_regions(0, end_pfn);
- reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT);
+ reserve_bootmem(bootmap, bootmap_size);
}
#endif
@@ -220,35 +220,28 @@ static inline void copy_edd(void)
#ifdef CONFIG_KEXEC
static void __init reserve_crashkernel(void)
{
- unsigned long long total_mem;
+ unsigned long long free_mem;
unsigned long long crash_size, crash_base;
int ret;
- total_mem = ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
+ free_mem =
+ ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
- ret = parse_crashkernel(boot_command_line, total_mem,
+ ret = parse_crashkernel(boot_command_line, free_mem,
&crash_size, &crash_base);
if (ret == 0 && crash_size) {
- if (crash_base <= 0) {
+ if (crash_base > 0) {
+ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+ "for crashkernel (System RAM: %ldMB)\n",
+ (unsigned long)(crash_size >> 20),
+ (unsigned long)(crash_base >> 20),
+ (unsigned long)(free_mem >> 20));
+ crashk_res.start = crash_base;
+ crashk_res.end = crash_base + crash_size - 1;
+ reserve_bootmem(crash_base, crash_size);
+ } else
printk(KERN_INFO "crashkernel reservation failed - "
"you have to specify a base address\n");
- return;
- }
-
- if (reserve_bootmem(crash_base, crash_size,
- BOOTMEM_EXCLUSIVE) < 0) {
- printk(KERN_INFO "crashkernel reservation failed - "
- "memory is in use\n");
- return;
- }
-
- printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
- "for crashkernel (System RAM: %ldMB)\n",
- (unsigned long)(crash_size >> 20),
- (unsigned long)(crash_base >> 20),
- (unsigned long)(total_mem >> 20));
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
}
}
#else
diff --git a/trunk/arch/x86/mm/discontig_32.c b/trunk/arch/x86/mm/discontig_32.c
index c394ca0720b8..04b1d20e2613 100644
--- a/trunk/arch/x86/mm/discontig_32.c
+++ b/trunk/arch/x86/mm/discontig_32.c
@@ -391,8 +391,7 @@ unsigned long __init setup_memory(void)
void __init numa_kva_reserve(void)
{
if (kva_pages)
- reserve_bootmem(PFN_PHYS(kva_start_pfn), PFN_PHYS(kva_pages),
- BOOTMEM_DEFAULT);
+ reserve_bootmem(PFN_PHYS(kva_start_pfn), PFN_PHYS(kva_pages));
}
void __init zone_sizes_init(void)
diff --git a/trunk/arch/x86/mm/init_64.c b/trunk/arch/x86/mm/init_64.c
index 5fe880fc305d..9b61c75a2355 100644
--- a/trunk/arch/x86/mm/init_64.c
+++ b/trunk/arch/x86/mm/init_64.c
@@ -644,9 +644,9 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
/* Should check here against the e820 map to avoid double free */
#ifdef CONFIG_NUMA
- reserve_bootmem_node(NODE_DATA(nid), phys, len, BOOTMEM_DEFAULT);
+ reserve_bootmem_node(NODE_DATA(nid), phys, len);
#else
- reserve_bootmem(phys, len, BOOTMEM_DEFAULT);
+ reserve_bootmem(phys, len);
#endif
if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
dma_reserve += len / PAGE_SIZE;
diff --git a/trunk/arch/x86/mm/numa_64.c b/trunk/arch/x86/mm/numa_64.c
index 1aecc658cd7d..5a02bf4c91ec 100644
--- a/trunk/arch/x86/mm/numa_64.c
+++ b/trunk/arch/x86/mm/numa_64.c
@@ -238,10 +238,9 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
free_bootmem_with_active_regions(nodeid, end);
- reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size,
- BOOTMEM_DEFAULT);
+ reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start,
- bootmap_pages<cra_blocksize))
diff --git a/trunk/crypto/cryptd.c b/trunk/crypto/cryptd.c
index 250425263e00..074298f2f8e3 100644
--- a/trunk/crypto/cryptd.c
+++ b/trunk/crypto/cryptd.c
@@ -230,7 +230,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return ERR_PTR(PTR_ERR(alg));
inst = cryptd_alloc_instance(alg, state);
if (IS_ERR(inst))
@@ -267,7 +267,7 @@ static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
+ return ERR_PTR(PTR_ERR(algt));
switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_BLKCIPHER:
diff --git a/trunk/crypto/ecb.c b/trunk/crypto/ecb.c
index a46838e98a71..6310387a872c 100644
--- a/trunk/crypto/ecb.c
+++ b/trunk/crypto/ecb.c
@@ -128,7 +128,7 @@ static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return ERR_PTR(PTR_ERR(alg));
inst = crypto_alloc_instance("ecb", alg);
if (IS_ERR(inst))
diff --git a/trunk/crypto/hmac.c b/trunk/crypto/hmac.c
index b60c3c7aa320..a1d016a50e7d 100644
--- a/trunk/crypto/hmac.c
+++ b/trunk/crypto/hmac.c
@@ -213,7 +213,7 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_HASH_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return ERR_PTR(PTR_ERR(alg));
inst = crypto_alloc_instance("hmac", alg);
if (IS_ERR(inst))
diff --git a/trunk/crypto/lrw.c b/trunk/crypto/lrw.c
index 9d52e580d10a..621095db28b3 100644
--- a/trunk/crypto/lrw.c
+++ b/trunk/crypto/lrw.c
@@ -241,7 +241,7 @@ static struct crypto_instance *alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return ERR_PTR(PTR_ERR(alg));
inst = crypto_alloc_instance("lrw", alg);
if (IS_ERR(inst))
diff --git a/trunk/crypto/pcbc.c b/trunk/crypto/pcbc.c
index d1b8bdfb5855..fe704775f88f 100644
--- a/trunk/crypto/pcbc.c
+++ b/trunk/crypto/pcbc.c
@@ -234,7 +234,7 @@ static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return ERR_PTR(PTR_ERR(alg));
inst = crypto_alloc_instance("pcbc", alg);
if (IS_ERR(inst))
diff --git a/trunk/crypto/xcbc.c b/trunk/crypto/xcbc.c
index 86727403e5ab..a82959df678c 100644
--- a/trunk/crypto/xcbc.c
+++ b/trunk/crypto/xcbc.c
@@ -301,7 +301,7 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return ERR_PTR(PTR_ERR(alg));
switch(alg->cra_blocksize) {
case 16:
diff --git a/trunk/drivers/block/xsysace.c b/trunk/drivers/block/xsysace.c
index 4a7a059ebaf7..78ebfffc77e3 100644
--- a/trunk/drivers/block/xsysace.c
+++ b/trunk/drivers/block/xsysace.c
@@ -1202,10 +1202,8 @@ static int __devexit ace_of_remove(struct of_device *op)
}
/* Match table for of_platform binding */
-static struct of_device_id ace_of_match[] __devinitdata = {
- { .compatible = "xlnx,opb-sysace-1.00.b", },
- { .compatible = "xlnx,opb-sysace-1.00.c", },
- { .compatible = "xlnx,xps-sysace-1.00.a", },
+static struct of_device_id __devinit ace_of_match[] = {
+ { .compatible = "xilinx,xsysace", },
{},
};
MODULE_DEVICE_TABLE(of, ace_of_match);
diff --git a/trunk/drivers/cdrom/viocd.c b/trunk/drivers/cdrom/viocd.c
index cac06bc1754b..8473b9f1da96 100644
--- a/trunk/drivers/cdrom/viocd.c
+++ b/trunk/drivers/cdrom/viocd.c
@@ -558,7 +558,7 @@ static struct cdrom_device_ops viocd_dops = {
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
};
-static int find_capability(const char *type)
+static int __init find_capability(const char *type)
{
struct capability_entry *entry;
diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig
index f01ac9a07bf5..85bf9b2aa74a 100644
--- a/trunk/drivers/char/Kconfig
+++ b/trunk/drivers/char/Kconfig
@@ -194,6 +194,17 @@ config MOXA_INTELLIO
module will be called moxa.
config MOXA_SMARTIO
+ tristate "Moxa SmartIO support (OBSOLETE)"
+ depends on SERIAL_NONSTANDARD
+ help
+ Say Y here if you have a Moxa SmartIO multiport serial card.
+
+ This driver can also be built as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called mxser. If you want to do that, say M
+ here.
+
+config MOXA_SMARTIO_NEW
tristate "Moxa SmartIO support v. 2.0"
depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
help
@@ -204,7 +215,7 @@ config MOXA_SMARTIO
changes finally resulting in PCI probing.
This driver can also be built as a module. The module will be called
- mxser. If you want to do that, say M here.
+ mxser_new. If you want to do that, say M here.
config ISI
tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
@@ -830,16 +841,6 @@ config DTLK
To compile this driver as a module, choose M here: the
module will be called dtlk.
-config XILINX_HWICAP
- tristate "Xilinx HWICAP Support"
- depends on XILINX_VIRTEX
- help
- This option enables support for Xilinx Internal Configuration
- Access Port (ICAP) driver. The ICAP is used on Xilinx Virtex
- FPGA platforms to partially reconfigure the FPGA at runtime.
-
- If unsure, say N.
-
config R3964
tristate "Siemens R3964 line discipline"
---help---
diff --git a/trunk/drivers/char/Makefile b/trunk/drivers/char/Makefile
index 5407b7615614..96fc01eddefe 100644
--- a/trunk/drivers/char/Makefile
+++ b/trunk/drivers/char/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
+obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o
obj-$(CONFIG_COMPUTONE) += ip2/
obj-$(CONFIG_RISCOM8) += riscom8.o
obj-$(CONFIG_ISI) += isicom.o
@@ -76,7 +77,6 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
-obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
diff --git a/trunk/drivers/char/epca.h b/trunk/drivers/char/epca.h
index 3c77c02b5d65..a297238cd3ba 100644
--- a/trunk/drivers/char/epca.h
+++ b/trunk/drivers/char/epca.h
@@ -77,6 +77,7 @@ static char *board_desc[] =
#define ON 1
#define FEPTIMEOUT 200000
+#define SERIAL_TYPE_NORMAL 1
#define SERIAL_TYPE_INFO 3
#define EPCA_EVENT_HANGUP 1
#define EPCA_MAGIC 0x5c6df104L
diff --git a/trunk/drivers/char/esp.c b/trunk/drivers/char/esp.c
index c01e26d9ee5e..28607763ae64 100644
--- a/trunk/drivers/char/esp.c
+++ b/trunk/drivers/char/esp.c
@@ -111,6 +111,9 @@ static char serial_version[] __initdata = "2.2";
static struct tty_driver *esp_driver;
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+
/*
* Serial driver configuration section. Here are the various options:
*
@@ -242,6 +245,17 @@ static void rs_start(struct tty_struct *tty)
* -----------------------------------------------------------------------
*/
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static inline void rs_sched_event(struct esp_struct *info,
+ int event)
+{
+ info->event |= 1 << event;
+ schedule_work(&info->tqueue);
+}
+
static DEFINE_SPINLOCK(pio_lock);
static inline struct esp_pio_buffer *get_pio_buffer(void)
@@ -463,8 +477,7 @@ static inline void transmit_chars_pio(struct esp_struct *info,
}
if (info->xmit_cnt < WAKEUP_CHARS) {
- if (info->tty)
- tty_wakeup(info->tty);
+ rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP);
#ifdef SERIAL_DEBUG_INTR
printk("THRE...");
@@ -502,8 +515,7 @@ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1);
if (info->xmit_cnt < WAKEUP_CHARS) {
- if (info->tty)
- tty_wakeup(info->tty);
+ rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP);
#ifdef SERIAL_DEBUG_INTR
printk("THRE...");
@@ -595,7 +607,7 @@ static inline void check_modem_status(struct esp_struct *info)
#ifdef SERIAL_DEBUG_OPEN
printk("scheduling hangup...");
#endif
- tty_hangup(info->tty);
+ schedule_work(&info->tqueue_hangup);
}
}
}
@@ -711,6 +723,41 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
* -------------------------------------------------------------------
*/
+static void do_softint(struct work_struct *work)
+{
+ struct esp_struct *info =
+ container_of(work, struct esp_struct, tqueue);
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
+ tty_wakeup(tty);
+ }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (scheduler tqueue) ->
+ * do_serial_hangup() -> tty->hangup() -> esp_hangup()
+ *
+ */
+static void do_serial_hangup(struct work_struct *work)
+{
+ struct esp_struct *info =
+ container_of(work, struct esp_struct, tqueue_hangup);
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (tty)
+ tty_hangup(tty);
+}
+
/*
* ---------------------------------------------------------------
* Low level utility subroutines for the serial driver: routines to
@@ -1994,6 +2041,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
+ info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
@@ -2061,6 +2109,7 @@ static void esp_hangup(struct tty_struct *tty)
rs_flush_buffer(tty);
shutdown(info);
+ info->event = 0;
info->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
info->tty = NULL;
@@ -2446,6 +2495,8 @@ static int __init espserial_init(void)
info->magic = ESP_MAGIC;
info->close_delay = 5*HZ/10;
info->closing_wait = 30*HZ;
+ INIT_WORK(&info->tqueue, do_softint);
+ INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
info->config.rx_timeout = rx_timeout;
info->config.flow_on = flow_on;
info->config.flow_off = flow_off;
diff --git a/trunk/drivers/char/i8k.c b/trunk/drivers/char/i8k.c
index 8609b8236c67..179223a17414 100644
--- a/trunk/drivers/char/i8k.c
+++ b/trunk/drivers/char/i8k.c
@@ -113,33 +113,6 @@ static int i8k_smm(struct smm_regs *regs)
int rc;
int eax = regs->eax;
-#if defined(CONFIG_X86_64)
- asm("pushq %%rax\n\t"
- "movl 0(%%rax),%%edx\n\t"
- "pushq %%rdx\n\t"
- "movl 4(%%rax),%%ebx\n\t"
- "movl 8(%%rax),%%ecx\n\t"
- "movl 12(%%rax),%%edx\n\t"
- "movl 16(%%rax),%%esi\n\t"
- "movl 20(%%rax),%%edi\n\t"
- "popq %%rax\n\t"
- "out %%al,$0xb2\n\t"
- "out %%al,$0x84\n\t"
- "xchgq %%rax,(%%rsp)\n\t"
- "movl %%ebx,4(%%rax)\n\t"
- "movl %%ecx,8(%%rax)\n\t"
- "movl %%edx,12(%%rax)\n\t"
- "movl %%esi,16(%%rax)\n\t"
- "movl %%edi,20(%%rax)\n\t"
- "popq %%rdx\n\t"
- "movl %%edx,0(%%rax)\n\t"
- "lahf\n\t"
- "shrl $8,%%eax\n\t"
- "andl $1,%%eax\n"
- :"=a"(rc)
- : "a"(regs)
- : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-#else
asm("pushl %%eax\n\t"
"movl 0(%%eax),%%edx\n\t"
"push %%edx\n\t"
@@ -164,7 +137,7 @@ static int i8k_smm(struct smm_regs *regs)
"andl $1,%%eax\n":"=a"(rc)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-#endif
+
if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
return -EINVAL;
@@ -473,13 +446,6 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
},
},
- {
- .ident = "Dell Inspiron 3",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "MP061"),
- },
- },
{ }
};
diff --git a/trunk/drivers/char/ip2/ip2main.c b/trunk/drivers/char/ip2/ip2main.c
index b1d6cad84282..0f49ccf02a7f 100644
--- a/trunk/drivers/char/ip2/ip2main.c
+++ b/trunk/drivers/char/ip2/ip2main.c
@@ -153,6 +153,9 @@ static char *pcVersion = "1.2.14";
static char *pcDriver_name = "ip2";
static char *pcIpl = "ip2ipl";
+/* Serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+
// cheezy kludge or genius - you decide?
int ip2_loadmain(int *, int *, unsigned char *, int);
static unsigned char *Fip_firmware;
diff --git a/trunk/drivers/char/istallion.c b/trunk/drivers/char/istallion.c
index c645455c3fd1..1f27be1ec3d4 100644
--- a/trunk/drivers/char/istallion.c
+++ b/trunk/drivers/char/istallion.c
@@ -627,6 +627,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp);
static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
+static void stli_dohangup(struct work_struct *);
static int stli_setport(struct stliport *portp);
static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
@@ -1822,6 +1823,25 @@ static void stli_start(struct tty_struct *tty)
/*****************************************************************************/
+/*
+ * Scheduler called hang up routine. This is called from the scheduler,
+ * not direct from the driver "poll" routine. We can't call it there
+ * since the real local hangup code will enable/disable the board and
+ * other things that we can't do while handling the poll. Much easier
+ * to deal with it some time later (don't really care when, hangups
+ * aren't that time critical).
+ */
+
+static void stli_dohangup(struct work_struct *ugly_api)
+{
+ struct stliport *portp = container_of(ugly_api, struct stliport, tqhangup);
+ if (portp->tty != NULL) {
+ tty_hangup(portp->tty);
+ }
+}
+
+/*****************************************************************************/
+
/*
* Hangup this port. This is pretty much like closing the port, only
* a little more brutal. No waiting for data to drain. Shutdown the
@@ -2385,7 +2405,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
((portp->sigs & TIOCM_CD) == 0)) {
if (portp->flags & ASYNC_CHECK_CD) {
if (tty)
- tty_hangup(tty);
+ schedule_work(&portp->tqhangup);
}
}
}
@@ -2713,6 +2733,7 @@ static int stli_initports(struct stlibrd *brdp)
portp->baud_base = STL_BAUDBASE;
portp->close_delay = STL_CLOSEDELAY;
portp->closing_wait = 30 * HZ;
+ INIT_WORK(&portp->tqhangup, stli_dohangup);
init_waitqueue_head(&portp->open_wait);
init_waitqueue_head(&portp->close_wait);
init_waitqueue_head(&portp->raw_wait);
diff --git a/trunk/drivers/char/mbcs.c b/trunk/drivers/char/mbcs.c
index f4716ad7348a..3c5802ae1716 100644
--- a/trunk/drivers/char/mbcs.c
+++ b/trunk/drivers/char/mbcs.c
@@ -23,7 +23,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -282,7 +281,7 @@ static inline int mbcs_algo_start(struct mbcs_soft *soft)
void *mmr_base = soft->mmr_base;
union cm_control cm_control;
- if (mutex_lock_interruptible(&soft->algolock))
+ if (down_interruptible(&soft->algolock))
return -ERESTARTSYS;
atomic_set(&soft->algo_done, 0);
@@ -299,7 +298,7 @@ static inline int mbcs_algo_start(struct mbcs_soft *soft)
cm_control.alg_go = 1;
MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
- mutex_unlock(&soft->algolock);
+ up(&soft->algolock);
return 0;
}
@@ -310,7 +309,7 @@ do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
{
int rv = 0;
- if (mutex_lock_interruptible(&soft->dmawritelock))
+ if (down_interruptible(&soft->dmawritelock))
return -ERESTARTSYS;
atomic_set(&soft->dmawrite_done, 0);
@@ -336,7 +335,7 @@ do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
*off += len;
dmawrite_exit:
- mutex_unlock(&soft->dmawritelock);
+ up(&soft->dmawritelock);
return rv;
}
@@ -347,7 +346,7 @@ do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
{
int rv = 0;
- if (mutex_lock_interruptible(&soft->dmareadlock))
+ if (down_interruptible(&soft->dmareadlock))
return -ERESTARTSYS;
atomic_set(&soft->dmawrite_done, 0);
@@ -372,7 +371,7 @@ do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
*off += len;
dmaread_exit:
- mutex_unlock(&soft->dmareadlock);
+ up(&soft->dmareadlock);
return rv;
}
@@ -763,9 +762,9 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
init_waitqueue_head(&soft->dmaread_queue);
init_waitqueue_head(&soft->algo_queue);
- mutex_init(&soft->dmawritelock);
- mutex_init(&soft->dmareadlock);
- mutex_init(&soft->algolock);
+ init_MUTEX(&soft->dmawritelock);
+ init_MUTEX(&soft->dmareadlock);
+ init_MUTEX(&soft->algolock);
mbcs_getdma_init(&soft->getdma);
mbcs_putdma_init(&soft->putdma);
diff --git a/trunk/drivers/char/mbcs.h b/trunk/drivers/char/mbcs.h
index ba671589f4cb..c9905a3c3353 100644
--- a/trunk/drivers/char/mbcs.h
+++ b/trunk/drivers/char/mbcs.h
@@ -537,9 +537,9 @@ struct mbcs_soft {
atomic_t dmawrite_done;
atomic_t dmaread_done;
atomic_t algo_done;
- struct mutex dmawritelock;
- struct mutex dmareadlock;
- struct mutex algolock;
+ struct semaphore dmawritelock;
+ struct semaphore dmareadlock;
+ struct semaphore algolock;
};
static int mbcs_open(struct inode *ip, struct file *fp);
diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c
index 68c2e9234691..47420787a017 100644
--- a/trunk/drivers/char/mxser.c
+++ b/trunk/drivers/char/mxser.c
@@ -1,24 +1,41 @@
/*
* mxser.c -- MOXA Smartio/Industio family multiport serial driver.
*
- * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com).
- * Copyright (C) 2006-2008 Jiri Slaby
+ * Copyright (C) 1999-2001 Moxa Technologies (support@moxa.com.tw).
*
- * This code is loosely based on the 1.8 moxa driver which is based on
- * Linux serial driver, written by Linus Torvalds, Theodore T'so and
- * others.
+ * This code is loosely based on the Linux serial driver, written by
+ * Linus Torvalds, Theodore T'so and others.
*
* 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.
+ *
+ * Original release 10/26/00
+ *
+ * 02/06/01 Support MOXA Industio family boards.
+ * 02/06/01 Support TIOCGICOUNT.
+ * 02/06/01 Fix the problem for connecting to serial mouse.
+ * 02/06/01 Fix the problem for H/W flow control.
+ * 02/06/01 Fix the compling warning when CONFIG_PCI
+ * don't be defined.
+ *
* Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
* . The original 1.8 code is available on www.moxa.com.
* - Fixed x86_64 cleanness
* - Fixed sleep with spinlock held in mxser_send_break
*/
+
#include
#include
#include
@@ -47,37 +64,33 @@
#include "mxser.h"
-#define MXSER_VERSION "2.0.3" /* 1.11 */
+#define MXSER_VERSION "1.8"
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
+#define MXSER_EVENT_TXLOW 1
+#define MXSER_EVENT_HANGUP 2
+
#define MXSER_BOARDS 4 /* Max. boards */
+#define MXSER_PORTS 32 /* Max. ports */
#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
-#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
-#define MXSER_ISR_PASS_LIMIT 100
+#define MXSER_ISR_PASS_LIMIT 256
#define MXSER_ERR_IOADDR -1
#define MXSER_ERR_IRQ -2
#define MXSER_ERR_IRQ_CONFLIT -3
#define MXSER_ERR_VECTOR -4
-/*CheckIsMoxaMust return value*/
-#define MOXA_OTHER_UART 0x00
-#define MOXA_MUST_MU150_HWID 0x01
-#define MOXA_MUST_MU860_HWID 0x02
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
#define WAKEUP_CHARS 256
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
-#define PCI_DEVICE_ID_CB108 0x1080
-#define PCI_DEVICE_ID_CB114 0x1142
-#define PCI_DEVICE_ID_CP114UL 0x1143
-#define PCI_DEVICE_ID_CB134I 0x1341
-#define PCI_DEVICE_ID_CP138U 0x1380
-#define PCI_DEVICE_ID_POS104UL 0x1044
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
@@ -86,11 +99,88 @@
#define CI134_ASIC_ID 3
#define CI104J_ASIC_ID 5
-#define MXSER_HIGHBAUD 1
-#define MXSER_HAS2 2
+enum {
+ MXSER_BOARD_C168_ISA = 1,
+ MXSER_BOARD_C104_ISA,
+ MXSER_BOARD_CI104J,
+ MXSER_BOARD_C168_PCI,
+ MXSER_BOARD_C104_PCI,
+ MXSER_BOARD_C102_ISA,
+ MXSER_BOARD_CI132,
+ MXSER_BOARD_CI134,
+ MXSER_BOARD_CP132,
+ MXSER_BOARD_CP114,
+ MXSER_BOARD_CT114,
+ MXSER_BOARD_CP102,
+ MXSER_BOARD_CP104U,
+ MXSER_BOARD_CP168U,
+ MXSER_BOARD_CP132U,
+ MXSER_BOARD_CP134U,
+ MXSER_BOARD_CP104JU,
+ MXSER_BOARD_RC7000,
+ MXSER_BOARD_CP118U,
+ MXSER_BOARD_CP102UL,
+ MXSER_BOARD_CP102U,
+};
+
+static char *mxser_brdname[] = {
+ "C168 series",
+ "C104 series",
+ "CI-104J series",
+ "C168H/PCI series",
+ "C104H/PCI series",
+ "C102 series",
+ "CI-132 series",
+ "CI-134 series",
+ "CP-132 series",
+ "CP-114 series",
+ "CT-114 series",
+ "CP-102 series",
+ "CP-104U series",
+ "CP-168U series",
+ "CP-132U series",
+ "CP-134U series",
+ "CP-104JU series",
+ "Moxa UC7000 Serial",
+ "CP-118U series",
+ "CP-102UL series",
+ "CP-102U series",
+};
+
+static int mxser_numports[] = {
+ 8, /* C168-ISA */
+ 4, /* C104-ISA */
+ 4, /* CI104J */
+ 8, /* C168-PCI */
+ 4, /* C104-PCI */
+ 2, /* C102-ISA */
+ 2, /* CI132 */
+ 4, /* CI134 */
+ 2, /* CP132 */
+ 4, /* CP114 */
+ 4, /* CT114 */
+ 2, /* CP102 */
+ 4, /* CP104U */
+ 8, /* CP168U */
+ 2, /* CP132U */
+ 4, /* CP134U */
+ 4, /* CP104JU */
+ 8, /* RC7000 */
+ 8, /* CP118U */
+ 2, /* CP102UL */
+ 2, /* CP102U */
+};
+
+#define UART_TYPE_NUM 2
+
+static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
+ MOXA_MUST_MU150_HWID,
+ MOXA_MUST_MU860_HWID
+};
/* This is only for PCI */
-static const struct {
+#define UART_INFO_NUM 3
+struct mxpciuart_info {
int type;
int tx_fifo;
int rx_fifo;
@@ -99,85 +189,51 @@ static const struct {
int rx_trigger;
int rx_low_water;
long max_baud;
-} Gpci_uart_info[] = {
+};
+
+static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
{MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
{MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
{MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
};
-#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
-struct mxser_cardinfo {
- char *name;
- unsigned int nports;
- unsigned int flags;
-};
-static const struct mxser_cardinfo mxser_cards[] = {
-/* 0*/ { "C168 series", 8, },
- { "C104 series", 4, },
- { "CI-104J series", 4, },
- { "C168H/PCI series", 8, },
- { "C104H/PCI series", 4, },
-/* 5*/ { "C102 series", 4, MXSER_HAS2 }, /* C102-ISA */
- { "CI-132 series", 4, MXSER_HAS2 },
- { "CI-134 series", 4, },
- { "CP-132 series", 2, },
- { "CP-114 series", 4, },
-/*10*/ { "CT-114 series", 4, },
- { "CP-102 series", 2, MXSER_HIGHBAUD },
- { "CP-104U series", 4, },
- { "CP-168U series", 8, },
- { "CP-132U series", 2, },
-/*15*/ { "CP-134U series", 4, },
- { "CP-104JU series", 4, },
- { "Moxa UC7000 Serial", 8, }, /* RC7000 */
- { "CP-118U series", 8, },
- { "CP-102UL series", 2, },
-/*20*/ { "CP-102U series", 2, },
- { "CP-118EL series", 8, },
- { "CP-168EL series", 8, },
- { "CP-104EL series", 4, },
- { "CB-108 series", 8, },
-/*25*/ { "CB-114 series", 4, },
- { "CB-134I series", 4, },
- { "CP-138U series", 8, },
- { "POS-104UL series", 4, },
- { "CP-114UL series", 4, }
-};
+#ifdef CONFIG_PCI
-/* driver_data correspond to the lines in the structure above
- see also ISA probe function before you change something */
static struct pci_device_id mxser_pcibrds[] = {
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 },
- { }
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C168_PCI},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP114},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CT114},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104U},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP168U},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132U},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP134U},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104JU},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_RC7000},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP118U},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102UL},
+ {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102U},
+ {0}
};
+
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+
+#endif
+
+typedef struct _moxa_pci_info {
+ unsigned short busNum;
+ unsigned short devNum;
+ struct pci_dev *pdev; /* add by Victor Yu. 06-23-2003 */
+} moxa_pci_info;
+
static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
static int ttymajor = MXSERMAJOR;
+static int calloutmajor = MXSERCUMAJOR;
+static int verbose = 0;
/* Variables for insmod */
@@ -185,6 +241,8 @@ MODULE_AUTHOR("Casper Yang");
MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
module_param_array(ioaddr, int, NULL, 0);
module_param(ttymajor, int, 0);
+module_param(calloutmajor, int, 0);
+module_param(verbose, bool, 0);
MODULE_LICENSE("GPL");
struct mxser_log {
@@ -219,69 +277,67 @@ struct mxser_mon_ext {
int iftype[32];
};
-struct mxser_board;
-
-struct mxser_port {
- struct mxser_board *board;
- struct tty_struct *tty;
-
- unsigned long ioaddr;
- unsigned long opmode_ioaddr;
- int max_baud;
+struct mxser_hwconf {
+ int board_type;
+ int ports;
+ int irq;
+ int vector;
+ int vector_mask;
+ int uart_type;
+ int ioaddr[MXSER_PORTS_PER_BOARD];
+ int baud_base[MXSER_PORTS_PER_BOARD];
+ moxa_pci_info pciInfo;
+ int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+ int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 09-04-2002 */
+ int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */
+};
+struct mxser_struct {
+ int port;
+ int base; /* port base address */
+ int irq; /* port using irq no. */
+ int vector; /* port irq vector */
+ int vectormask; /* port vector mask */
int rx_high_water;
int rx_trigger; /* Rx fifo trigger level */
int rx_low_water;
int baud_base; /* max. speed */
- int type; /* UART type */
int flags; /* defined in tty.h */
-
- int x_char; /* xon/xoff character */
- int IER; /* Interrupt Enable Register */
- int MCR; /* Modem control register */
-
- unsigned char stop_rx;
- unsigned char ldisc_stop_rx;
-
+ int type; /* UART type */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int xmit_fifo_size;
int custom_divisor;
+ int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
- unsigned char err_shadow;
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
unsigned long event;
-
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
- struct async_icount icount; /* kernel counters for 4 input interrupts */
- int timeout;
-
- int read_status_mask;
- int ignore_status_mask;
- int xmit_fifo_size;
unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
-
+ struct work_struct tqueue;
struct ktermios normal_termios;
-
- struct mxser_mon mon_data;
-
- spinlock_t slock;
+ struct ktermios callout_termios;
wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
-};
-
-struct mxser_board {
- unsigned int idx;
- int irq;
- const struct mxser_cardinfo *info;
- unsigned long vector;
- unsigned long vector_mask;
-
- int chip_flag;
- int uart_type;
-
- struct mxser_port ports[MXSER_PORTS_PER_BOARD];
+ struct async_icount icount; /* kernel counters for the 4 input interrupts */
+ int timeout;
+ int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+ int MaxCanSetBaudRate; /* add by Victor Yu. 09-04-2002 */
+ int opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */
+ unsigned char stop_rx;
+ unsigned char ldisc_stop_rx;
+ long realbaud;
+ struct mxser_mon mon_data;
+ unsigned char err_shadow;
+ spinlock_t slock;
};
struct mxser_mstatus {
@@ -299,16 +355,73 @@ static int mxserBoardCAP[MXSER_BOARDS] = {
/* 0x180, 0x280, 0x200, 0x320 */
};
-static struct mxser_board mxser_boards[MXSER_BOARDS];
static struct tty_driver *mxvar_sdriver;
+static struct mxser_struct mxvar_table[MXSER_PORTS];
+static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
+static struct ktermios *mxvar_termios[MXSER_PORTS + 1];
+static struct ktermios *mxvar_termios_locked[MXSER_PORTS + 1];
static struct mxser_log mxvar_log;
static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
+static spinlock_t gm_lock;
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+
+static struct mxser_hwconf mxsercfg[MXSER_BOARDS];
+
+/*
+ * static functions:
+ */
+
+static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
+static int mxser_init(void);
+
+/* static void mxser_poll(unsigned long); */
+static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
+static void mxser_do_softint(struct work_struct *);
+static int mxser_open(struct tty_struct *, struct file *);
+static void mxser_close(struct tty_struct *, struct file *);
+static int mxser_write(struct tty_struct *, const unsigned char *, int);
+static int mxser_write_room(struct tty_struct *);
+static void mxser_flush_buffer(struct tty_struct *);
+static int mxser_chars_in_buffer(struct tty_struct *);
+static void mxser_flush_chars(struct tty_struct *);
+static void mxser_put_char(struct tty_struct *, unsigned char);
+static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
+static int mxser_ioctl_special(unsigned int, void __user *);
+static void mxser_throttle(struct tty_struct *);
+static void mxser_unthrottle(struct tty_struct *);
+static void mxser_set_termios(struct tty_struct *, struct ktermios *);
+static void mxser_stop(struct tty_struct *);
+static void mxser_start(struct tty_struct *);
+static void mxser_hangup(struct tty_struct *);
+static void mxser_rs_break(struct tty_struct *, int);
+static irqreturn_t mxser_interrupt(int, void *);
+static void mxser_receive_chars(struct mxser_struct *, int *);
+static void mxser_transmit_chars(struct mxser_struct *);
+static void mxser_check_modem_status(struct mxser_struct *, int);
+static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
+static int mxser_startup(struct mxser_struct *);
+static void mxser_shutdown(struct mxser_struct *);
+static int mxser_change_speed(struct mxser_struct *, struct ktermios *old_termios);
+static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
+static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
+static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
+static void mxser_send_break(struct mxser_struct *, int);
+static int mxser_tiocmget(struct tty_struct *, struct file *);
+static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
+static int mxser_set_baud(struct mxser_struct *info, long newspd);
+static void mxser_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static void mxser_startrx(struct tty_struct *tty);
+static void mxser_stoprx(struct tty_struct *tty);
#ifdef CONFIG_PCI
-static int __devinit CheckIsMoxaMust(unsigned long io)
+static int CheckIsMoxaMust(int io)
{
u8 oldmcr, hwid;
int i;
@@ -324,15 +437,90 @@ static int __devinit CheckIsMoxaMust(unsigned long io)
}
GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
- for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
- if (hwid == Gpci_uart_info[i].type)
+ for (i = 0; i < UART_TYPE_NUM; i++) {
+ if (hwid == Gmoxa_uart_id[i])
return (int)hwid;
}
return MOXA_OTHER_UART;
}
#endif
-static void process_txrx_fifo(struct mxser_port *info)
+/* above is modified by Victor Yu. 08-15-2002 */
+
+static const struct tty_operations mxser_ops = {
+ .open = mxser_open,
+ .close = mxser_close,
+ .write = mxser_write,
+ .put_char = mxser_put_char,
+ .flush_chars = mxser_flush_chars,
+ .write_room = mxser_write_room,
+ .chars_in_buffer = mxser_chars_in_buffer,
+ .flush_buffer = mxser_flush_buffer,
+ .ioctl = mxser_ioctl,
+ .throttle = mxser_throttle,
+ .unthrottle = mxser_unthrottle,
+ .set_termios = mxser_set_termios,
+ .stop = mxser_stop,
+ .start = mxser_start,
+ .hangup = mxser_hangup,
+ .break_ctl = mxser_rs_break,
+ .wait_until_sent = mxser_wait_until_sent,
+ .tiocmget = mxser_tiocmget,
+ .tiocmset = mxser_tiocmset,
+};
+
+/*
+ * The MOXA Smartio/Industio serial driver boot-time initialization code!
+ */
+
+static int __init mxser_module_init(void)
+{
+ int ret;
+
+ if (verbose)
+ printk(KERN_DEBUG "Loading module mxser ...\n");
+ ret = mxser_init();
+ if (verbose)
+ printk(KERN_DEBUG "Done.\n");
+ return ret;
+}
+
+static void __exit mxser_module_exit(void)
+{
+ int i, err;
+
+ if (verbose)
+ printk(KERN_DEBUG "Unloading module mxser ...\n");
+
+ err = tty_unregister_driver(mxvar_sdriver);
+ if (!err)
+ put_tty_driver(mxvar_sdriver);
+ else
+ printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
+
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ struct pci_dev *pdev;
+
+ if (mxsercfg[i].board_type == -1)
+ continue;
+ else {
+ pdev = mxsercfg[i].pciInfo.pdev;
+ free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
+ if (pdev != NULL) { /* PCI */
+ release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
+ release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
+ pci_dev_put(pdev);
+ } else {
+ release_region(mxsercfg[i].ioaddr[0], 8 * mxsercfg[i].ports);
+ release_region(mxsercfg[i].vector, 1);
+ }
+ }
+ }
+ if (verbose)
+ printk(KERN_DEBUG "Done.\n");
+}
+
+static void process_txrx_fifo(struct mxser_struct *info)
{
int i;
@@ -341,586 +529,476 @@ static void process_txrx_fifo(struct mxser_port *info)
info->rx_high_water = 1;
info->rx_low_water = 1;
info->xmit_fifo_size = 1;
- } else
- for (i = 0; i < UART_INFO_NUM; i++)
- if (info->board->chip_flag == Gpci_uart_info[i].type) {
+ } else {
+ for (i = 0; i < UART_INFO_NUM; i++) {
+ if (info->IsMoxaMustChipFlag == Gpci_uart_info[i].type) {
info->rx_trigger = Gpci_uart_info[i].rx_trigger;
info->rx_low_water = Gpci_uart_info[i].rx_low_water;
info->rx_high_water = Gpci_uart_info[i].rx_high_water;
info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
break;
}
+ }
+ }
}
-static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
+static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
{
- unsigned char status = 0;
+ struct mxser_struct *info;
+ int retval;
+ int i, n;
- status = inb(baseaddr + UART_MSR);
+ n = board * MXSER_PORTS_PER_BOARD;
+ info = &mxvar_table[n];
+ /*if (verbose) */ {
+ printk(KERN_DEBUG " ttyMI%d - ttyMI%d ",
+ n, n + hwconf->ports - 1);
+ printk(" max. baud rate = %d bps.\n",
+ hwconf->MaxCanSetBaudRate[0]);
+ }
+
+ for (i = 0; i < hwconf->ports; i++, n++, info++) {
+ info->port = n;
+ info->base = hwconf->ioaddr[i];
+ info->irq = hwconf->irq;
+ info->vector = hwconf->vector;
+ info->vectormask = hwconf->vector_mask;
+ info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */
+ info->stop_rx = 0;
+ info->ldisc_stop_rx = 0;
- mxser_msr[port] &= 0x0F;
- mxser_msr[port] |= status;
- status = mxser_msr[port];
- if (mode)
- mxser_msr[port] = 0;
+ info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
+ /* Enhance mode enabled here */
+ if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
+ ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
+ }
- return status;
-}
+ info->flags = ASYNC_SHARE_IRQ;
+ info->type = hwconf->uart_type;
+ info->baud_base = hwconf->baud_base[i];
-static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
- struct mxser_port *port)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
- unsigned long flags;
+ info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i];
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- test_bit(TTY_IO_ERROR, &tty->flags)) {
- port->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
+ process_txrx_fifo(info);
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
+ info->custom_divisor = hwconf->baud_base[i] * 16;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = 30 * HZ;
+ INIT_WORK(&info->tqueue, mxser_do_softint);
+ info->normal_termios = mxvar_sdriver->init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ memset(&info->mon_data, 0, sizeof(struct mxser_mon));
+ info->err_shadow = 0;
+ spin_lock_init(&info->slock);
+ }
/*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, port->count is dropped by one, so that
- * mxser_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
+ * Allocate the IRQ if necessary
*/
- retval = 0;
- add_wait_queue(&port->open_wait, &wait);
- spin_lock_irqsave(&port->slock, flags);
- if (!tty_hung_up_p(filp))
- port->count--;
- spin_unlock_irqrestore(&port->slock, flags);
- port->blocked_open++;
- while (1) {
- spin_lock_irqsave(&port->slock, flags);
- outb(inb(port->ioaddr + UART_MCR) |
- UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&port->slock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
- if (port->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
- break;
- }
- if (!(port->flags & ASYNC_CLOSING) &&
- (do_clocal ||
- (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
+
+ /* before set INT ISR, disable all int */
+ for (i = 0; i < hwconf->ports; i++) {
+ outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0,
+ hwconf->ioaddr[i] + UART_IER);
}
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- if (retval)
+
+ n = board * MXSER_PORTS_PER_BOARD;
+ info = &mxvar_table[n];
+
+ retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+ "mxser", info);
+ if (retval) {
+ printk(KERN_ERR "Board %d: %s",
+ board, mxser_brdname[hwconf->board_type - 1]);
+ printk(" Request irq failed, IRQ (%d) may conflict with"
+ " another device.\n", info->irq);
return retval;
- port->flags |= ASYNC_NORMAL_ACTIVE;
+ }
return 0;
}
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
{
- int quot = 0, baud;
- unsigned char cval;
-
- if (!info->tty || !info->tty->termios)
- return -1;
+ mxsercfg[board] = *hwconf;
+}
- if (!(info->ioaddr))
- return -1;
+#ifdef CONFIG_PCI
+static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
+{
+ int i, j;
+ /* unsigned int val; */
+ unsigned int ioaddress;
+ struct pci_dev *pdev = hwconf->pciInfo.pdev;
- if (newspd > info->max_baud)
- return -1;
+ /* io address */
+ hwconf->board_type = board_type;
+ hwconf->ports = mxser_numports[board_type - 1];
+ ioaddress = pci_resource_start(pdev, 2);
+ request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2),
+ "mxser(IO)");
- if (newspd == 134) {
- quot = 2 * info->baud_base / 269;
- tty_encode_baud_rate(info->tty, 134, 134);
- } else if (newspd) {
- quot = info->baud_base / newspd;
- if (quot == 0)
- quot = 1;
- baud = info->baud_base/quot;
- tty_encode_baud_rate(info->tty, baud, baud);
- } else {
- quot = 0;
- }
+ for (i = 0; i < hwconf->ports; i++)
+ hwconf->ioaddr[i] = ioaddress + 8 * i;
- info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
- info->timeout += HZ / 50; /* Add .02 seconds of slop */
+ /* vector */
+ ioaddress = pci_resource_start(pdev, 3);
+ request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3),
+ "mxser(vector)");
+ hwconf->vector = ioaddress;
- if (quot) {
- info->MCR |= UART_MCR_DTR;
- outb(info->MCR, info->ioaddr + UART_MCR);
- } else {
- info->MCR &= ~UART_MCR_DTR;
- outb(info->MCR, info->ioaddr + UART_MCR);
- return 0;
- }
+ /* irq */
+ hwconf->irq = hwconf->pciInfo.pdev->irq;
- cval = inb(info->ioaddr + UART_LCR);
+ hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]);
+ hwconf->uart_type = PORT_16550A;
+ hwconf->vector_mask = 0;
- outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */
- outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */
- outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
- outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
+ for (i = 0; i < hwconf->ports; i++) {
+ for (j = 0; j < UART_INFO_NUM; j++) {
+ if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) {
+ hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud;
-#ifdef BOTHER
- if (C_BAUD(info->tty) == BOTHER) {
- quot = info->baud_base % newspd;
- quot *= 8;
- if (quot % newspd > newspd / 2) {
- quot /= newspd;
- quot++;
- } else
- quot /= newspd;
+ /* exception....CP-102 */
+ if (board_type == MXSER_BOARD_CP102)
+ hwconf->MaxCanSetBaudRate[i] = 921600;
+ break;
+ }
+ }
+ }
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
- } else
-#endif
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
+ if (hwconf->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID) {
+ for (i = 0; i < hwconf->ports; i++) {
+ if (i < 4)
+ hwconf->opmode_ioaddr[i] = ioaddress + 4;
+ else
+ hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
+ }
+ outb(0, ioaddress + 4); /* default set to RS232 mode */
+ outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
+ }
+ for (i = 0; i < hwconf->ports; i++) {
+ hwconf->vector_mask |= (1 << i);
+ hwconf->baud_base[i] = 921600;
+ }
return 0;
}
+#endif
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static int mxser_change_speed(struct mxser_port *info,
- struct ktermios *old_termios)
+static int mxser_init(void)
{
- unsigned cflag, cval, fcr;
- int ret = 0;
- unsigned char status;
+ int i, m, retval, b, n;
+ struct pci_dev *pdev = NULL;
+ int index;
+ unsigned char busnum, devnum;
+ struct mxser_hwconf hwconf;
- if (!info->tty || !info->tty->termios)
- return ret;
- cflag = info->tty->termios->c_cflag;
- if (!(info->ioaddr))
- return ret;
-
- if (mxser_set_baud_method[info->tty->index] == 0)
- mxser_set_baud(info, tty_get_baud_rate(info->tty));
+ mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
+ if (!mxvar_sdriver)
+ return -ENOMEM;
+ spin_lock_init(&gm_lock);
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5:
- cval = 0x00;
- break;
- case CS6:
- cval = 0x01;
- break;
- case CS7:
- cval = 0x02;
- break;
- case CS8:
- cval = 0x03;
- break;
- default:
- cval = 0x00;
- break; /* too keep GCC shut... */
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ mxsercfg[i].board_type = -1;
}
- if (cflag & CSTOPB)
- cval |= 0x04;
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
- if (cflag & CMSPAR)
- cval |= UART_LCR_SPAR;
- if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
- if (info->board->chip_flag) {
- fcr = UART_FCR_ENABLE_FIFO;
- fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
- } else
- fcr = 0;
- } else {
- fcr = UART_FCR_ENABLE_FIFO;
- if (info->board->chip_flag) {
- fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
- } else {
- switch (info->rx_trigger) {
- case 1:
- fcr |= UART_FCR_TRIGGER_1;
- break;
- case 4:
- fcr |= UART_FCR_TRIGGER_4;
- break;
- case 8:
- fcr |= UART_FCR_TRIGGER_8;
- break;
- default:
- fcr |= UART_FCR_TRIGGER_14;
- break;
- }
- }
- }
+ printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+ MXSER_VERSION);
- /* CTS flow control flag and modem status interrupts */
- info->IER &= ~UART_IER_MSI;
- info->MCR &= ~UART_MCR_AFE;
- if (cflag & CRTSCTS) {
- info->flags |= ASYNC_CTS_FLOW;
- info->IER |= UART_IER_MSI;
- if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
- info->MCR |= UART_MCR_AFE;
- } else {
- status = inb(info->ioaddr + UART_MSR);
- if (info->tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
- info->tty->hw_stopped = 0;
- if (info->type != PORT_16550A &&
- !info->board->chip_flag) {
- outb(info->IER & ~UART_IER_THRI,
- info->ioaddr +
- UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr +
- UART_IER);
- }
- tty_wakeup(info->tty);
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
- info->tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) &&
- (!info->board->chip_flag)) {
- info->IER &= ~UART_IER_THRI;
- outb(info->IER, info->ioaddr +
- UART_IER);
- }
- }
- }
+ /* Initialize the tty_driver structure */
+ memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
+ mxvar_sdriver->owner = THIS_MODULE;
+ mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
+ mxvar_sdriver->name = "ttyMI";
+ mxvar_sdriver->major = ttymajor;
+ mxvar_sdriver->minor_start = 0;
+ mxvar_sdriver->num = MXSER_PORTS + 1;
+ mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
+ mxvar_sdriver->init_termios = tty_std_termios;
+ mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ mxvar_sdriver->init_termios.c_ispeed = 9600;
+ mxvar_sdriver->init_termios.c_ospeed = 9600;
+ mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(mxvar_sdriver, &mxser_ops);
+ mxvar_sdriver->ttys = mxvar_tty;
+ mxvar_sdriver->termios = mxvar_termios;
+ mxvar_sdriver->termios_locked = mxvar_termios_locked;
+
+ mxvar_diagflag = 0;
+ memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));
+ memset(&mxvar_log, 0, sizeof(struct mxser_log));
+
+ memset(&mxser_msr, 0, sizeof(unsigned char) * (MXSER_PORTS + 1));
+ memset(&mon_data_ext, 0, sizeof(struct mxser_mon_ext));
+ memset(&mxser_set_baud_method, 0, sizeof(int) * (MXSER_PORTS + 1));
+ memset(&hwconf, 0, sizeof(struct mxser_hwconf));
+
+ m = 0;
+ /* Start finding ISA boards here */
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ int cap;
+
+ if (!(cap = mxserBoardCAP[b]))
+ continue;
+
+ retval = mxser_get_ISA_conf(cap, &hwconf);
+
+ if (retval != 0)
+ printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk(KERN_ERR "Invalid interrupt vector, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
+
+ continue;
}
- } else {
- info->flags &= ~ASYNC_CTS_FLOW;
- }
- outb(info->MCR, info->ioaddr + UART_MCR);
- if (cflag & CLOCAL) {
- info->flags &= ~ASYNC_CHECK_CD;
- } else {
- info->flags |= ASYNC_CHECK_CD;
- info->IER |= UART_IER_MSI;
+
+ hwconf.pciInfo.busNum = 0;
+ hwconf.pciInfo.devNum = 0;
+ hwconf.pciInfo.pdev = NULL;
+
+ mxser_getcfg(m, &hwconf);
+ /*
+ * init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+
+ m++;
}
- outb(info->IER, info->ioaddr + UART_IER);
- /*
- * Set up parity check flag
- */
- info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (I_INPCK(info->tty))
- info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
- info->read_status_mask |= UART_LSR_BI;
+ /* Start finding ISA boards from module arg */
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ int cap;
- info->ignore_status_mask = 0;
+ if (!(cap = ioaddr[b]))
+ continue;
- if (I_IGNBRK(info->tty)) {
- info->ignore_status_mask |= UART_LSR_BI;
- info->read_status_mask |= UART_LSR_BI;
+ retval = mxser_get_ISA_conf(cap, &hwconf);
+
+ if (retval != 0)
+ printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk(KERN_ERR "Invalid interrupt vector, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
+
+ continue;
+ }
+
+ hwconf.pciInfo.busNum = 0;
+ hwconf.pciInfo.devNum = 0;
+ hwconf.pciInfo.pdev = NULL;
+
+ mxser_getcfg(m, &hwconf);
/*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
+ * init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
*/
- if (I_IGNPAR(info->tty)) {
- info->ignore_status_mask |=
- UART_LSR_OE |
- UART_LSR_PE |
- UART_LSR_FE;
- info->read_status_mask |=
- UART_LSR_OE |
- UART_LSR_PE |
- UART_LSR_FE;
- }
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+
+ m++;
}
- if (info->board->chip_flag) {
- SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
- SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
- if (I_IXON(info->tty)) {
- ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- } else {
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+
+ /* start finding PCI board here */
+#ifdef CONFIG_PCI
+ n = ARRAY_SIZE(mxser_pcibrds) - 1;
+ index = 0;
+ b = 0;
+ while (b < n) {
+ pdev = pci_get_device(mxser_pcibrds[b].vendor,
+ mxser_pcibrds[b].device, pdev);
+ if (pdev == NULL) {
+ b++;
+ continue;
}
- if (I_IXOFF(info->tty)) {
- ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- } else {
- DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ hwconf.pciInfo.busNum = busnum = pdev->bus->number;
+ hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3;
+ hwconf.pciInfo.pdev = pdev;
+ printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+ mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
+ busnum, devnum >> 3);
+ index++;
+ if (m >= MXSER_BOARDS)
+ printk(KERN_ERR
+ "Too many Smartio/Industio family boards find "
+ "(maximum %d), board not configured\n",
+ MXSER_BOARDS);
+ else {
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "Moxa SmartI/O PCI enable "
+ "fail !\n");
+ continue;
+ }
+ retval = mxser_get_PCI_conf(busnum, devnum,
+ (int)mxser_pcibrds[b].driver_data,
+ &hwconf);
+ if (retval < 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk(KERN_ERR
+ "Invalid interrupt number, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk(KERN_ERR
+ "Invalid interrupt number, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk(KERN_ERR
+ "Invalid interrupt vector, "
+ "board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk(KERN_ERR
+ "Invalid I/O address, "
+ "board not configured\n");
+ continue;
+ }
+ mxser_getcfg(m, &hwconf);
+ /* init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+ m++;
+ /* Keep an extra reference if we succeeded. It will
+ be returned at unload time */
+ pci_dev_get(pdev);
}
}
+#endif
+ retval = tty_register_driver(mxvar_sdriver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
+ " driver !\n");
+ put_tty_driver(mxvar_sdriver);
- outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
- outb(cval, info->ioaddr + UART_LCR);
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ if (mxsercfg[i].board_type == -1)
+ continue;
+ else {
+ free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
+ /* todo: release io, vector */
+ }
+ }
+ return retval;
+ }
- return ret;
+ return 0;
}
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_do_softint(struct work_struct *work)
{
- /* update input line counters */
- if (status & UART_MSR_TERI)
- port->icount.rng++;
- if (status & UART_MSR_DDSR)
- port->icount.dsr++;
- if (status & UART_MSR_DDCD)
- port->icount.dcd++;
- if (status & UART_MSR_DCTS)
- port->icount.cts++;
- port->mon_data.modem_status = status;
- wake_up_interruptible(&port->delta_msr_wait);
+ struct mxser_struct *info =
+ container_of(work, struct mxser_struct, tqueue);
+ struct tty_struct *tty;
- if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
- if (status & UART_MSR_DCD)
- wake_up_interruptible(&port->open_wait);
- }
+ tty = info->tty;
- if (port->flags & ASYNC_CTS_FLOW) {
- if (port->tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
- port->tty->hw_stopped = 0;
-
- if ((port->type != PORT_16550A) &&
- (!port->board->chip_flag)) {
- outb(port->IER & ~UART_IER_THRI,
- port->ioaddr + UART_IER);
- port->IER |= UART_IER_THRI;
- outb(port->IER, port->ioaddr +
- UART_IER);
- }
- tty_wakeup(port->tty);
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
- port->tty->hw_stopped = 1;
- if (port->type != PORT_16550A &&
- !port->board->chip_flag) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr +
- UART_IER);
- }
- }
- }
+ if (tty) {
+ if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
+ tty_wakeup(tty);
+ if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event))
+ tty_hangup(tty);
}
}
-static int mxser_startup(struct mxser_port *info)
+static unsigned char mxser_get_msr(int baseaddr, int mode, int port, struct mxser_struct *info)
{
- unsigned long page;
- unsigned long flags;
+ unsigned char status = 0;
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
+ status = inb(baseaddr + UART_MSR);
- spin_lock_irqsave(&info->slock, flags);
+ mxser_msr[port] &= 0x0F;
+ mxser_msr[port] |= status;
+ status = mxser_msr[port];
+ if (mode)
+ mxser_msr[port] = 0;
- if (info->flags & ASYNC_INITIALIZED) {
- free_page(page);
- spin_unlock_irqrestore(&info->slock, flags);
- return 0;
- }
+ return status;
+}
- if (!info->ioaddr || !info->type) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- free_page(page);
- spin_unlock_irqrestore(&info->slock, flags);
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_struct *info;
+ int retval, line;
+
+ /* initialize driver_data in case something fails */
+ tty->driver_data = NULL;
+
+ line = tty->index;
+ if (line == MXSER_PORTS)
return 0;
- }
- if (info->xmit_buf)
- free_page(page);
- else
- info->xmit_buf = (unsigned char *) page;
+ if (line < 0 || line > MXSER_PORTS)
+ return -ENODEV;
+ info = mxvar_table + line;
+ if (!info->base)
+ return -ENODEV;
+ tty->driver_data = info;
+ info->tty = tty;
/*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in mxser_change_speed())
+ * Start up serial port
*/
- if (info->board->chip_flag)
- outb((UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT |
- MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
- else
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
- info->ioaddr + UART_FCR);
+ retval = mxser_startup(info);
+ if (retval)
+ return retval;
- /*
- * At this point there's no way the LSR could still be 0xFF;
- * if it is, then bail out, because there's likely no UART
- * here.
- */
- if (inb(info->ioaddr + UART_LSR) == 0xff) {
- spin_unlock_irqrestore(&info->slock, flags);
- if (capable(CAP_SYS_ADMIN)) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- return 0;
- } else
- return -ENODEV;
- }
-
- /*
- * Clear the interrupt registers.
- */
- (void) inb(info->ioaddr + UART_LSR);
- (void) inb(info->ioaddr + UART_RX);
- (void) inb(info->ioaddr + UART_IIR);
- (void) inb(info->ioaddr + UART_MSR);
-
- /*
- * Now, initialize the UART
- */
- outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
- outb(info->MCR, info->ioaddr + UART_MCR);
-
- /*
- * Finally, enable interrupts
- */
- info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-
- if (info->board->chip_flag)
- info->IER |= MOXA_MUST_IER_EGDAI;
- outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */
-
- /*
- * And clear the interrupt registers again for luck.
- */
- (void) inb(info->ioaddr + UART_LSR);
- (void) inb(info->ioaddr + UART_RX);
- (void) inb(info->ioaddr + UART_IIR);
- (void) inb(info->ioaddr + UART_MSR);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /*
- * and set the speed of the serial port
- */
- mxser_change_speed(info, NULL);
- info->flags |= ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&info->slock, flags);
-
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void mxser_shutdown(struct mxser_port *info)
-{
- unsigned long flags;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
- spin_lock_irqsave(&info->slock, flags);
+ retval = mxser_block_til_ready(tty, filp, info);
+ if (retval)
+ return retval;
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
- * here so the queue might never be waken up
- */
- wake_up_interruptible(&info->delta_msr_wait);
+ info->count++;
- /*
- * Free the IRQ, if necessary
- */
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = NULL;
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ mxser_change_speed(info, NULL);
}
- info->IER = 0;
- outb(0x00, info->ioaddr + UART_IER);
-
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
- outb(info->MCR, info->ioaddr + UART_MCR);
-
- /* clear Rx/Tx FIFO's */
- if (info->board->chip_flag)
- outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
- MOXA_MUST_FCR_GDA_MODE_ENABLE,
- info->ioaddr + UART_FCR);
- else
- outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
- info->ioaddr + UART_FCR);
-
- /* read data port to reset things */
- (void) inb(info->ioaddr + UART_RX);
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- info->flags &= ~ASYNC_INITIALIZED;
-
- if (info->board->chip_flag)
- SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-
- spin_unlock_irqrestore(&info->slock, flags);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int mxser_open(struct tty_struct *tty, struct file *filp)
-{
- struct mxser_port *info;
- unsigned long flags;
- int retval, line;
-
- line = tty->index;
- if (line == MXSER_PORTS)
- return 0;
- if (line < 0 || line > MXSER_PORTS)
- return -ENODEV;
- info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
- if (!info->ioaddr)
- return -ENODEV;
-
- tty->driver_data = info;
- info->tty = tty;
/*
- * Start up serial port
- */
- spin_lock_irqsave(&info->slock, flags);
- info->count++;
- spin_unlock_irqrestore(&info->slock, flags);
- retval = mxser_startup(info);
- if (retval)
- return retval;
-
- retval = mxser_block_til_ready(tty, filp, info);
- if (retval)
- return retval;
+ status = mxser_get_msr(info->base, 0, info->port);
+ mxser_check_modem_status(info, status);
+ */
/* unmark here for very high baud rate (ex. 921600 bps) used */
tty->low_latency = 1;
@@ -935,10 +1013,11 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
*/
static void mxser_close(struct tty_struct *tty, struct file *filp)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long timeout;
unsigned long flags;
+ struct tty_ldisc *ld;
if (tty->index == MXSER_PORTS)
return;
@@ -965,7 +1044,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
if (--info->count < 0) {
printk(KERN_ERR "mxser_close: bad serial port count for "
- "ttys%d: %d\n", tty->index, info->count);
+ "ttys%d: %d\n", info->port, info->count);
info->count = 0;
}
if (info->count) {
@@ -994,18 +1073,20 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
* line status register.
*/
info->IER &= ~UART_IER_RLSI;
- if (info->board->chip_flag)
+ if (info->IsMoxaMustChipFlag)
info->IER &= ~MOXA_MUST_RECV_ISR;
-
+/* by William
+ info->read_status_mask &= ~UART_LSR_DR;
+*/
if (info->flags & ASYNC_INITIALIZED) {
- outb(info->IER, info->ioaddr + UART_IER);
+ outb(info->IER, info->base + UART_IER);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
timeout = jiffies + HZ;
- while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
+ while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) {
schedule_timeout_interruptible(5);
if (time_after(jiffies, timeout))
break;
@@ -1015,9 +1096,14 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
-
- tty_ldisc_flush(tty);
-
+
+ ld = tty_ldisc_ref(tty);
+ if (ld) {
+ if (ld->flush_buffer)
+ ld->flush_buffer(tty);
+ tty_ldisc_deref(ld);
+ }
+
tty->closing = 0;
info->event = 0;
info->tty = NULL;
@@ -1028,12 +1114,14 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+
}
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int c, total = 0;
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
if (!info->xmit_buf)
@@ -1057,15 +1145,13 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
total += c;
}
- if (info->xmit_cnt && !tty->stopped) {
+ if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
- (info->board->chip_flag)) {
+ (info->IsMoxaMustChipFlag)) {
spin_lock_irqsave(&info->slock, flags);
- outb(info->IER & ~UART_IER_THRI, info->ioaddr +
- UART_IER);
info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
+ outb(info->IER, info->base + UART_IER);
spin_unlock_irqrestore(&info->slock, flags);
}
}
@@ -1074,7 +1160,7 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
if (!info->xmit_buf)
@@ -1088,14 +1174,13 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
- if (!tty->stopped) {
+ if (!tty->stopped && !(info->IER & UART_IER_THRI)) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
- info->board->chip_flag) {
+ info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
- outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
+ outb(info->IER, info->base + UART_IER);
spin_unlock_irqrestore(&info->slock, flags);
}
}
@@ -1104,7 +1189,7 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
static void mxser_flush_chars(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
if (info->xmit_cnt <= 0 ||
@@ -1112,22 +1197,21 @@ static void mxser_flush_chars(struct tty_struct *tty)
!info->xmit_buf ||
(tty->hw_stopped &&
(info->type != PORT_16550A) &&
- (!info->board->chip_flag)
+ (!info->IsMoxaMustChipFlag)
))
return;
spin_lock_irqsave(&info->slock, flags);
- outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
+ outb(info->IER, info->base + UART_IER);
spin_unlock_irqrestore(&info->slock, flags);
}
static int mxser_write_room(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
int ret;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -1138,13 +1222,13 @@ static int mxser_write_room(struct tty_struct *tty)
static int mxser_chars_in_buffer(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
return info->xmit_cnt;
}
static void mxser_flush_buffer(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
char fcr;
unsigned long flags;
@@ -1152,421 +1236,360 @@ static void mxser_flush_buffer(struct tty_struct *tty)
spin_lock_irqsave(&info->slock, flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- fcr = inb(info->ioaddr + UART_FCR);
+ /* below added by shinhay */
+ fcr = inb(info->base + UART_FCR);
outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
- info->ioaddr + UART_FCR);
- outb(fcr, info->ioaddr + UART_FCR);
+ info->base + UART_FCR);
+ outb(fcr, info->base + UART_FCR);
spin_unlock_irqrestore(&info->slock, flags);
+ /* above added by shinhay */
tty_wakeup(tty);
}
-/*
- * ------------------------------------------------------------
- * friends of mxser_ioctl()
- * ------------------------------------------------------------
- */
-static int mxser_get_serial_info(struct mxser_port *info,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp = {
- .type = info->type,
- .line = info->tty->index,
- .port = info->ioaddr,
- .irq = info->board->irq,
- .flags = info->flags,
- .baud_base = info->baud_base,
- .close_delay = info->close_delay,
- .closing_wait = info->closing_wait,
- .custom_divisor = info->custom_divisor,
- .hub6 = 0
- };
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int mxser_set_serial_info(struct mxser_port *info,
- struct serial_struct __user *new_info)
+static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct serial_struct new_serial;
- speed_t baud;
- unsigned long sl_flags;
- unsigned int flags;
- int retval = 0;
-
- if (!new_info || !info->ioaddr)
- return -ENODEV;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ struct mxser_struct *info = tty->driver_data;
+ int retval;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser;
+ unsigned long templ;
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
- if (new_serial.irq != info->board->irq ||
- new_serial.port != info->ioaddr)
- return -EINVAL;
+ if (tty->index == MXSER_PORTS)
+ return mxser_ioctl_special(cmd, argp);
- flags = info->flags & ASYNC_SPD_MASK;
+ /* following add by Victor Yu. 01-05-2004 */
+ if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
+ int opmode, p;
+ static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
+ int shiftbit;
+ unsigned char val, mask;
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- } else {
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
- info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->close_delay = new_serial.close_delay * HZ / 100;
- info->closing_wait = new_serial.closing_wait * HZ / 100;
- info->tty->low_latency =
- (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->tty->low_latency = 0;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
- (new_serial.baud_base != info->baud_base ||
- new_serial.custom_divisor !=
- info->custom_divisor)) {
- baud = new_serial.baud_base / new_serial.custom_divisor;
- tty_encode_baud_rate(info->tty, baud, baud);
+ p = info->port % 4;
+ if (cmd == MOXA_SET_OP_MODE) {
+ if (get_user(opmode, (int __user *) argp))
+ return -EFAULT;
+ if (opmode != RS232_MODE &&
+ opmode != RS485_2WIRE_MODE &&
+ opmode != RS422_MODE &&
+ opmode != RS485_4WIRE_MODE)
+ return -EFAULT;
+ mask = ModeMask[p];
+ shiftbit = p * 2;
+ val = inb(info->opmode_ioaddr);
+ val &= mask;
+ val |= (opmode << shiftbit);
+ outb(val, info->opmode_ioaddr);
+ } else {
+ shiftbit = p * 2;
+ opmode = inb(info->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+ if (copy_to_user(argp, &opmode, sizeof(int)))
+ return -EFAULT;
}
+ return 0;
}
+ /* above add by Victor Yu. 01-05-2004 */
- info->type = new_serial.type;
-
- process_txrx_fifo(info);
-
- if (info->flags & ASYNC_INITIALIZED) {
- if (flags != (info->flags & ASYNC_SPD_MASK)) {
- spin_lock_irqsave(&info->slock, sl_flags);
- mxser_change_speed(info, NULL);
- spin_unlock_irqrestore(&info->slock, sl_flags);
- }
- } else
- retval = mxser_startup(info);
-
- return retval;
-}
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ mxser_send_break(info, HZ / 4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+ return 0;
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
+ case TIOCSSOFTCAR:
+ if (get_user(templ, (unsigned long __user *) argp))
+ return -EFAULT;
+ arg = templ;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCGSERIAL:
+ return mxser_get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ return mxser_set_serial_info(info, argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return mxser_get_lsr_info(info, argp);
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->slock, flags);
-/*
- * mxser_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int mxser_get_lsr_info(struct mxser_port *info,
- unsigned int __user *value)
-{
- unsigned char status;
- unsigned int result;
- unsigned long flags;
+ wait_event_interruptible(info->delta_msr_wait, ({
+ cprev = cnow;
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount; /* atomic copy */
+ spin_unlock_irqrestore(&info->slock, flags);
- spin_lock_irqsave(&info->slock, flags);
- status = inb(info->ioaddr + UART_LSR);
- spin_unlock_irqrestore(&info->slock, flags);
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void mxser_send_break(struct mxser_port *info, int duration)
-{
- unsigned long flags;
-
- if (!info->ioaddr)
- return;
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
- info->ioaddr + UART_LCR);
- spin_unlock_irqrestore(&info->slock, flags);
- schedule_timeout(duration);
- spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
- info->ioaddr + UART_LCR);
- spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct mxser_port *info = tty->driver_data;
- unsigned char control, status;
- unsigned long flags;
+ ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
+ }));
+ break;
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->slock, flags);
+ p_cuser = argp;
+ /* modified by casper 1/11/2000 */
+ if (put_user(cnow.frame, &p_cuser->frame))
+ return -EFAULT;
+ if (put_user(cnow.brk, &p_cuser->brk))
+ return -EFAULT;
+ if (put_user(cnow.overrun, &p_cuser->overrun))
+ return -EFAULT;
+ if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+ return -EFAULT;
+ if (put_user(cnow.parity, &p_cuser->parity))
+ return -EFAULT;
+ if (put_user(cnow.rx, &p_cuser->rx))
+ return -EFAULT;
+ if (put_user(cnow.tx, &p_cuser->tx))
+ return -EFAULT;
+ put_user(cnow.cts, &p_cuser->cts);
+ put_user(cnow.dsr, &p_cuser->dsr);
+ put_user(cnow.rng, &p_cuser->rng);
+ put_user(cnow.dcd, &p_cuser->dcd);
+ return 0;
+ case MOXA_HighSpeedOn:
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+ case MOXA_SDS_RSTICOUNTER: {
+ info->mon_data.rxcnt = 0;
+ info->mon_data.txcnt = 0;
+ return 0;
+ }
+/* (above) added by James. */
+ case MOXA_ASPP_SETBAUD:{
+ long baud;
+ if (get_user(baud, (long __user *)argp))
+ return -EFAULT;
+ mxser_set_baud(info, baud);
+ return 0;
+ }
+ case MOXA_ASPP_GETBAUD:
+ if (copy_to_user(argp, &info->realbaud, sizeof(long)))
+ return -EFAULT;
+ return 0;
- if (tty->index == MXSER_PORTS)
- return -ENOIOCTLCMD;
- if (test_bit(TTY_IO_ERROR, &tty->flags))
- return -EIO;
+ case MOXA_ASPP_OQUEUE:{
+ int len, lsr;
- control = info->MCR;
+ len = mxser_chars_in_buffer(tty);
- spin_lock_irqsave(&info->slock, flags);
- status = inb(info->ioaddr + UART_MSR);
- if (status & UART_MSR_ANY_DELTA)
- mxser_check_modem_status(info, status);
- spin_unlock_irqrestore(&info->slock, flags);
- return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
- ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
- ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
- ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
- ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
- ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-}
+ lsr = inb(info->base + UART_LSR) & UART_LSR_TEMT;
-static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct mxser_port *info = tty->driver_data;
- unsigned long flags;
+ len += (lsr ? 0 : 1);
+ if (copy_to_user(argp, &len, sizeof(int)))
+ return -EFAULT;
- if (tty->index == MXSER_PORTS)
- return -ENOIOCTLCMD;
- if (test_bit(TTY_IO_ERROR, &tty->flags))
- return -EIO;
+ return 0;
+ }
+ case MOXA_ASPP_MON: {
+ int mcr, status;
- spin_lock_irqsave(&info->slock, flags);
+ /* info->mon_data.ser_param = tty->termios->c_cflag; */
- if (set & TIOCM_RTS)
- info->MCR |= UART_MCR_RTS;
- if (set & TIOCM_DTR)
- info->MCR |= UART_MCR_DTR;
+ status = mxser_get_msr(info->base, 1, info->port, info);
+ mxser_check_modem_status(info, status);
- if (clear & TIOCM_RTS)
- info->MCR &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR)
- info->MCR &= ~UART_MCR_DTR;
+ mcr = inb(info->base + UART_MCR);
+ if (mcr & MOXA_MUST_MCR_XON_FLAG)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
- outb(info->MCR, info->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
- return 0;
-}
+ if (mcr & MOXA_MUST_MCR_TX_XON)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
-static int __init mxser_program_mode(int port)
-{
- int id, i, j, n;
+ if (info->tty->hw_stopped)
+ info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
+ else
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
- outb(0, port);
- outb(0, port);
- outb(0, port);
- (void)inb(port);
- (void)inb(port);
- outb(0, port);
- (void)inb(port);
+ if (copy_to_user(argp, &info->mon_data,
+ sizeof(struct mxser_mon)))
+ return -EFAULT;
- id = inb(port + 1) & 0x1F;
- if ((id != C168_ASIC_ID) &&
- (id != C104_ASIC_ID) &&
- (id != C102_ASIC_ID) &&
- (id != CI132_ASIC_ID) &&
- (id != CI134_ASIC_ID) &&
- (id != CI104J_ASIC_ID))
- return -1;
- for (i = 0, j = 0; i < 4; i++) {
- n = inb(port + 2);
- if (n == 'M') {
- j = 1;
- } else if ((j == 1) && (n == 1)) {
- j = 2;
- break;
- } else
- j = 0;
- }
- if (j != 2)
- id = -2;
- return id;
-}
+ return 0;
+ }
-static void __init mxser_normal_mode(int port)
-{
- int i, n;
+ case MOXA_ASPP_LSTATUS: {
+ if (copy_to_user(argp, &info->err_shadow,
+ sizeof(unsigned char)))
+ return -EFAULT;
- outb(0xA5, port + 1);
- outb(0x80, port + 3);
- outb(12, port + 0); /* 9600 bps */
- outb(0, port + 1);
- outb(0x03, port + 3); /* 8 data bits */
- outb(0x13, port + 4); /* loop back mode */
- for (i = 0; i < 16; i++) {
- n = inb(port + 5);
- if ((n & 0x61) == 0x60)
- break;
- if ((n & 1) == 1)
- (void)inb(port);
- }
- outb(0x00, port + 4);
-}
+ info->err_shadow = 0;
+ return 0;
+ }
+ case MOXA_SET_BAUD_METHOD: {
+ int method;
-#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
-#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
-#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
-#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
-#define EN_CCMD 0x000 /* Chip's command register */
-#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
-#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
-#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
-#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
-#define EN0_DCFG 0x00E /* Data configuration reg WR */
-#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
-#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
-#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
-static int __init mxser_read_register(int port, unsigned short *regs)
-{
- int i, k, value, id;
- unsigned int j;
+ if (get_user(method, (int __user *)argp))
+ return -EFAULT;
+ mxser_set_baud_method[info->port] = method;
+ if (copy_to_user(argp, &method, sizeof(int)))
+ return -EFAULT;
- id = mxser_program_mode(port);
- if (id < 0)
- return id;
- for (i = 0; i < 14; i++) {
- k = (i & 0x3F) | 0x180;
- for (j = 0x100; j > 0; j >>= 1) {
- outb(CHIP_CS, port);
- if (k & j) {
- outb(CHIP_CS | CHIP_DO, port);
- outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
- } else {
- outb(CHIP_CS, port);
- outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
- }
- }
- (void)inb(port);
- value = 0;
- for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
- outb(CHIP_CS, port);
- outb(CHIP_CS | CHIP_SK, port);
- if (inb(port) & CHIP_DI)
- value |= j;
+ return 0;
}
- regs[i] = value;
- outb(0, port);
+ default:
+ return -ENOIOCTLCMD;
}
- mxser_normal_mode(port);
- return id;
+ return 0;
}
+#ifndef CMSPAR
+#define CMSPAR 010000000000
+#endif
+
static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
{
- struct mxser_port *port;
- int result, status;
- unsigned int i, j;
+ int i, result, status;
switch (cmd) {
+ case MOXA_GET_CONF:
+ if (copy_to_user(argp, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
+ return -EFAULT;
+ return 0;
case MOXA_GET_MAJOR:
- return put_user(ttymajor, (int __user *)argp);
+ if (copy_to_user(argp, &ttymajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_GET_CUMAJOR:
+ if (copy_to_user(argp, &calloutmajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
case MOXA_CHKPORTENABLE:
result = 0;
-
- for (i = 0; i < MXSER_BOARDS; i++)
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
- if (mxser_boards[i].ports[j].ioaddr)
- result |= (1 << i);
-
+ for (i = 0; i < MXSER_PORTS; i++) {
+ if (mxvar_table[i].base)
+ result |= (1 << i);
+ }
return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
return -EFAULT;
return 0;
case MOXA_GETMSTATUS:
- for (i = 0; i < MXSER_BOARDS; i++)
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
- port = &mxser_boards[i].ports[j];
-
- GMStatus[i].ri = 0;
- if (!port->ioaddr) {
- GMStatus[i].dcd = 0;
- GMStatus[i].dsr = 0;
- GMStatus[i].cts = 0;
- continue;
- }
+ for (i = 0; i < MXSER_PORTS; i++) {
+ GMStatus[i].ri = 0;
+ if (!mxvar_table[i].base) {
+ GMStatus[i].dcd = 0;
+ GMStatus[i].dsr = 0;
+ GMStatus[i].cts = 0;
+ continue;
+ }
- if (!port->tty || !port->tty->termios)
- GMStatus[i].cflag =
- port->normal_termios.c_cflag;
- else
- GMStatus[i].cflag =
- port->tty->termios->c_cflag;
+ if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios)
+ GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag;
+ else
+ GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag;
- status = inb(port->ioaddr + UART_MSR);
- if (status & 0x80 /*UART_MSR_DCD */ )
- GMStatus[i].dcd = 1;
- else
- GMStatus[i].dcd = 0;
+ status = inb(mxvar_table[i].base + UART_MSR);
+ if (status & 0x80 /*UART_MSR_DCD */ )
+ GMStatus[i].dcd = 1;
+ else
+ GMStatus[i].dcd = 0;
- if (status & 0x20 /*UART_MSR_DSR */ )
- GMStatus[i].dsr = 1;
- else
- GMStatus[i].dsr = 0;
+ if (status & 0x20 /*UART_MSR_DSR */ )
+ GMStatus[i].dsr = 1;
+ else
+ GMStatus[i].dsr = 0;
- if (status & 0x10 /*UART_MSR_CTS */ )
- GMStatus[i].cts = 1;
- else
- GMStatus[i].cts = 0;
- }
+ if (status & 0x10 /*UART_MSR_CTS */ )
+ GMStatus[i].cts = 1;
+ else
+ GMStatus[i].cts = 0;
+ }
if (copy_to_user(argp, GMStatus,
sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
return 0;
case MOXA_ASPP_MON_EXT: {
- int p, shiftbit;
- unsigned long opmode;
- unsigned cflag, iflag;
-
- for (i = 0; i < MXSER_BOARDS; i++)
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
- port = &mxser_boards[i].ports[j];
- if (!port->ioaddr)
- continue;
+ int status;
+ int opmode, p;
+ int shiftbit;
+ unsigned cflag, iflag;
- status = mxser_get_msr(port->ioaddr, 0, i);
+ for (i = 0; i < MXSER_PORTS; i++) {
+ if (!mxvar_table[i].base)
+ continue;
+ status = mxser_get_msr(mxvar_table[i].base, 0,
+ i, &(mxvar_table[i]));
+ /*
+ mxser_check_modem_status(&mxvar_table[i],
+ status);
+ */
if (status & UART_MSR_TERI)
- port->icount.rng++;
+ mxvar_table[i].icount.rng++;
if (status & UART_MSR_DDSR)
- port->icount.dsr++;
+ mxvar_table[i].icount.dsr++;
if (status & UART_MSR_DDCD)
- port->icount.dcd++;
+ mxvar_table[i].icount.dcd++;
if (status & UART_MSR_DCTS)
- port->icount.cts++;
-
- port->mon_data.modem_status = status;
- mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
- mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
- mon_data_ext.up_rxcnt[i] =
- port->mon_data.up_rxcnt;
- mon_data_ext.up_txcnt[i] =
- port->mon_data.up_txcnt;
- mon_data_ext.modem_status[i] =
- port->mon_data.modem_status;
- mon_data_ext.baudrate[i] =
- tty_get_baud_rate(port->tty);
-
- if (!port->tty || !port->tty->termios) {
- cflag = port->normal_termios.c_cflag;
- iflag = port->normal_termios.c_iflag;
+ mxvar_table[i].icount.cts++;
+
+ mxvar_table[i].mon_data.modem_status = status;
+ mon_data_ext.rx_cnt[i] = mxvar_table[i].mon_data.rxcnt;
+ mon_data_ext.tx_cnt[i] = mxvar_table[i].mon_data.txcnt;
+ mon_data_ext.up_rxcnt[i] = mxvar_table[i].mon_data.up_rxcnt;
+ mon_data_ext.up_txcnt[i] = mxvar_table[i].mon_data.up_txcnt;
+ mon_data_ext.modem_status[i] = mxvar_table[i].mon_data.modem_status;
+ mon_data_ext.baudrate[i] = mxvar_table[i].realbaud;
+
+ if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios) {
+ cflag = mxvar_table[i].normal_termios.c_cflag;
+ iflag = mxvar_table[i].normal_termios.c_iflag;
} else {
- cflag = port->tty->termios->c_cflag;
- iflag = port->tty->termios->c_iflag;
+ cflag = mxvar_table[i].tty->termios->c_cflag;
+ iflag = mxvar_table[i].tty->termios->c_iflag;
}
mon_data_ext.databits[i] = cflag & CSIZE;
mon_data_ext.stopbits[i] = cflag & CSTOPB;
- mon_data_ext.parity[i] =
- cflag & (PARENB | PARODD | CMSPAR);
+ mon_data_ext.parity[i] = cflag & (PARENB | PARODD | CMSPAR);
mon_data_ext.flowctrl[i] = 0x00;
@@ -1576,260 +1599,101 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (iflag & (IXON | IXOFF))
mon_data_ext.flowctrl[i] |= 0x0C;
- if (port->type == PORT_16550A)
+ if (mxvar_table[i].type == PORT_16550A)
mon_data_ext.fifo[i] = 1;
else
mon_data_ext.fifo[i] = 0;
p = i % 4;
shiftbit = p * 2;
- opmode = inb(port->opmode_ioaddr) >> shiftbit;
+ opmode = inb(mxvar_table[i].opmode_ioaddr) >> shiftbit;
opmode &= OP_MODE_MASK;
mon_data_ext.iftype[i] = opmode;
}
- if (copy_to_user(argp, &mon_data_ext,
- sizeof(mon_data_ext)))
+ if (copy_to_user(argp, &mon_data_ext, sizeof(struct mxser_mon_ext)))
return -EFAULT;
return 0;
- } default:
+ }
+ default:
return -ENOIOCTLCMD;
}
return 0;
}
-static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg,
- struct async_icount *cprev)
+static void mxser_stoprx(struct tty_struct *tty)
{
- struct async_icount cnow;
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&info->slock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->slock, flags);
-
- ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+ struct mxser_struct *info = tty->driver_data;
+ /* unsigned long flags; */
- *cprev = cnow;
+ info->ldisc_stop_rx = 1;
+ if (I_IXOFF(tty)) {
+ /* MX_LOCK(&info->slock); */
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag) {
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->base + UART_IER);
+ } else {
+ /* above add by Victor Yu. 09-02-2002 */
+ info->x_char = STOP_CHAR(tty);
+ /* mask by Victor Yu. 09-02-2002 */
+ /* outb(info->IER, 0); */
+ outb(0, info->base + UART_IER);
+ info->IER |= UART_IER_THRI;
+ /* force Tx interrupt */
+ outb(info->IER, info->base + UART_IER);
+ } /* add by Victor Yu. 09-02-2002 */
+ /* MX_UNLOCK(&info->slock); */
+ }
- return ret;
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ /* MX_LOCK(&info->slock); */
+ info->MCR &= ~UART_MCR_RTS;
+ outb(info->MCR, info->base + UART_MCR);
+ /* MX_UNLOCK(&info->slock); */
+ }
}
-static int mxser_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
+static void mxser_startrx(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
- struct async_icount cnow;
- struct serial_icounter_struct __user *p_cuser;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
- int retval;
-
- if (tty->index == MXSER_PORTS)
- return mxser_ioctl_special(cmd, argp);
-
- if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
- int p;
- unsigned long opmode;
- static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
- int shiftbit;
- unsigned char val, mask;
-
- p = tty->index % 4;
- if (cmd == MOXA_SET_OP_MODE) {
- if (get_user(opmode, (int __user *) argp))
- return -EFAULT;
- if (opmode != RS232_MODE &&
- opmode != RS485_2WIRE_MODE &&
- opmode != RS422_MODE &&
- opmode != RS485_4WIRE_MODE)
- return -EFAULT;
- mask = ModeMask[p];
- shiftbit = p * 2;
- val = inb(info->opmode_ioaddr);
- val &= mask;
- val |= (opmode << shiftbit);
- outb(val, info->opmode_ioaddr);
- } else {
- shiftbit = p * 2;
- opmode = inb(info->opmode_ioaddr) >> shiftbit;
- opmode &= OP_MODE_MASK;
- if (put_user(opmode, (int __user *)argp))
- return -EFAULT;
- }
- return 0;
- }
-
- if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
- test_bit(TTY_IO_ERROR, &tty->flags))
- return -EIO;
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- mxser_send_break(info, HZ / 4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
- return 0;
- case TIOCGSOFTCAR:
- return put_user(!!C_CLOCAL(tty), (unsigned long __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return 0;
- case TIOCGSERIAL:
- return mxser_get_serial_info(info, argp);
- case TIOCSSERIAL:
- return mxser_set_serial_info(info, argp);
- case TIOCSERGETLSR: /* Get line status register */
- return mxser_get_lsr_info(info, argp);
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
- spin_lock_irqsave(&info->slock, flags);
- cnow = info->icount; /* note the counters on entry */
- spin_unlock_irqrestore(&info->slock, flags);
-
- return wait_event_interruptible(info->delta_msr_wait,
- mxser_cflags_changed(info, arg, &cnow));
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- case TIOCGICOUNT:
- spin_lock_irqsave(&info->slock, flags);
- cnow = info->icount;
- spin_unlock_irqrestore(&info->slock, flags);
- p_cuser = argp;
- if (put_user(cnow.frame, &p_cuser->frame))
- return -EFAULT;
- if (put_user(cnow.brk, &p_cuser->brk))
- return -EFAULT;
- if (put_user(cnow.overrun, &p_cuser->overrun))
- return -EFAULT;
- if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
- return -EFAULT;
- if (put_user(cnow.parity, &p_cuser->parity))
- return -EFAULT;
- if (put_user(cnow.rx, &p_cuser->rx))
- return -EFAULT;
- if (put_user(cnow.tx, &p_cuser->tx))
- return -EFAULT;
- put_user(cnow.cts, &p_cuser->cts);
- put_user(cnow.dsr, &p_cuser->dsr);
- put_user(cnow.rng, &p_cuser->rng);
- put_user(cnow.dcd, &p_cuser->dcd);
- return 0;
- case MOXA_HighSpeedOn:
- return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
- case MOXA_SDS_RSTICOUNTER:
- info->mon_data.rxcnt = 0;
- info->mon_data.txcnt = 0;
- return 0;
-
- case MOXA_ASPP_OQUEUE:{
- int len, lsr;
-
- len = mxser_chars_in_buffer(tty);
-
- lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
-
- len += (lsr ? 0 : 1);
-
- return put_user(len, (int __user *)argp);
- }
- case MOXA_ASPP_MON: {
- int mcr, status;
-
- status = mxser_get_msr(info->ioaddr, 1, tty->index);
- mxser_check_modem_status(info, status);
-
- mcr = inb(info->ioaddr + UART_MCR);
- if (mcr & MOXA_MUST_MCR_XON_FLAG)
- info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
- else
- info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
-
- if (mcr & MOXA_MUST_MCR_TX_XON)
- info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
- else
- info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
-
- if (info->tty->hw_stopped)
- info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
- else
- info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
- if (copy_to_user(argp, &info->mon_data,
- sizeof(struct mxser_mon)))
- return -EFAULT;
-
- return 0;
- }
- case MOXA_ASPP_LSTATUS: {
- if (put_user(info->err_shadow, (unsigned char __user *)argp))
- return -EFAULT;
-
- info->err_shadow = 0;
- return 0;
- }
- case MOXA_SET_BAUD_METHOD: {
- int method;
+ struct mxser_struct *info = tty->driver_data;
+ /* unsigned long flags; */
- if (get_user(method, (int __user *)argp))
- return -EFAULT;
- mxser_set_baud_method[tty->index] = method;
- return put_user(method, (int __user *)argp);
- }
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
+ info->ldisc_stop_rx = 0;
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ /* MX_LOCK(&info->slock); */
-static void mxser_stoprx(struct tty_struct *tty)
-{
- struct mxser_port *info = tty->driver_data;
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag) {
+ info->IER |= MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->base + UART_IER);
+ } else {
+ /* above add by Victor Yu. 09-02-2002 */
- info->ldisc_stop_rx = 1;
- if (I_IXOFF(tty)) {
- if (info->board->chip_flag) {
- info->IER &= ~MOXA_MUST_RECV_ISR;
- outb(info->IER, info->ioaddr + UART_IER);
- } else {
- info->x_char = STOP_CHAR(tty);
- outb(0, info->ioaddr + UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
+ info->x_char = START_CHAR(tty);
+ /* mask by Victor Yu. 09-02-2002 */
+ /* outb(info->IER, 0); */
+ /* add by Victor Yu. 09-02-2002 */
+ outb(0, info->base + UART_IER);
+ /* force Tx interrupt */
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ } /* add by Victor Yu. 09-02-2002 */
+ /* MX_UNLOCK(&info->slock); */
}
}
if (info->tty->termios->c_cflag & CRTSCTS) {
- info->MCR &= ~UART_MCR_RTS;
- outb(info->MCR, info->ioaddr + UART_MCR);
+ /* MX_LOCK(&info->slock); */
+ info->MCR |= UART_MCR_RTS;
+ outb(info->MCR, info->base + UART_MCR);
+ /* MX_UNLOCK(&info->slock); */
}
}
@@ -1839,34 +1703,51 @@ static void mxser_stoprx(struct tty_struct *tty)
*/
static void mxser_throttle(struct tty_struct *tty)
{
+ /* struct mxser_struct *info = tty->driver_data; */
+ /* unsigned long flags; */
+
+ /* MX_LOCK(&info->slock); */
mxser_stoprx(tty);
+ /* MX_UNLOCK(&info->slock); */
}
static void mxser_unthrottle(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ /* struct mxser_struct *info = tty->driver_data; */
+ /* unsigned long flags; */
- /* startrx */
- info->ldisc_stop_rx = 0;
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else {
- if (info->board->chip_flag) {
- info->IER |= MOXA_MUST_RECV_ISR;
- outb(info->IER, info->ioaddr + UART_IER);
- } else {
- info->x_char = START_CHAR(tty);
- outb(0, info->ioaddr + UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
- }
- }
+ /* MX_LOCK(&info->slock); */
+ mxser_startrx(tty);
+ /* MX_UNLOCK(&info->slock); */
+}
+
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct mxser_struct *info = tty->driver_data;
+ unsigned long flags;
+
+ mxser_change_speed(info, old_termios);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
}
- if (info->tty->termios->c_cflag & CRTSCTS) {
- info->MCR |= UART_MCR_RTS;
- outb(info->MCR, info->ioaddr + UART_MCR);
+/* Handle sw stopped */
+ if ((old_termios->c_iflag & IXON) &&
+ !(tty->termios->c_iflag & IXON)) {
+ tty->stopped = 0;
+
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag) {
+ spin_lock_irqsave(&info->slock, flags);
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ /* above add by Victor Yu. 09-02-2002 */
+
+ mxser_start(tty);
}
}
@@ -1878,67 +1759,36 @@ static void mxser_unthrottle(struct tty_struct *tty)
*/
static void mxser_stop(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
+ outb(info->IER, info->base + UART_IER);
}
spin_unlock_irqrestore(&info->slock, flags);
}
static void mxser_start(struct tty_struct *tty)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
- if (info->xmit_cnt && info->xmit_buf) {
- outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
+ outb(info->IER, info->base + UART_IER);
}
spin_unlock_irqrestore(&info->slock, flags);
}
-static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct mxser_port *info = tty->driver_data;
- unsigned long flags;
-
- spin_lock_irqsave(&info->slock, flags);
- mxser_change_speed(info, old_termios);
- spin_unlock_irqrestore(&info->slock, flags);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- mxser_start(tty);
- }
-
- /* Handle sw stopped */
- if ((old_termios->c_iflag & IXON) &&
- !(tty->termios->c_iflag & IXON)) {
- tty->stopped = 0;
-
- if (info->board->chip_flag) {
- spin_lock_irqsave(&info->slock, flags);
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- spin_unlock_irqrestore(&info->slock, flags);
- }
-
- mxser_start(tty);
- }
-}
-
/*
* mxser_wait_until_sent() --- wait until the transmitter is empty
*/
static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct mxser_port *info = tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
int lsr;
@@ -1979,7 +1829,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
- while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
+ while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
#endif
@@ -1989,440 +1839,1141 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- set_current_state(TASK_RUNNING);
+ set_current_state(TASK_RUNNING);
+
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+void mxser_hangup(struct tty_struct *tty)
+{
+ struct mxser_struct *info = tty->driver_data;
+
+ mxser_flush_buffer(tty);
+ mxser_shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ info->tty = NULL;
+ wake_up_interruptible(&info->open_wait);
+}
+
+
+/* added by James 03-12-2004. */
+/*
+ * mxser_rs_break() --- routine which turns the break handling on or off
+ */
+static void mxser_rs_break(struct tty_struct *tty, int break_state)
+{
+ struct mxser_struct *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (break_state == -1)
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+ info->base + UART_LCR);
+ else
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+ info->base + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+/* (above) added by James. */
+
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
+{
+ int status, iir, i;
+ struct mxser_struct *info;
+ struct mxser_struct *port;
+ int max, irqbits, bits, msr;
+ int pass_counter = 0;
+ int handled = IRQ_NONE;
+
+ port = NULL;
+ /* spin_lock(&gm_lock); */
+
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
+ port = dev_id;
+ break;
+ }
+ }
+
+ if (i == MXSER_BOARDS)
+ goto irq_stop;
+ if (port == 0)
+ goto irq_stop;
+ max = mxser_numports[mxsercfg[i].board_type - 1];
+ while (1) {
+ irqbits = inb(port->vector) & port->vectormask;
+ if (irqbits == port->vectormask)
+ break;
+
+ handled = IRQ_HANDLED;
+ for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+ if (irqbits == port->vectormask)
+ break;
+ if (bits & irqbits)
+ continue;
+ info = port + i;
+
+ /* following add by Victor Yu. 09-13-2002 */
+ iir = inb(info->base + UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ continue;
+ iir &= MOXA_MUST_IIR_MASK;
+ if (!info->tty) {
+ status = inb(info->base + UART_LSR);
+ outb(0x27, info->base + UART_FCR);
+ inb(info->base + UART_MSR);
+ continue;
+ }
+
+ /* mask by Victor Yu. 09-13-2002
+ if ( !info->tty ||
+ (inb(info->base + UART_IIR) & UART_IIR_NO_INT) )
+ continue;
+ */
+ /* mask by Victor Yu. 09-02-2002
+ status = inb(info->base + UART_LSR) & info->read_status_mask;
+ */
+
+ /* following add by Victor Yu. 09-02-2002 */
+ status = inb(info->base + UART_LSR);
+
+ if (status & UART_LSR_PE)
+ info->err_shadow |= NPPI_NOTIFY_PARITY;
+ if (status & UART_LSR_FE)
+ info->err_shadow |= NPPI_NOTIFY_FRAMING;
+ if (status & UART_LSR_OE)
+ info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN;
+ if (status & UART_LSR_BI)
+ info->err_shadow |= NPPI_NOTIFY_BREAK;
+
+ if (info->IsMoxaMustChipFlag) {
+ /*
+ if ( (status & 0x02) && !(status & 0x01) ) {
+ outb(info->base+UART_FCR, 0x23);
+ continue;
+ }
+ */
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
+ mxser_receive_chars(info, &status);
+
+ } else {
+ /* above add by Victor Yu. 09-02-2002 */
+
+ status &= info->read_status_mask;
+ if (status & UART_LSR_DR)
+ mxser_receive_chars(info, &status);
+ }
+ msr = inb(info->base + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA) {
+ mxser_check_modem_status(info, msr);
+ }
+ /* following add by Victor Yu. 09-13-2002 */
+ if (info->IsMoxaMustChipFlag) {
+ if ((iir == 0x02) && (status & UART_LSR_THRE)) {
+ mxser_transmit_chars(info);
+ }
+ } else {
+ /* above add by Victor Yu. 09-13-2002 */
+
+ if (status & UART_LSR_THRE) {
+/* 8-2-99 by William
+ if ( info->x_char || (info->xmit_cnt > 0) )
+*/
+ mxser_transmit_chars(info);
+ }
+ }
+ }
+ if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
+ break; /* Prevent infinite loops */
+ }
+ }
+
+ irq_stop:
+ /* spin_unlock(&gm_lock); */
+ return handled;
+}
+
+static void mxser_receive_chars(struct mxser_struct *info, int *status)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, gdl;
+ int ignored = 0;
+ int cnt = 0;
+ int recv_room;
+ int max = 256;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ recv_room = tty->receive_room;
+ if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
+ /* mxser_throttle(tty); */
+ mxser_stoprx(tty);
+ /* return; */
+ }
+
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
+
+ if (*status & UART_LSR_SPECIAL) {
+ goto intr_old;
+ }
+ /* following add by Victor Yu. 02-11-2004 */
+ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID &&
+ (*status & MOXA_MUST_LSR_RERR))
+ goto intr_old;
+ /* above add by Victor Yu. 02-14-2004 */
+ if (*status & MOXA_MUST_LSR_RERR)
+ goto intr_old;
+
+ gdl = inb(info->base + MOXA_MUST_GDL_REGISTER);
+
+ /* add by Victor Yu. 02-11-2004 */
+ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)
+ gdl &= MOXA_MUST_GDL_MASK;
+ if (gdl >= recv_room) {
+ if (!info->ldisc_stop_rx) {
+ /* mxser_throttle(tty); */
+ mxser_stoprx(tty);
+ }
+ /* return; */
+ }
+ while (gdl--) {
+ ch = inb(info->base + UART_RX);
+ tty_insert_flip_char(tty, ch, 0);
+ cnt++;
+ /*
+ if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
+ mxser_stoprx(tty);
+ info->stop_rx = 1;
+ break;
+ } */
+ }
+ goto end_intr;
+ }
+ intr_old:
+ /* above add by Victor Yu. 09-02-2002 */
+
+ do {
+ if (max-- < 0)
+ break;
+ /*
+ if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
+ mxser_stoprx(tty);
+ info->stop_rx=1;
+ break;
+ }
+ */
+
+ ch = inb(info->base + UART_RX);
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ )
+ outb(0x23, info->base + UART_FCR);
+ *status &= info->read_status_mask;
+ /* above add by Victor Yu. 09-02-2002 */
+ if (*status & info->ignore_status_mask) {
+ if (++ignored > 100)
+ break;
+ } else {
+ char flag = 0;
+ if (*status & UART_LSR_SPECIAL) {
+ if (*status & UART_LSR_BI) {
+ flag = TTY_BREAK;
+/* added by casper 1/11/2000 */
+ info->icount.brk++;
+/* */
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (*status & UART_LSR_PE) {
+ flag = TTY_PARITY;
+/* added by casper 1/11/2000 */
+ info->icount.parity++;
+/* */
+ } else if (*status & UART_LSR_FE) {
+ flag = TTY_FRAME;
+/* added by casper 1/11/2000 */
+ info->icount.frame++;
+/* */
+ } else if (*status & UART_LSR_OE) {
+ flag = TTY_OVERRUN;
+/* added by casper 1/11/2000 */
+ info->icount.overrun++;
+/* */
+ }
+ }
+ tty_insert_flip_char(tty, ch, flag);
+ cnt++;
+ if (cnt >= recv_room) {
+ if (!info->ldisc_stop_rx) {
+ /* mxser_throttle(tty); */
+ mxser_stoprx(tty);
+ }
+ break;
+ }
+
+ }
+
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag)
+ break;
+ /* above add by Victor Yu. 09-02-2002 */
+
+ /* mask by Victor Yu. 09-02-2002
+ *status = inb(info->base + UART_LSR) & info->read_status_mask;
+ */
+ /* following add by Victor Yu. 09-02-2002 */
+ *status = inb(info->base + UART_LSR);
+ /* above add by Victor Yu. 09-02-2002 */
+ } while (*status & UART_LSR_DR);
+
+end_intr: /* add by Victor Yu. 09-02-2002 */
+ mxvar_log.rxcnt[info->port] += cnt;
+ info->mon_data.rxcnt += cnt;
+ info->mon_data.up_rxcnt += cnt;
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_flip_buffer_push(tty);
+}
+
+static void mxser_transmit_chars(struct mxser_struct *info)
+{
+ int count, cnt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (info->x_char) {
+ outb(info->x_char, info->base + UART_TX);
+ info->x_char = 0;
+ mxvar_log.txcnt[info->port]++;
+ info->mon_data.txcnt++;
+ info->mon_data.up_txcnt++;
+
+/* added by casper 1/11/2000 */
+ info->icount.tx++;
+/* */
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+
+ if (info->xmit_buf == 0) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+
+ if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+ (info->tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag))) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+
+ cnt = info->xmit_cnt;
+ count = info->xmit_fifo_size;
+ do {
+ outb(info->xmit_buf[info->xmit_tail++],
+ info->base + UART_TX);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ if (--info->xmit_cnt <= 0)
+ break;
+ } while (--count > 0);
+ mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
+
+/* added by James 03-12-2004. */
+ info->mon_data.txcnt += (cnt - info->xmit_cnt);
+ info->mon_data.up_txcnt += (cnt - info->xmit_cnt);
+/* (above) added by James. */
+
+/* added by casper 1/11/2000 */
+ info->icount.tx += (cnt - info->xmit_cnt);
+/* */
+
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ schedule_work(&info->tqueue);
+ }
+ if (info->xmit_cnt <= 0) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_check_modem_status(struct mxser_struct *info, int status)
+{
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ info->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ info->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ info->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ info->icount.cts++;
+ info->mon_data.modem_status = status;
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+ if (status & UART_MSR_DCD)
+ wake_up_interruptible(&info->open_wait);
+ schedule_work(&info->tqueue);
+ }
+
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ info->tty->hw_stopped = 0;
+
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ schedule_work(&info->tqueue); }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ info->tty->hw_stopped = 1;
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ }
+ }
+ }
+}
+
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_struct *info)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+ unsigned long flags;
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * mxser_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ spin_unlock_irqrestore(&info->slock, flags);
+ info->blocked_open++;
+ while (1) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->base + UART_MCR) |
+ UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(info->flags & ASYNC_CLOSING) &&
+ (do_clocal ||
+ (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int mxser_startup(struct mxser_struct *info)
+{
+ unsigned long page;
+ unsigned long flags;
+
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+
+ if (!info->base || !info->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in mxser_change_speed())
+ */
+ if (info->IsMoxaMustChipFlag)
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+ else
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
+
+ /*
+ * At this point there's no way the LSR could still be 0xFF;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (inb(info->base + UART_LSR) == 0xff) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ return 0;
+ } else
+ return -ENODEV;
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) inb(info->base + UART_LSR);
+ (void) inb(info->base + UART_RX);
+ (void) inb(info->base + UART_IIR);
+ (void) inb(info->base + UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+ outb(info->MCR, info->base + UART_MCR);
+
+ /*
+ * Finally, enable interrupts
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+ /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
+
+ /* following add by Victor Yu. 08-30-2002 */
+ if (info->IsMoxaMustChipFlag)
+ info->IER |= MOXA_MUST_IER_EGDAI;
+ /* above add by Victor Yu. 08-30-2002 */
+ outb(info->IER, info->base + UART_IER); /* enable interrupts */
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ (void) inb(info->base + UART_LSR);
+ (void) inb(info->base + UART_RX);
+ (void) inb(info->base + UART_IIR);
+ (void) inb(info->base + UART_MSR);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * and set the speed of the serial port
+ */
+ spin_unlock_irqrestore(&info->slock, flags);
+ mxser_change_speed(info, NULL);
+
+ info->flags |= ASYNC_INITIALIZED;
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_struct *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = NULL;
+ }
+
+ info->IER = 0;
+ outb(0x00, info->base + UART_IER);
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ outb(info->MCR, info->base + UART_MCR);
+
+ /* clear Rx/Tx FIFO's */
+ /* following add by Victor Yu. 08-30-2002 */
+ if (info->IsMoxaMustChipFlag)
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+ else
+ /* above add by Victor Yu. 08-30-2002 */
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
+
+ /* read data port to reset things */
+ (void) inb(info->base + UART_RX);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ /* following add by Victor Yu. 09-23-2002 */
+ if (info->IsMoxaMustChipFlag)
+ SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
+ /* above add by Victor Yu. 09-23-2002 */
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_struct *info, struct ktermios *old_termios)
+{
+ unsigned cflag, cval, fcr;
+ int ret = 0;
+ unsigned char status;
+ long baud;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+ cflag = info->tty->termios->c_cflag;
+ if (!(info->base))
+ return ret;
+
+#ifndef B921600
+#define B921600 (B460800 +1)
+#endif
+ if (mxser_set_baud_method[info->port] == 0) {
+ baud = tty_get_baud_rate(info->tty);
+ mxser_set_baud(info, baud);
+ }
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cval = 0x00;
+ break;
+ case CS6:
+ cval = 0x01;
+ break;
+ case CS7:
+ cval = 0x02;
+ break;
+ case CS8:
+ cval = 0x03;
+ break;
+ default:
+ cval = 0x00;
+ break; /* too keep GCC shut... */
+ }
+ if (cflag & CSTOPB)
+ cval |= 0x04;
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+ if (cflag & CMSPAR)
+ cval |= UART_LCR_SPAR;
+
+ if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+ if (info->IsMoxaMustChipFlag) {
+ fcr = UART_FCR_ENABLE_FIFO;
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else
+ fcr = 0;
+ } else {
+ fcr = UART_FCR_ENABLE_FIFO;
+ /* following add by Victor Yu. 08-30-2002 */
+ if (info->IsMoxaMustChipFlag) {
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else {
+ /* above add by Victor Yu. 08-30-2002 */
+ switch (info->rx_trigger) {
+ case 1:
+ fcr |= UART_FCR_TRIGGER_1;
+ break;
+ case 4:
+ fcr |= UART_FCR_TRIGGER_4;
+ break;
+ case 8:
+ fcr |= UART_FCR_TRIGGER_8;
+ break;
+ default:
+ fcr |= UART_FCR_TRIGGER_14;
+ break;
+ }
+ }
+ }
+
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ info->MCR &= ~UART_MCR_AFE;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
+ info->MCR |= UART_MCR_AFE;
+ } else {
+ status = inb(info->base + UART_MSR);
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ info->tty->hw_stopped = 0;
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ schedule_work(&info->tqueue); }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ info->tty->hw_stopped = 1;
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->base + UART_IER);
+ }
+ }
+ }
+ }
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ }
+ outb(info->MCR, info->base + UART_MCR);
+ if (cflag & CLOCAL) {
+ info->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ outb(info->IER, info->base + UART_IER);
+
+ /*
+ * Set up parity check flag
+ */
+ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
+
+ info->ignore_status_mask = 0;
+
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ info->read_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty)) {
+ info->ignore_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ info->read_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ }
+ }
+ /* following add by Victor Yu. 09-02-2002 */
+ if (info->IsMoxaMustChipFlag) {
+ spin_lock_irqsave(&info->slock, flags);
+ SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
+ SET_MOXA_MUST_XOFF1_VALUE(info->base, STOP_CHAR(info->tty));
+ if (I_IXON(info->tty)) {
+ ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
+ } else {
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
+ }
+ if (I_IXOFF(info->tty)) {
+ ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
+ } else {
+ DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
+ }
+ /*
+ if ( I_IXANY(info->tty) ) {
+ info->MCR |= MOXA_MUST_MCR_XON_ANY;
+ ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
+ } else {
+ info->MCR &= ~MOXA_MUST_MCR_XON_ANY;
+ DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
+ }
+ */
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ /* above add by Victor Yu. 09-02-2002 */
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-/*
- * This routine is called by tty_hangup() when a hangup is signaled.
- */
-static void mxser_hangup(struct tty_struct *tty)
-{
- struct mxser_port *info = tty->driver_data;
+ outb(fcr, info->base + UART_FCR); /* set fcr */
+ outb(cval, info->base + UART_LCR);
- mxser_flush_buffer(tty);
- mxser_shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->tty = NULL;
- wake_up_interruptible(&info->open_wait);
+ return ret;
}
-/*
- * mxser_rs_break() --- routine which turns the break handling on or off
- */
-static void mxser_rs_break(struct tty_struct *tty, int break_state)
+
+static int mxser_set_baud(struct mxser_struct *info, long newspd)
{
- struct mxser_port *info = tty->driver_data;
+ int quot = 0;
+ unsigned char cval;
+ int ret = 0;
unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
- if (break_state == -1)
- outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
- info->ioaddr + UART_LCR);
- else
- outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
- info->ioaddr + UART_LCR);
- spin_unlock_irqrestore(&info->slock, flags);
-}
-
-static void mxser_receive_chars(struct mxser_port *port, int *status)
-{
- struct tty_struct *tty = port->tty;
- unsigned char ch, gdl;
- int ignored = 0;
- int cnt = 0;
- int recv_room;
- int max = 256;
+ if (!info->tty || !info->tty->termios)
+ return ret;
- recv_room = tty->receive_room;
- if ((recv_room == 0) && (!port->ldisc_stop_rx))
- mxser_stoprx(tty);
+ if (!(info->base))
+ return ret;
- if (port->board->chip_flag != MOXA_OTHER_UART) {
+ if (newspd > info->MaxCanSetBaudRate)
+ return 0;
- if (*status & UART_LSR_SPECIAL)
- goto intr_old;
- if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
- (*status & MOXA_MUST_LSR_RERR))
- goto intr_old;
- if (*status & MOXA_MUST_LSR_RERR)
- goto intr_old;
+ info->realbaud = newspd;
+ if (newspd == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (newspd) {
+ quot = info->baud_base / newspd;
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
- gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
+ info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
+ info->timeout += HZ / 50; /* Add .02 seconds of slop */
- if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
- gdl &= MOXA_MUST_GDL_MASK;
- if (gdl >= recv_room) {
- if (!port->ldisc_stop_rx)
- mxser_stoprx(tty);
- }
- while (gdl--) {
- ch = inb(port->ioaddr + UART_RX);
- tty_insert_flip_char(tty, ch, 0);
- cnt++;
- }
- goto end_intr;
+ if (quot) {
+ spin_lock_irqsave(&info->slock, flags);
+ info->MCR |= UART_MCR_DTR;
+ outb(info->MCR, info->base + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ } else {
+ spin_lock_irqsave(&info->slock, flags);
+ info->MCR &= ~UART_MCR_DTR;
+ outb(info->MCR, info->base + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ret;
}
-intr_old:
-
- do {
- if (max-- < 0)
- break;
- ch = inb(port->ioaddr + UART_RX);
- if (port->board->chip_flag && (*status & UART_LSR_OE))
- outb(0x23, port->ioaddr + UART_FCR);
- *status &= port->read_status_mask;
- if (*status & port->ignore_status_mask) {
- if (++ignored > 100)
- break;
- } else {
- char flag = 0;
- if (*status & UART_LSR_SPECIAL) {
- if (*status & UART_LSR_BI) {
- flag = TTY_BREAK;
- port->icount.brk++;
+ cval = inb(info->base + UART_LCR);
- if (port->flags & ASYNC_SAK)
- do_SAK(tty);
- } else if (*status & UART_LSR_PE) {
- flag = TTY_PARITY;
- port->icount.parity++;
- } else if (*status & UART_LSR_FE) {
- flag = TTY_FRAME;
- port->icount.frame++;
- } else if (*status & UART_LSR_OE) {
- flag = TTY_OVERRUN;
- port->icount.overrun++;
- } else
- flag = TTY_BREAK;
- }
- tty_insert_flip_char(tty, ch, flag);
- cnt++;
- if (cnt >= recv_room) {
- if (!port->ldisc_stop_rx)
- mxser_stoprx(tty);
- break;
- }
+ outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */
- }
+ outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */
+ outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */
+ outb(cval, info->base + UART_LCR); /* reset DLAB */
- if (port->board->chip_flag)
- break;
- *status = inb(port->ioaddr + UART_LSR);
- } while (*status & UART_LSR_DR);
+ return ret;
+}
-end_intr:
- mxvar_log.rxcnt[port->tty->index] += cnt;
- port->mon_data.rxcnt += cnt;
- port->mon_data.up_rxcnt += cnt;
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
- /*
- * We are called from an interrupt context with &port->slock
- * being held. Drop it temporarily in order to prevent
- * recursive locking.
- */
- spin_unlock(&port->slock);
- tty_flip_buffer_push(tty);
- spin_lock(&port->slock);
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->port;
+ tmp.port = info->base;
+ tmp.irq = info->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0;
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
}
-static void mxser_transmit_chars(struct mxser_port *port)
+static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
{
- int count, cnt;
+ struct serial_struct new_serial;
+ unsigned int flags;
+ int retval = 0;
- if (port->x_char) {
- outb(port->x_char, port->ioaddr + UART_TX);
- port->x_char = 0;
- mxvar_log.txcnt[port->tty->index]++;
- port->mon_data.txcnt++;
- port->mon_data.up_txcnt++;
- port->icount.tx++;
- return;
- }
+ if (!new_info || !info->base)
+ return -EFAULT;
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
- if (port->xmit_buf == NULL)
- return;
+ if ((new_serial.irq != info->irq) ||
+ (new_serial.port != info->base) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return -EPERM;
- if ((port->xmit_cnt <= 0) || port->tty->stopped ||
- (port->tty->hw_stopped &&
- (port->type != PORT_16550A) &&
- (!port->board->chip_flag))) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr + UART_IER);
- return;
- }
+ flags = info->flags & ASYNC_SPD_MASK;
- cnt = port->xmit_cnt;
- count = port->xmit_fifo_size;
- do {
- outb(port->xmit_buf[port->xmit_tail++],
- port->ioaddr + UART_TX);
- port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
- if (--port->xmit_cnt <= 0)
- break;
- } while (--count > 0);
- mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ } else {
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
+ info->tty->low_latency =
+ (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
+ }
- port->mon_data.txcnt += (cnt - port->xmit_cnt);
- port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
- port->icount.tx += (cnt - port->xmit_cnt);
+ /* added by casper, 3/17/2000, for mouse */
+ info->type = new_serial.type;
- if (port->xmit_cnt < WAKEUP_CHARS)
- tty_wakeup(port->tty);
+ process_txrx_fifo(info);
- if (port->xmit_cnt <= 0) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr + UART_IER);
+ if (info->flags & ASYNC_INITIALIZED) {
+ if (flags != (info->flags & ASYNC_SPD_MASK)) {
+ mxser_change_speed(info, NULL);
+ }
+ } else {
+ retval = mxser_startup(info);
}
+ return retval;
}
/*
- * This is the serial driver's generic interrupt routine
+ * mxser_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
*/
-static irqreturn_t mxser_interrupt(int irq, void *dev_id)
+static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value)
{
- int status, iir, i;
- struct mxser_board *brd = NULL;
- struct mxser_port *port;
- int max, irqbits, bits, msr;
- unsigned int int_cnt, pass_counter = 0;
- int handled = IRQ_NONE;
-
- for (i = 0; i < MXSER_BOARDS; i++)
- if (dev_id == &mxser_boards[i]) {
- brd = dev_id;
- break;
- }
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
- if (i == MXSER_BOARDS)
- goto irq_stop;
- if (brd == NULL)
- goto irq_stop;
- max = brd->info->nports;
- while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
- irqbits = inb(brd->vector) & brd->vector_mask;
- if (irqbits == brd->vector_mask)
- break;
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->base + UART_LSR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+ return put_user(result, value);
+}
- handled = IRQ_HANDLED;
- for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
- if (irqbits == brd->vector_mask)
- break;
- if (bits & irqbits)
- continue;
- port = &brd->ports[i];
-
- int_cnt = 0;
- spin_lock(&port->slock);
- do {
- iir = inb(port->ioaddr + UART_IIR);
- if (iir & UART_IIR_NO_INT)
- break;
- iir &= MOXA_MUST_IIR_MASK;
- if (!port->tty ||
- (port->flags & ASYNC_CLOSING) ||
- !(port->flags &
- ASYNC_INITIALIZED)) {
- status = inb(port->ioaddr + UART_LSR);
- outb(0x27, port->ioaddr + UART_FCR);
- inb(port->ioaddr + UART_MSR);
- break;
- }
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_struct *info, int duration)
+{
+ unsigned long flags;
- status = inb(port->ioaddr + UART_LSR);
-
- if (status & UART_LSR_PE)
- port->err_shadow |= NPPI_NOTIFY_PARITY;
- if (status & UART_LSR_FE)
- port->err_shadow |= NPPI_NOTIFY_FRAMING;
- if (status & UART_LSR_OE)
- port->err_shadow |=
- NPPI_NOTIFY_HW_OVERRUN;
- if (status & UART_LSR_BI)
- port->err_shadow |= NPPI_NOTIFY_BREAK;
-
- if (port->board->chip_flag) {
- if (iir == MOXA_MUST_IIR_GDA ||
- iir == MOXA_MUST_IIR_RDA ||
- iir == MOXA_MUST_IIR_RTO ||
- iir == MOXA_MUST_IIR_LSR)
- mxser_receive_chars(port,
- &status);
+ if (!info->base)
+ return;
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+ info->base + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ schedule_timeout(duration);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+ info->base + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
- } else {
- status &= port->read_status_mask;
- if (status & UART_LSR_DR)
- mxser_receive_chars(port,
- &status);
- }
- msr = inb(port->ioaddr + UART_MSR);
- if (msr & UART_MSR_ANY_DELTA)
- mxser_check_modem_status(port, msr);
-
- if (port->board->chip_flag) {
- if (iir == 0x02 && (status &
- UART_LSR_THRE))
- mxser_transmit_chars(port);
- } else {
- if (status & UART_LSR_THRE)
- mxser_transmit_chars(port);
- }
- } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
- spin_unlock(&port->slock);
- }
- }
+static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct mxser_struct *info = tty->driver_data;
+ unsigned char control, status;
+ unsigned long flags;
-irq_stop:
- return handled;
-}
-static const struct tty_operations mxser_ops = {
- .open = mxser_open,
- .close = mxser_close,
- .write = mxser_write,
- .put_char = mxser_put_char,
- .flush_chars = mxser_flush_chars,
- .write_room = mxser_write_room,
- .chars_in_buffer = mxser_chars_in_buffer,
- .flush_buffer = mxser_flush_buffer,
- .ioctl = mxser_ioctl,
- .throttle = mxser_throttle,
- .unthrottle = mxser_unthrottle,
- .set_termios = mxser_set_termios,
- .stop = mxser_stop,
- .start = mxser_start,
- .hangup = mxser_hangup,
- .break_ctl = mxser_rs_break,
- .wait_until_sent = mxser_wait_until_sent,
- .tiocmget = mxser_tiocmget,
- .tiocmset = mxser_tiocmset,
-};
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
-/*
- * The MOXA Smartio/Industio serial driver boot-time initialization code!
- */
+ control = info->MCR;
-static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
- unsigned int irq)
-{
- if (irq)
- free_irq(brd->irq, brd);
- if (pdev != NULL) { /* PCI */
-#ifdef CONFIG_PCI
- pci_release_region(pdev, 2);
- pci_release_region(pdev, 3);
-#endif
- } else {
- release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- release_region(brd->vector, 1);
- }
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->base + UART_MSR);
+ if (status & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, status);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
}
-static int __devinit mxser_initbrd(struct mxser_board *brd,
- struct pci_dev *pdev)
+static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
{
- struct mxser_port *info;
- unsigned int i;
- int retval;
+ struct mxser_struct *info = tty->driver_data;
+ unsigned long flags;
- printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
- for (i = 0; i < brd->info->nports; i++) {
- info = &brd->ports[i];
- info->board = brd;
- info->stop_rx = 0;
- info->ldisc_stop_rx = 0;
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
- /* Enhance mode enabled here */
- if (brd->chip_flag != MOXA_OTHER_UART)
- ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+ spin_lock_irqsave(&info->slock, flags);
- info->flags = ASYNC_SHARE_IRQ;
- info->type = brd->uart_type;
+ if (set & TIOCM_RTS)
+ info->MCR |= UART_MCR_RTS;
+ if (set & TIOCM_DTR)
+ info->MCR |= UART_MCR_DTR;
- process_txrx_fifo(info);
+ if (clear & TIOCM_RTS)
+ info->MCR &= ~UART_MCR_RTS;
+ if (clear & TIOCM_DTR)
+ info->MCR &= ~UART_MCR_DTR;
- info->custom_divisor = info->baud_base * 16;
- info->close_delay = 5 * HZ / 10;
- info->closing_wait = 30 * HZ;
- info->normal_termios = mxvar_sdriver->init_termios;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- memset(&info->mon_data, 0, sizeof(struct mxser_mon));
- info->err_shadow = 0;
- spin_lock_init(&info->slock);
+ outb(info->MCR, info->base + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+}
- /* before set INT ISR, disable all int */
- outb(inb(info->ioaddr + UART_IER) & 0xf0,
- info->ioaddr + UART_IER);
- }
- retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
- brd);
- if (retval) {
- printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
- "conflict with another device.\n",
- brd->info->name, brd->irq);
- /* We hold resources, we need to release them. */
- mxser_release_res(brd, pdev, 0);
- }
- return retval;
-}
+static int mxser_read_register(int, unsigned short *);
+static int mxser_program_mode(int);
+static void mxser_normal_mode(int);
-static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
+static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
{
int id, i, bits;
unsigned short regs[16], irq;
unsigned char scratch, scratch2;
- brd->chip_flag = MOXA_OTHER_UART;
+ hwconf->IsMoxaMustChipFlag = MOXA_OTHER_UART;
id = mxser_read_register(cap, regs);
- switch (id) {
- case C168_ASIC_ID:
- brd->info = &mxser_cards[0];
- break;
- case C104_ASIC_ID:
- brd->info = &mxser_cards[1];
- break;
- case CI104J_ASIC_ID:
- brd->info = &mxser_cards[2];
- break;
- case C102_ASIC_ID:
- brd->info = &mxser_cards[5];
- break;
- case CI132_ASIC_ID:
- brd->info = &mxser_cards[6];
- break;
- case CI134_ASIC_ID:
- brd->info = &mxser_cards[7];
- break;
- default:
+ if (id == C168_ASIC_ID) {
+ hwconf->board_type = MXSER_BOARD_C168_ISA;
+ hwconf->ports = 8;
+ } else if (id == C104_ASIC_ID) {
+ hwconf->board_type = MXSER_BOARD_C104_ISA;
+ hwconf->ports = 4;
+ } else if (id == C102_ASIC_ID) {
+ hwconf->board_type = MXSER_BOARD_C102_ISA;
+ hwconf->ports = 2;
+ } else if (id == CI132_ASIC_ID) {
+ hwconf->board_type = MXSER_BOARD_CI132;
+ hwconf->ports = 2;
+ } else if (id == CI134_ASIC_ID) {
+ hwconf->board_type = MXSER_BOARD_CI134;
+ hwconf->ports = 4;
+ } else if (id == CI104J_ASIC_ID) {
+ hwconf->board_type = MXSER_BOARD_CI104J;
+ hwconf->ports = 4;
+ } else
return 0;
- }
irq = 0;
- /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
- Flag-hack checks if configuration should be read as 2-port here. */
- if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
+ if (hwconf->ports == 2) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
if (irq != (regs[9] & 0xFF00))
return MXSER_ERR_IRQ_CONFLIT;
- } else if (brd->info->nports == 4) {
+ } else if (hwconf->ports == 4) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if (irq != regs[9])
return MXSER_ERR_IRQ_CONFLIT;
- } else if (brd->info->nports == 8) {
+ } else if (hwconf->ports == 8) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
@@ -2432,23 +2983,23 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
if (!irq)
return MXSER_ERR_IRQ;
- brd->irq = ((int)(irq & 0xF000) >> 12);
+ hwconf->irq = ((int)(irq & 0xF000) >> 12);
for (i = 0; i < 8; i++)
- brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
+ hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
if ((regs[12] & 0x80) == 0)
return MXSER_ERR_VECTOR;
- brd->vector = (int)regs[11]; /* interrupt vector */
+ hwconf->vector = (int)regs[11]; /* interrupt vector */
if (id == 1)
- brd->vector_mask = 0x00FF;
+ hwconf->vector_mask = 0x00FF;
else
- brd->vector_mask = 0x000F;
+ hwconf->vector_mask = 0x000F;
for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
if (regs[12] & bits) {
- brd->ports[i].baud_base = 921600;
- brd->ports[i].max_baud = 921600;
+ hwconf->baud_base[i] = 921600;
+ hwconf->MaxCanSetBaudRate[i] = 921600; /* add by Victor Yu. 09-04-2002 */
} else {
- brd->ports[i].baud_base = 115200;
- brd->ports[i].max_baud = 115200;
+ hwconf->baud_base[i] = 115200;
+ hwconf->MaxCanSetBaudRate[i] = 115200; /* add by Victor Yu. 09-04-2002 */
}
}
scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -2459,279 +3010,123 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
scratch = inb(cap + UART_IIR);
if (scratch & 0xC0)
- brd->uart_type = PORT_16550A;
+ hwconf->uart_type = PORT_16550A;
else
- brd->uart_type = PORT_16450;
- if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
- "mxser(IO)"))
- return MXSER_ERR_IOADDR;
- if (!request_region(brd->vector, 1, "mxser(vector)")) {
- release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- return MXSER_ERR_VECTOR;
- }
- return brd->info->nports;
+ hwconf->uart_type = PORT_16450;
+ if (id == 1)
+ hwconf->ports = 8;
+ else
+ hwconf->ports = 4;
+ request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)");
+ request_region(hwconf->vector, 1, "mxser(vector)");
+ return hwconf->ports;
}
-static int __devinit mxser_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
+#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
+#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
+#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
+#define EN_CCMD 0x000 /* Chip's command register */
+#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
+#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
+#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
+#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
+#define EN0_DCFG 0x00E /* Data configuration reg WR */
+#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
+#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
+#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
+static int mxser_read_register(int port, unsigned short *regs)
{
-#ifdef CONFIG_PCI
- struct mxser_board *brd;
- unsigned int i, j;
- unsigned long ioaddress;
- int retval = -EINVAL;
-
- for (i = 0; i < MXSER_BOARDS; i++)
- if (mxser_boards[i].info == NULL)
- break;
-
- if (i >= MXSER_BOARDS) {
- printk(KERN_ERR "Too many Smartio/Industio family boards found "
- "(maximum %d), board not configured\n", MXSER_BOARDS);
- goto err;
- }
-
- brd = &mxser_boards[i];
- brd->idx = i * MXSER_PORTS_PER_BOARD;
- printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
- mxser_cards[ent->driver_data].name,
- pdev->bus->number, PCI_SLOT(pdev->devfn));
-
- retval = pci_enable_device(pdev);
- if (retval) {
- printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
- goto err;
- }
-
- /* io address */
- ioaddress = pci_resource_start(pdev, 2);
- retval = pci_request_region(pdev, 2, "mxser(IO)");
- if (retval)
- goto err;
-
- brd->info = &mxser_cards[ent->driver_data];
- for (i = 0; i < brd->info->nports; i++)
- brd->ports[i].ioaddr = ioaddress + 8 * i;
-
- /* vector */
- ioaddress = pci_resource_start(pdev, 3);
- retval = pci_request_region(pdev, 3, "mxser(vector)");
- if (retval)
- goto err_relio;
- brd->vector = ioaddress;
-
- /* irq */
- brd->irq = pdev->irq;
-
- brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
- brd->uart_type = PORT_16550A;
- brd->vector_mask = 0;
-
- for (i = 0; i < brd->info->nports; i++) {
- for (j = 0; j < UART_INFO_NUM; j++) {
- if (Gpci_uart_info[j].type == brd->chip_flag) {
- brd->ports[i].max_baud =
- Gpci_uart_info[j].max_baud;
+ int i, k, value, id;
+ unsigned int j;
- /* exception....CP-102 */
- if (brd->info->flags & MXSER_HIGHBAUD)
- brd->ports[i].max_baud = 921600;
- break;
+ id = mxser_program_mode(port);
+ if (id < 0)
+ return id;
+ for (i = 0; i < 14; i++) {
+ k = (i & 0x3F) | 0x180;
+ for (j = 0x100; j > 0; j >>= 1) {
+ outb(CHIP_CS, port);
+ if (k & j) {
+ outb(CHIP_CS | CHIP_DO, port);
+ outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
+ } else {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
}
}
- }
-
- if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
- for (i = 0; i < brd->info->nports; i++) {
- if (i < 4)
- brd->ports[i].opmode_ioaddr = ioaddress + 4;
- else
- brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
+ (void)inb(port);
+ value = 0;
+ for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port);
+ if (inb(port) & CHIP_DI)
+ value |= j;
}
- outb(0, ioaddress + 4); /* default set to RS232 mode */
- outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
- }
-
- for (i = 0; i < brd->info->nports; i++) {
- brd->vector_mask |= (1 << i);
- brd->ports[i].baud_base = 921600;
+ regs[i] = value;
+ outb(0, port);
}
-
- /* mxser_initbrd will hook ISR. */
- retval = mxser_initbrd(brd, pdev);
- if (retval)
- goto err_null;
-
- for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
-
- pci_set_drvdata(pdev, brd);
-
- return 0;
-err_relio:
- pci_release_region(pdev, 2);
-err_null:
- brd->info = NULL;
-err:
- return retval;
-#else
- return -ENODEV;
-#endif
-}
-
-static void __devexit mxser_remove(struct pci_dev *pdev)
-{
- struct mxser_board *brd = pci_get_drvdata(pdev);
- unsigned int i;
-
- for (i = 0; i < brd->info->nports; i++)
- tty_unregister_device(mxvar_sdriver, brd->idx + i);
-
- mxser_release_res(brd, pdev, 1);
- brd->info = NULL;
+ mxser_normal_mode(port);
+ return id;
}
-static struct pci_driver mxser_driver = {
- .name = "mxser",
- .id_table = mxser_pcibrds,
- .probe = mxser_probe,
- .remove = __devexit_p(mxser_remove)
-};
-
-static int __init mxser_module_init(void)
+static int mxser_program_mode(int port)
{
- struct mxser_board *brd;
- unsigned long cap;
- unsigned int i, m, isaloop;
- int retval, b;
-
- pr_debug("Loading module mxser ...\n");
-
- mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
- if (!mxvar_sdriver)
- return -ENOMEM;
-
- printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
- MXSER_VERSION);
-
- /* Initialize the tty_driver structure */
- mxvar_sdriver->owner = THIS_MODULE;
- mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
- mxvar_sdriver->name = "ttyMI";
- mxvar_sdriver->major = ttymajor;
- mxvar_sdriver->minor_start = 0;
- mxvar_sdriver->num = MXSER_PORTS + 1;
- mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
- mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
- mxvar_sdriver->init_termios = tty_std_termios;
- mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
- mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(mxvar_sdriver, &mxser_ops);
-
- retval = tty_register_driver(mxvar_sdriver);
- if (retval) {
- printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
- "tty driver !\n");
- goto err_put;
- }
-
- mxvar_diagflag = 0;
-
- m = 0;
- /* Start finding ISA boards here */
- for (isaloop = 0; isaloop < 2; isaloop++)
- for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
- if (!isaloop)
- cap = mxserBoardCAP[b]; /* predefined */
- else
- cap = ioaddr[b]; /* module param */
-
- if (!cap)
- continue;
-
- brd = &mxser_boards[m];
- retval = mxser_get_ISA_conf(cap, brd);
-
- if (retval != 0)
- printk(KERN_INFO "Found MOXA %s board "
- "(CAP=0x%x)\n",
- brd->info->name, ioaddr[b]);
-
- if (retval <= 0) {
- if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt "
- "number, board not "
- "configured\n");
- else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt "
- "number, board not "
- "configured\n");
- else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt "
- "vector, board not "
- "configured\n");
- else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address, "
- "board not configured\n");
-
- brd->info = NULL;
- continue;
- }
-
- /* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd, NULL) < 0) {
- brd->info = NULL;
- continue;
- }
-
- brd->idx = m * MXSER_PORTS_PER_BOARD;
- for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i,
- NULL);
+ int id, i, j, n;
+ /* unsigned long flags; */
- m++;
- }
+ spin_lock(&gm_lock);
+ outb(0, port);
+ outb(0, port);
+ outb(0, port);
+ (void)inb(port);
+ (void)inb(port);
+ outb(0, port);
+ (void)inb(port);
+ /* restore_flags(flags); */
+ spin_unlock(&gm_lock);
- retval = pci_register_driver(&mxser_driver);
- if (retval) {
- printk(KERN_ERR "Can't register pci driver\n");
- if (!m) {
- retval = -ENODEV;
- goto err_unr;
- } /* else: we have some ISA cards under control */
+ id = inb(port + 1) & 0x1F;
+ if ((id != C168_ASIC_ID) &&
+ (id != C104_ASIC_ID) &&
+ (id != C102_ASIC_ID) &&
+ (id != CI132_ASIC_ID) &&
+ (id != CI134_ASIC_ID) &&
+ (id != CI104J_ASIC_ID))
+ return -1;
+ for (i = 0, j = 0; i < 4; i++) {
+ n = inb(port + 2);
+ if (n == 'M') {
+ j = 1;
+ } else if ((j == 1) && (n == 1)) {
+ j = 2;
+ break;
+ } else
+ j = 0;
}
-
- pr_debug("Done.\n");
-
- return 0;
-err_unr:
- tty_unregister_driver(mxvar_sdriver);
-err_put:
- put_tty_driver(mxvar_sdriver);
- return retval;
+ if (j != 2)
+ id = -2;
+ return id;
}
-static void __exit mxser_module_exit(void)
+static void mxser_normal_mode(int port)
{
- unsigned int i, j;
-
- pr_debug("Unloading module mxser ...\n");
-
- pci_unregister_driver(&mxser_driver);
-
- for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
- if (mxser_boards[i].info != NULL)
- for (j = 0; j < mxser_boards[i].info->nports; j++)
- tty_unregister_device(mxvar_sdriver,
- mxser_boards[i].idx + j);
- tty_unregister_driver(mxvar_sdriver);
- put_tty_driver(mxvar_sdriver);
-
- for (i = 0; i < MXSER_BOARDS; i++)
- if (mxser_boards[i].info != NULL)
- mxser_release_res(&mxser_boards[i], NULL, 1);
+ int i, n;
- pr_debug("Done.\n");
+ outb(0xA5, port + 1);
+ outb(0x80, port + 3);
+ outb(12, port + 0); /* 9600 bps */
+ outb(0, port + 1);
+ outb(0x03, port + 3); /* 8 data bits */
+ outb(0x13, port + 4); /* loop back mode */
+ for (i = 0; i < 16; i++) {
+ n = inb(port + 5);
+ if ((n & 0x61) == 0x60)
+ break;
+ if ((n & 1) == 1)
+ (void)inb(port);
+ }
+ outb(0x00, port + 4);
}
module_init(mxser_module_init);
diff --git a/trunk/drivers/char/mxser.h b/trunk/drivers/char/mxser.h
index 844171115954..1f4aa45ec004 100644
--- a/trunk/drivers/char/mxser.h
+++ b/trunk/drivers/char/mxser.h
@@ -4,17 +4,19 @@
/*
* Semi-public control interfaces
*/
-
+
/*
* MOXA ioctls
*/
#define MOXA 0x400
#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_CONF (MOXA + 35)
#define MOXA_DIAGNOSE (MOXA + 50)
#define MOXA_CHKPORTENABLE (MOXA + 60)
#define MOXA_HighSpeedOn (MOXA + 61)
#define MOXA_GET_MAJOR (MOXA + 63)
+#define MOXA_GET_CUMAJOR (MOXA + 64)
#define MOXA_GETMSTATUS (MOXA + 65)
#define MOXA_SET_OP_MODE (MOXA + 66)
#define MOXA_GET_OP_MODE (MOXA + 67)
@@ -24,14 +26,26 @@
#define RS422_MODE 2
#define RS485_4WIRE_MODE 3
#define OP_MODE_MASK 3
+// above add by Victor Yu. 01-05-2004
+
+#define TTY_THRESHOLD_THROTTLE 128
+
+#define HI_WATER 768
+
+// added by James. 03-11-2004.
+#define MOXA_SDS_GETICOUNTER (MOXA + 68)
+#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
+// (above) added by James.
-#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
#define MOXA_ASPP_OQUEUE (MOXA + 70)
+#define MOXA_ASPP_SETBAUD (MOXA + 71)
+#define MOXA_ASPP_GETBAUD (MOXA + 72)
#define MOXA_ASPP_MON (MOXA + 73)
#define MOXA_ASPP_LSTATUS (MOXA + 74)
#define MOXA_ASPP_MON_EXT (MOXA + 75)
#define MOXA_SET_BAUD_METHOD (MOXA + 76)
+
/* --------------------------------------------------- */
#define NPPI_NOTIFY_PARITY 0x01
@@ -40,46 +54,51 @@
#define NPPI_NOTIFY_SW_OVERRUN 0x08
#define NPPI_NOTIFY_BREAK 0x10
-#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */
-#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */
-#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */
-#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */
-
-/* follow just for Moxa Must chip define. */
-/* */
-/* when LCR register (offset 0x03) write following value, */
-/* the Must chip will enter enchance mode. And write value */
-/* on EFR (offset 0x02) bit 6,7 to change bank. */
+#define NPPI_NOTIFY_CTSHOLD 0x01 // Tx hold by CTS low
+#define NPPI_NOTIFY_DSRHOLD 0x02 // Tx hold by DSR low
+#define NPPI_NOTIFY_XOFFHOLD 0x08 // Tx hold by Xoff received
+#define NPPI_NOTIFY_XOFFXENT 0x10 // Xoff Sent
+
+//CheckIsMoxaMust return value
+#define MOXA_OTHER_UART 0x00
+#define MOXA_MUST_MU150_HWID 0x01
+#define MOXA_MUST_MU860_HWID 0x02
+
+// follow just for Moxa Must chip define.
+//
+// when LCR register (offset 0x03) write following value,
+// the Must chip will enter enchance mode. And write value
+// on EFR (offset 0x02) bit 6,7 to change bank.
#define MOXA_MUST_ENTER_ENCHANCE 0xBF
-/* when enhance mode enable, access on general bank register */
+// when enhance mode enable, access on general bank register
#define MOXA_MUST_GDL_REGISTER 0x07
#define MOXA_MUST_GDL_MASK 0x7F
#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
-#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */
-/* enchance register bank select and enchance mode setting register */
-/* when LCR register equal to 0xBF */
+#define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO
+// enchance register bank select and enchance mode setting register
+// when LCR register equal to 0xBF
#define MOXA_MUST_EFR_REGISTER 0x02
-/* enchance mode enable */
+// enchance mode enable
#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
-/* enchance reister bank set 0, 1, 2 */
+// enchance reister bank set 0, 1, 2
#define MOXA_MUST_EFR_BANK0 0x00
#define MOXA_MUST_EFR_BANK1 0x40
#define MOXA_MUST_EFR_BANK2 0x80
#define MOXA_MUST_EFR_BANK3 0xC0
#define MOXA_MUST_EFR_BANK_MASK 0xC0
-/* set XON1 value register, when LCR=0xBF and change to bank0 */
+// set XON1 value register, when LCR=0xBF and change to bank0
#define MOXA_MUST_XON1_REGISTER 0x04
-/* set XON2 value register, when LCR=0xBF and change to bank0 */
+// set XON2 value register, when LCR=0xBF and change to bank0
#define MOXA_MUST_XON2_REGISTER 0x05
-/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
+// set XOFF1 value register, when LCR=0xBF and change to bank0
#define MOXA_MUST_XOFF1_REGISTER 0x06
-/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
+// set XOFF2 value register, when LCR=0xBF and change to bank0
#define MOXA_MUST_XOFF2_REGISTER 0x07
#define MOXA_MUST_RBRTL_REGISTER 0x04
@@ -91,32 +110,32 @@
#define MOXA_MUST_ECR_REGISTER 0x06
#define MOXA_MUST_CSR_REGISTER 0x07
-/* good data mode enable */
+// good data mode enable
#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
-/* only good data put into RxFIFO */
+// only good data put into RxFIFO
#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
-/* enable CTS interrupt */
+// enable CTS interrupt
#define MOXA_MUST_IER_ECTSI 0x80
-/* enable RTS interrupt */
+// enable RTS interrupt
#define MOXA_MUST_IER_ERTSI 0x40
-/* enable Xon/Xoff interrupt */
+// enable Xon/Xoff interrupt
#define MOXA_MUST_IER_XINT 0x20
-/* enable GDA interrupt */
+// enable GDA interrupt
#define MOXA_MUST_IER_EGDAI 0x10
#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
-/* GDA interrupt pending */
+// GDA interrupt pending
#define MOXA_MUST_IIR_GDA 0x1C
#define MOXA_MUST_IIR_RDA 0x04
#define MOXA_MUST_IIR_RTO 0x0C
#define MOXA_MUST_IIR_LSR 0x06
-/* recieved Xon/Xoff or specical interrupt pending */
+// recieved Xon/Xoff or specical interrupt pending
#define MOXA_MUST_IIR_XSC 0x10
-/* RTS/CTS change state interrupt pending */
+// RTS/CTS change state interrupt pending
#define MOXA_MUST_IIR_RTSCTS 0x20
#define MOXA_MUST_IIR_MASK 0x3E
@@ -124,164 +143,299 @@
#define MOXA_MUST_MCR_XON_ANY 0x80
#define MOXA_MUST_MCR_TX_XON 0x08
-/* software flow control on chip mask value */
+
+// software flow control on chip mask value
#define MOXA_MUST_EFR_SF_MASK 0x0F
-/* send Xon1/Xoff1 */
+// send Xon1/Xoff1
#define MOXA_MUST_EFR_SF_TX1 0x08
-/* send Xon2/Xoff2 */
+// send Xon2/Xoff2
#define MOXA_MUST_EFR_SF_TX2 0x04
-/* send Xon1,Xon2/Xoff1,Xoff2 */
+// send Xon1,Xon2/Xoff1,Xoff2
#define MOXA_MUST_EFR_SF_TX12 0x0C
-/* don't send Xon/Xoff */
+// don't send Xon/Xoff
#define MOXA_MUST_EFR_SF_TX_NO 0x00
-/* Tx software flow control mask */
+// Tx software flow control mask
#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
-/* don't receive Xon/Xoff */
+// don't receive Xon/Xoff
#define MOXA_MUST_EFR_SF_RX_NO 0x00
-/* receive Xon1/Xoff1 */
+// receive Xon1/Xoff1
#define MOXA_MUST_EFR_SF_RX1 0x02
-/* receive Xon2/Xoff2 */
+// receive Xon2/Xoff2
#define MOXA_MUST_EFR_SF_RX2 0x01
-/* receive Xon1,Xon2/Xoff1,Xoff2 */
+// receive Xon1,Xon2/Xoff1,Xoff2
#define MOXA_MUST_EFR_SF_RX12 0x03
-/* Rx software flow control mask */
+// Rx software flow control mask
#define MOXA_MUST_EFR_SF_RX_MASK 0x03
-#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+//#define MOXA_MUST_MIN_XOFFLIMIT 66
+//#define MOXA_MUST_MIN_XONLIMIT 20
+//#define ID1_RX_TRIG 120
+
+
+#define CHECK_MOXA_MUST_XOFFLIMIT(info) { \
+ if ( (info)->IsMoxaMustChipFlag && \
+ (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \
+ (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \
+ (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \
+ } \
+}
+
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
-#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_FIFO_VALUE(info) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((info)->ioaddr+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
- __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- outb((u8)((info)->rx_high_water), (info)->ioaddr+ \
- MOXA_MUST_RBRTH_REGISTER); \
- outb((u8)((info)->rx_trigger), (info)->ioaddr+ \
- MOXA_MUST_RBRTI_REGISTER); \
- outb((u8)((info)->rx_low_water), (info)->ioaddr+ \
- MOXA_MUST_RBRTL_REGISTER); \
- outb(__oldlcr, (info)->ioaddr+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+//#define MOXA_MUST_RBRL_VALUE 4
+#define SET_MOXA_MUST_FIFO_VALUE(info) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((info)->base+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (info)->base+UART_LCR); \
+ __efr = inb((info)->base+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (info)->base+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)((info)->rx_high_water), (info)->base+MOXA_MUST_RBRTH_REGISTER); \
+ outb((u8)((info)->rx_trigger), (info)->base+MOXA_MUST_RBRTI_REGISTER); \
+ outb((u8)((info)->rx_low_water), (info)->base+MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (info)->base+UART_LCR); \
+}
+
+
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
-#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_TX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_RX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
+ u8 __oldmcr; \
+ __oldmcr = inb((baseio)+UART_MCR); \
+ __oldmcr |= MOXA_MUST_MCR_XON_ANY; \
+ outb(__oldmcr, (baseio)+UART_MCR); \
+}
+
+#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
+ u8 __oldmcr; \
+ __oldmcr = inb((baseio)+UART_MCR); \
+ __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \
+ outb(__oldmcr, (baseio)+UART_MCR); \
+}
+
+#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)
#endif
diff --git a/trunk/drivers/char/mxser_new.c b/trunk/drivers/char/mxser_new.c
new file mode 100644
index 000000000000..bf1bee4e1f5e
--- /dev/null
+++ b/trunk/drivers/char/mxser_new.c
@@ -0,0 +1,2816 @@
+/*
+ * mxser.c -- MOXA Smartio/Industio family multiport serial driver.
+ *
+ * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 2006-2007 Jiri Slaby
+ *
+ * This code is loosely based on the 1.8 moxa driver which is based on
+ * Linux serial driver, written by Linus Torvalds, Theodore T'so and
+ * others.
+ *
+ * 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.
+ *
+ * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
+ * . The original 1.8 code is available on www.moxa.com.
+ * - Fixed x86_64 cleanness
+ * - Fixed sleep with spinlock held in mxser_send_break
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "mxser_new.h"
+
+#define MXSER_VERSION "2.0.2" /* 1.10 */
+#define MXSERMAJOR 174
+#define MXSERCUMAJOR 175
+
+#define MXSER_BOARDS 4 /* Max. boards */
+#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
+#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
+#define MXSER_ISR_PASS_LIMIT 100
+
+#define MXSER_ERR_IOADDR -1
+#define MXSER_ERR_IRQ -2
+#define MXSER_ERR_IRQ_CONFLIT -3
+#define MXSER_ERR_VECTOR -4
+
+/*CheckIsMoxaMust return value*/
+#define MOXA_OTHER_UART 0x00
+#define MOXA_MUST_MU150_HWID 0x01
+#define MOXA_MUST_MU860_HWID 0x02
+
+#define WAKEUP_CHARS 256
+
+#define UART_MCR_AFE 0x20
+#define UART_LSR_SPECIAL 0x1E
+
+#define PCI_DEVICE_ID_CB108 0x1080
+#define PCI_DEVICE_ID_CB114 0x1142
+#define PCI_DEVICE_ID_CB134I 0x1341
+#define PCI_DEVICE_ID_CP138U 0x1380
+#define PCI_DEVICE_ID_POS104UL 0x1044
+
+
+#define C168_ASIC_ID 1
+#define C104_ASIC_ID 2
+#define C102_ASIC_ID 0xB
+#define CI132_ASIC_ID 4
+#define CI134_ASIC_ID 3
+#define CI104J_ASIC_ID 5
+
+#define MXSER_HIGHBAUD 1
+#define MXSER_HAS2 2
+
+/* This is only for PCI */
+static const struct {
+ int type;
+ int tx_fifo;
+ int rx_fifo;
+ int xmit_fifo_size;
+ int rx_high_water;
+ int rx_trigger;
+ int rx_low_water;
+ long max_baud;
+} Gpci_uart_info[] = {
+ {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
+ {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
+ {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
+};
+#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
+
+struct mxser_cardinfo {
+ unsigned int nports;
+ char *name;
+ unsigned int flags;
+};
+
+static const struct mxser_cardinfo mxser_cards[] = {
+/* 0*/ { 8, "C168 series", },
+ { 4, "C104 series", },
+ { 4, "CI-104J series", },
+ { 8, "C168H/PCI series", },
+ { 4, "C104H/PCI series", },
+/* 5*/ { 4, "C102 series", MXSER_HAS2 }, /* C102-ISA */
+ { 4, "CI-132 series", MXSER_HAS2 },
+ { 4, "CI-134 series", },
+ { 2, "CP-132 series", },
+ { 4, "CP-114 series", },
+/*10*/ { 4, "CT-114 series", },
+ { 2, "CP-102 series", MXSER_HIGHBAUD },
+ { 4, "CP-104U series", },
+ { 8, "CP-168U series", },
+ { 2, "CP-132U series", },
+/*15*/ { 4, "CP-134U series", },
+ { 4, "CP-104JU series", },
+ { 8, "Moxa UC7000 Serial", }, /* RC7000 */
+ { 8, "CP-118U series", },
+ { 2, "CP-102UL series", },
+/*20*/ { 2, "CP-102U series", },
+ { 8, "CP-118EL series", },
+ { 8, "CP-168EL series", },
+ { 4, "CP-104EL series", },
+ { 8, "CB-108 series", },
+/*25*/ { 4, "CB-114 series", },
+ { 4, "CB-134I series", },
+ { 8, "CP-138U series", },
+ { 4, "POS-104UL series", }
+};
+
+/* driver_data correspond to the lines in the structure above
+ see also ISA probe function before you change something */
+static struct pci_device_id mxser_pcibrds[] = {
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+
+static int mxvar_baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+};
+static unsigned int mxvar_baud_table1[] = {
+ 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400,
+ B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600
+};
+#define BAUD_TABLE_NO ARRAY_SIZE(mxvar_baud_table)
+
+#define B_SPEC B2000000
+
+static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
+static int ttymajor = MXSERMAJOR;
+static int calloutmajor = MXSERCUMAJOR;
+
+/* Variables for insmod */
+
+MODULE_AUTHOR("Casper Yang");
+MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
+module_param_array(ioaddr, int, NULL, 0);
+module_param(ttymajor, int, 0);
+MODULE_LICENSE("GPL");
+
+struct mxser_log {
+ int tick;
+ unsigned long rxcnt[MXSER_PORTS];
+ unsigned long txcnt[MXSER_PORTS];
+};
+
+
+struct mxser_mon {
+ unsigned long rxcnt;
+ unsigned long txcnt;
+ unsigned long up_rxcnt;
+ unsigned long up_txcnt;
+ int modem_status;
+ unsigned char hold_reason;
+};
+
+struct mxser_mon_ext {
+ unsigned long rx_cnt[32];
+ unsigned long tx_cnt[32];
+ unsigned long up_rxcnt[32];
+ unsigned long up_txcnt[32];
+ int modem_status[32];
+
+ long baudrate[32];
+ int databits[32];
+ int stopbits[32];
+ int parity[32];
+ int flowctrl[32];
+ int fifo[32];
+ int iftype[32];
+};
+
+struct mxser_board;
+
+struct mxser_port {
+ struct mxser_board *board;
+ struct tty_struct *tty;
+
+ unsigned long ioaddr;
+ unsigned long opmode_ioaddr;
+ int max_baud;
+
+ int rx_high_water;
+ int rx_trigger; /* Rx fifo trigger level */
+ int rx_low_water;
+ int baud_base; /* max. speed */
+ long realbaud;
+ int type; /* UART type */
+ int flags; /* defined in tty.h */
+ int speed;
+
+ int x_char; /* xon/xoff character */
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+
+ unsigned char stop_rx;
+ unsigned char ldisc_stop_rx;
+
+ int custom_divisor;
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned char err_shadow;
+ unsigned long event;
+
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ struct async_icount icount; /* kernel counters for 4 input interrupts */
+ int timeout;
+
+ int read_status_mask;
+ int ignore_status_mask;
+ int xmit_fifo_size;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+
+ struct ktermios normal_termios;
+
+ struct mxser_mon mon_data;
+
+ spinlock_t slock;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t delta_msr_wait;
+};
+
+struct mxser_board {
+ unsigned int idx;
+ int irq;
+ const struct mxser_cardinfo *info;
+ unsigned long vector;
+ unsigned long vector_mask;
+
+ int chip_flag;
+ int uart_type;
+
+ struct mxser_port ports[MXSER_PORTS_PER_BOARD];
+};
+
+struct mxser_mstatus {
+ tcflag_t cflag;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MXSER_PORTS];
+
+static int mxserBoardCAP[MXSER_BOARDS] = {
+ 0, 0, 0, 0
+ /* 0x180, 0x280, 0x200, 0x320 */
+};
+
+static struct mxser_board mxser_boards[MXSER_BOARDS];
+static struct tty_driver *mxvar_sdriver;
+static struct mxser_log mxvar_log;
+static int mxvar_diagflag;
+static unsigned char mxser_msr[MXSER_PORTS + 1];
+static struct mxser_mon_ext mon_data_ext;
+static int mxser_set_baud_method[MXSER_PORTS + 1];
+
+#ifdef CONFIG_PCI
+static int __devinit CheckIsMoxaMust(int io)
+{
+ u8 oldmcr, hwid;
+ int i;
+
+ outb(0, io + UART_LCR);
+ DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
+ oldmcr = inb(io + UART_MCR);
+ outb(0, io + UART_MCR);
+ SET_MOXA_MUST_XON1_VALUE(io, 0x11);
+ if ((hwid = inb(io + UART_MCR)) != 0) {
+ outb(oldmcr, io + UART_MCR);
+ return MOXA_OTHER_UART;
+ }
+
+ GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
+ for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+ if (hwid == Gpci_uart_info[i].type)
+ return (int)hwid;
+ }
+ return MOXA_OTHER_UART;
+}
+#endif
+
+static void process_txrx_fifo(struct mxser_port *info)
+{
+ int i;
+
+ if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
+ info->rx_trigger = 1;
+ info->rx_high_water = 1;
+ info->rx_low_water = 1;
+ info->xmit_fifo_size = 1;
+ } else
+ for (i = 0; i < UART_INFO_NUM; i++)
+ if (info->board->chip_flag == Gpci_uart_info[i].type) {
+ info->rx_trigger = Gpci_uart_info[i].rx_trigger;
+ info->rx_low_water = Gpci_uart_info[i].rx_low_water;
+ info->rx_high_water = Gpci_uart_info[i].rx_high_water;
+ info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
+ break;
+ }
+}
+
+static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
+{
+ unsigned char status = 0;
+
+ status = inb(baseaddr + UART_MSR);
+
+ mxser_msr[port] &= 0x0F;
+ mxser_msr[port] |= status;
+ status = mxser_msr[port];
+ if (mode)
+ mxser_msr[port] = 0;
+
+ return status;
+}
+
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct mxser_port *port)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+ unsigned long flags;
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ test_bit(TTY_IO_ERROR, &tty->flags)) {
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, port->count is dropped by one, so that
+ * mxser_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&port->open_wait, &wait);
+
+ spin_lock_irqsave(&port->slock, flags);
+ if (!tty_hung_up_p(filp))
+ port->count--;
+ spin_unlock_irqrestore(&port->slock, flags);
+ port->blocked_open++;
+ while (1) {
+ spin_lock_irqsave(&port->slock, flags);
+ outb(inb(port->ioaddr + UART_MCR) |
+ UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&port->slock, flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(port->flags & ASYNC_CLOSING) &&
+ (do_clocal ||
+ (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ if (retval)
+ return retval;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int mxser_set_baud(struct mxser_port *info, long newspd)
+{
+ unsigned int i;
+ int quot = 0;
+ unsigned char cval;
+ int ret = 0;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+
+ if (!(info->ioaddr))
+ return ret;
+
+ if (newspd > info->max_baud)
+ return 0;
+
+ info->realbaud = newspd;
+ for (i = 0; i < BAUD_TABLE_NO; i++)
+ if (newspd == mxvar_baud_table[i])
+ break;
+ if (i == BAUD_TABLE_NO) {
+ quot = info->baud_base / info->speed;
+ if (info->speed <= 0 || info->speed > info->max_baud)
+ quot = 0;
+ } else {
+ if (newspd == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (newspd) {
+ quot = info->baud_base / newspd;
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
+ }
+
+ info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
+ info->timeout += HZ / 50; /* Add .02 seconds of slop */
+
+ if (quot) {
+ info->MCR |= UART_MCR_DTR;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ } else {
+ info->MCR &= ~UART_MCR_DTR;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ return ret;
+ }
+
+ cval = inb(info->ioaddr + UART_LCR);
+
+ outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */
+
+ outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */
+ outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
+ outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
+
+ if (i == BAUD_TABLE_NO) {
+ quot = info->baud_base % info->speed;
+ quot *= 8;
+ if ((quot % info->speed) > (info->speed / 2)) {
+ quot /= info->speed;
+ quot++;
+ } else {
+ quot /= info->speed;
+ }
+ SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+ } else
+ SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
+
+ return ret;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_port *info,
+ struct ktermios *old_termios)
+{
+ unsigned cflag, cval, fcr;
+ int ret = 0;
+ unsigned char status;
+ long baud;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+ cflag = info->tty->termios->c_cflag;
+ if (!(info->ioaddr))
+ return ret;
+
+ if (mxser_set_baud_method[info->tty->index] == 0) {
+ if ((cflag & CBAUD) == B_SPEC)
+ baud = info->speed;
+ else
+ baud = tty_get_baud_rate(info->tty);
+ mxser_set_baud(info, baud);
+ }
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cval = 0x00;
+ break;
+ case CS6:
+ cval = 0x01;
+ break;
+ case CS7:
+ cval = 0x02;
+ break;
+ case CS8:
+ cval = 0x03;
+ break;
+ default:
+ cval = 0x00;
+ break; /* too keep GCC shut... */
+ }
+ if (cflag & CSTOPB)
+ cval |= 0x04;
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+ if (cflag & CMSPAR)
+ cval |= UART_LCR_SPAR;
+
+ if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+ if (info->board->chip_flag) {
+ fcr = UART_FCR_ENABLE_FIFO;
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else
+ fcr = 0;
+ } else {
+ fcr = UART_FCR_ENABLE_FIFO;
+ if (info->board->chip_flag) {
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else {
+ switch (info->rx_trigger) {
+ case 1:
+ fcr |= UART_FCR_TRIGGER_1;
+ break;
+ case 4:
+ fcr |= UART_FCR_TRIGGER_4;
+ break;
+ case 8:
+ fcr |= UART_FCR_TRIGGER_8;
+ break;
+ default:
+ fcr |= UART_FCR_TRIGGER_14;
+ break;
+ }
+ }
+ }
+
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ info->MCR &= ~UART_MCR_AFE;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
+ info->MCR |= UART_MCR_AFE;
+ } else {
+ status = inb(info->ioaddr + UART_MSR);
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ info->tty->hw_stopped = 0;
+ if (info->type != PORT_16550A &&
+ !info->board->chip_flag) {
+ outb(info->IER & ~UART_IER_THRI,
+ info->ioaddr +
+ UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr +
+ UART_IER);
+ }
+ tty_wakeup(info->tty);
+ }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ info->tty->hw_stopped = 1;
+ if ((info->type != PORT_16550A) &&
+ (!info->board->chip_flag)) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr +
+ UART_IER);
+ }
+ }
+ }
+ }
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ }
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ if (cflag & CLOCAL) {
+ info->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ outb(info->IER, info->ioaddr + UART_IER);
+
+ /*
+ * Set up parity check flag
+ */
+ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
+
+ info->ignore_status_mask = 0;
+
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ info->read_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty)) {
+ info->ignore_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ info->read_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ }
+ }
+ if (info->board->chip_flag) {
+ SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
+ SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+ if (I_IXON(info->tty)) {
+ ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ } else {
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ }
+ if (I_IXOFF(info->tty)) {
+ ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ } else {
+ DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ }
+ }
+
+
+ outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
+ outb(cval, info->ioaddr + UART_LCR);
+
+ return ret;
+}
+
+static void mxser_check_modem_status(struct mxser_port *port, int status)
+{
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ port->icount.cts++;
+ port->mon_data.modem_status = status;
+ wake_up_interruptible(&port->delta_msr_wait);
+
+ if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+ if (status & UART_MSR_DCD)
+ wake_up_interruptible(&port->open_wait);
+ }
+
+ if (port->flags & ASYNC_CTS_FLOW) {
+ if (port->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ port->tty->hw_stopped = 0;
+
+ if ((port->type != PORT_16550A) &&
+ (!port->board->chip_flag)) {
+ outb(port->IER & ~UART_IER_THRI,
+ port->ioaddr + UART_IER);
+ port->IER |= UART_IER_THRI;
+ outb(port->IER, port->ioaddr +
+ UART_IER);
+ }
+ tty_wakeup(port->tty);
+ }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ port->tty->hw_stopped = 1;
+ if (port->type != PORT_16550A &&
+ !port->board->chip_flag) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr +
+ UART_IER);
+ }
+ }
+ }
+ }
+}
+
+static int mxser_startup(struct mxser_port *info)
+{
+ unsigned long page;
+ unsigned long flags;
+
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+
+ if (!info->ioaddr || !info->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in mxser_change_speed())
+ */
+ if (info->board->chip_flag)
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
+ else
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+
+ /*
+ * At this point there's no way the LSR could still be 0xFF;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (inb(info->ioaddr + UART_LSR) == 0xff) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ return 0;
+ } else
+ return -ENODEV;
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) inb(info->ioaddr + UART_LSR);
+ (void) inb(info->ioaddr + UART_RX);
+ (void) inb(info->ioaddr + UART_IIR);
+ (void) inb(info->ioaddr + UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+
+ /*
+ * Finally, enable interrupts
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+
+ if (info->board->chip_flag)
+ info->IER |= MOXA_MUST_IER_EGDAI;
+ outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ (void) inb(info->ioaddr + UART_LSR);
+ (void) inb(info->ioaddr + UART_RX);
+ (void) inb(info->ioaddr + UART_IIR);
+ (void) inb(info->ioaddr + UART_MSR);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * and set the speed of the serial port
+ */
+ mxser_change_speed(info, NULL);
+ info->flags |= ASYNC_INITIALIZED;
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_port *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = NULL;
+ }
+
+ info->IER = 0;
+ outb(0x00, info->ioaddr + UART_IER);
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ outb(info->MCR, info->ioaddr + UART_MCR);
+
+ /* clear Rx/Tx FIFO's */
+ if (info->board->chip_flag)
+ outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE,
+ info->ioaddr + UART_FCR);
+ else
+ outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ info->ioaddr + UART_FCR);
+
+ /* read data port to reset things */
+ (void) inb(info->ioaddr + UART_RX);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ if (info->board->chip_flag)
+ SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info;
+ unsigned long flags;
+ int retval, line;
+
+ line = tty->index;
+ if (line == MXSER_PORTS)
+ return 0;
+ if (line < 0 || line > MXSER_PORTS)
+ return -ENODEV;
+ info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
+ if (!info->ioaddr)
+ return -ENODEV;
+
+ tty->driver_data = info;
+ info->tty = tty;
+ /*
+ * Start up serial port
+ */
+ spin_lock_irqsave(&info->slock, flags);
+ info->count++;
+ spin_unlock_irqrestore(&info->slock, flags);
+ retval = mxser_startup(info);
+ if (retval)
+ return retval;
+
+ retval = mxser_block_til_ready(tty, filp, info);
+ if (retval)
+ return retval;
+
+ /* unmark here for very high baud rate (ex. 921600 bps) used */
+ tty->low_latency = 1;
+ return 0;
+}
+
+/*
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void mxser_close(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ unsigned long timeout;
+ unsigned long flags;
+
+ if (tty->index == MXSER_PORTS)
+ return;
+ if (!info)
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk(KERN_ERR "mxser_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk(KERN_ERR "mxser_close: bad serial port count for "
+ "ttys%d: %d\n", tty->index, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ spin_unlock_irqrestore(&info->slock, flags);
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ info->IER &= ~UART_IER_RLSI;
+ if (info->board->chip_flag)
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ outb(info->IER, info->ioaddr + UART_IER);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ timeout = jiffies + HZ;
+ while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
+ schedule_timeout_interruptible(5);
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ }
+ mxser_shutdown(info);
+
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+
+ tty_ldisc_flush(tty);
+
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->close_delay)
+ schedule_timeout_interruptible(info->close_delay);
+ wake_up_interruptible(&info->open_wait);
+ }
+
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+}
+
+static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!info->xmit_buf)
+ return 0;
+
+ while (1) {
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ buf += c;
+ count -= c;
+ total += c;
+ }
+
+ if (info->xmit_cnt && !tty->stopped) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ (info->board->chip_flag)) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr +
+ UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ }
+ return total;
+}
+
+static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!info->xmit_buf)
+ return;
+
+ if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ info->xmit_cnt++;
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (!tty->stopped) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ }
+}
+
+
+static void mxser_flush_chars(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (info->xmit_cnt <= 0 ||
+ tty->stopped ||
+ !info->xmit_buf ||
+ (tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->board->chip_flag)
+ ))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static int mxser_write_room(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ int ret;
+
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int mxser_chars_in_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ return info->xmit_cnt;
+}
+
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ char fcr;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ fcr = inb(info->ioaddr + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+ outb(fcr, info->ioaddr + UART_FCR);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_wakeup(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_port *info,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->tty->index;
+ tmp.port = info->ioaddr;
+ tmp.irq = info->board->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0;
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int mxser_set_serial_info(struct mxser_port *info,
+ struct serial_struct __user *new_info)
+{
+ struct serial_struct new_serial;
+ unsigned long sl_flags;
+ unsigned int flags;
+ int retval = 0;
+
+ if (!new_info || !info->ioaddr)
+ return -EFAULT;
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+
+ if ((new_serial.irq != info->board->irq) ||
+ (new_serial.port != info->ioaddr) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return -EPERM;
+
+ flags = info->flags & ASYNC_SPD_MASK;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ } else {
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
+ info->tty->low_latency =
+ (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency = 0;
+ }
+
+ info->type = new_serial.type;
+
+ process_txrx_fifo(info);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ if (flags != (info->flags & ASYNC_SPD_MASK)) {
+ spin_lock_irqsave(&info->slock, sl_flags);
+ mxser_change_speed(info, NULL);
+ spin_unlock_irqrestore(&info->slock, sl_flags);
+ }
+ } else
+ retval = mxser_startup(info);
+
+ return retval;
+}
+
+/*
+ * mxser_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int mxser_get_lsr_info(struct mxser_port *info,
+ unsigned int __user *value)
+{
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->ioaddr + UART_LSR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+ return put_user(result, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_port *info, int duration)
+{
+ unsigned long flags;
+
+ if (!info->ioaddr)
+ return;
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ schedule_timeout(duration);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned char control, status;
+ unsigned long flags;
+
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ control = info->MCR;
+
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->ioaddr + UART_MSR);
+ if (status & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, status);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+}
+
+static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (set & TIOCM_RTS)
+ info->MCR |= UART_MCR_RTS;
+ if (set & TIOCM_DTR)
+ info->MCR |= UART_MCR_DTR;
+
+ if (clear & TIOCM_RTS)
+ info->MCR &= ~UART_MCR_RTS;
+ if (clear & TIOCM_DTR)
+ info->MCR &= ~UART_MCR_DTR;
+
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+}
+
+static int __init mxser_program_mode(int port)
+{
+ int id, i, j, n;
+
+ outb(0, port);
+ outb(0, port);
+ outb(0, port);
+ (void)inb(port);
+ (void)inb(port);
+ outb(0, port);
+ (void)inb(port);
+
+ id = inb(port + 1) & 0x1F;
+ if ((id != C168_ASIC_ID) &&
+ (id != C104_ASIC_ID) &&
+ (id != C102_ASIC_ID) &&
+ (id != CI132_ASIC_ID) &&
+ (id != CI134_ASIC_ID) &&
+ (id != CI104J_ASIC_ID))
+ return -1;
+ for (i = 0, j = 0; i < 4; i++) {
+ n = inb(port + 2);
+ if (n == 'M') {
+ j = 1;
+ } else if ((j == 1) && (n == 1)) {
+ j = 2;
+ break;
+ } else
+ j = 0;
+ }
+ if (j != 2)
+ id = -2;
+ return id;
+}
+
+static void __init mxser_normal_mode(int port)
+{
+ int i, n;
+
+ outb(0xA5, port + 1);
+ outb(0x80, port + 3);
+ outb(12, port + 0); /* 9600 bps */
+ outb(0, port + 1);
+ outb(0x03, port + 3); /* 8 data bits */
+ outb(0x13, port + 4); /* loop back mode */
+ for (i = 0; i < 16; i++) {
+ n = inb(port + 5);
+ if ((n & 0x61) == 0x60)
+ break;
+ if ((n & 1) == 1)
+ (void)inb(port);
+ }
+ outb(0x00, port + 4);
+}
+
+#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
+#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
+#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
+#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
+#define EN_CCMD 0x000 /* Chip's command register */
+#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
+#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
+#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
+#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
+#define EN0_DCFG 0x00E /* Data configuration reg WR */
+#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
+#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
+#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
+static int __init mxser_read_register(int port, unsigned short *regs)
+{
+ int i, k, value, id;
+ unsigned int j;
+
+ id = mxser_program_mode(port);
+ if (id < 0)
+ return id;
+ for (i = 0; i < 14; i++) {
+ k = (i & 0x3F) | 0x180;
+ for (j = 0x100; j > 0; j >>= 1) {
+ outb(CHIP_CS, port);
+ if (k & j) {
+ outb(CHIP_CS | CHIP_DO, port);
+ outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
+ } else {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
+ }
+ }
+ (void)inb(port);
+ value = 0;
+ for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port);
+ if (inb(port) & CHIP_DI)
+ value |= j;
+ }
+ regs[i] = value;
+ outb(0, port);
+ }
+ mxser_normal_mode(port);
+ return id;
+}
+
+static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
+{
+ struct mxser_port *port;
+ int result, status;
+ unsigned int i, j;
+
+ switch (cmd) {
+ case MOXA_GET_CONF:
+/* if (copy_to_user(argp, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
+ return -EFAULT;
+ return 0;*/
+ return -ENXIO;
+ case MOXA_GET_MAJOR:
+ if (copy_to_user(argp, &ttymajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_GET_CUMAJOR:
+ if (copy_to_user(argp, &calloutmajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_CHKPORTENABLE:
+ result = 0;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
+ if (mxser_boards[i].ports[j].ioaddr)
+ result |= (1 << i);
+
+ return put_user(result, (unsigned long __user *)argp);
+ case MOXA_GETDATACOUNT:
+ if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
+ return -EFAULT;
+ return 0;
+ case MOXA_GETMSTATUS:
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ port = &mxser_boards[i].ports[j];
+
+ GMStatus[i].ri = 0;
+ if (!port->ioaddr) {
+ GMStatus[i].dcd = 0;
+ GMStatus[i].dsr = 0;
+ GMStatus[i].cts = 0;
+ continue;
+ }
+
+ if (!port->tty || !port->tty->termios)
+ GMStatus[i].cflag =
+ port->normal_termios.c_cflag;
+ else
+ GMStatus[i].cflag =
+ port->tty->termios->c_cflag;
+
+ status = inb(port->ioaddr + UART_MSR);
+ if (status & 0x80 /*UART_MSR_DCD */ )
+ GMStatus[i].dcd = 1;
+ else
+ GMStatus[i].dcd = 0;
+
+ if (status & 0x20 /*UART_MSR_DSR */ )
+ GMStatus[i].dsr = 1;
+ else
+ GMStatus[i].dsr = 0;
+
+
+ if (status & 0x10 /*UART_MSR_CTS */ )
+ GMStatus[i].cts = 1;
+ else
+ GMStatus[i].cts = 0;
+ }
+ if (copy_to_user(argp, GMStatus,
+ sizeof(struct mxser_mstatus) * MXSER_PORTS))
+ return -EFAULT;
+ return 0;
+ case MOXA_ASPP_MON_EXT: {
+ int p, shiftbit;
+ unsigned long opmode;
+ unsigned cflag, iflag;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ port = &mxser_boards[i].ports[j];
+ if (!port->ioaddr)
+ continue;
+
+ status = mxser_get_msr(port->ioaddr, 0, i);
+
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ port->icount.cts++;
+
+ port->mon_data.modem_status = status;
+ mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
+ mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
+ mon_data_ext.up_rxcnt[i] =
+ port->mon_data.up_rxcnt;
+ mon_data_ext.up_txcnt[i] =
+ port->mon_data.up_txcnt;
+ mon_data_ext.modem_status[i] =
+ port->mon_data.modem_status;
+ mon_data_ext.baudrate[i] = port->realbaud;
+
+ if (!port->tty || !port->tty->termios) {
+ cflag = port->normal_termios.c_cflag;
+ iflag = port->normal_termios.c_iflag;
+ } else {
+ cflag = port->tty->termios->c_cflag;
+ iflag = port->tty->termios->c_iflag;
+ }
+
+ mon_data_ext.databits[i] = cflag & CSIZE;
+
+ mon_data_ext.stopbits[i] = cflag & CSTOPB;
+
+ mon_data_ext.parity[i] =
+ cflag & (PARENB | PARODD | CMSPAR);
+
+ mon_data_ext.flowctrl[i] = 0x00;
+
+ if (cflag & CRTSCTS)
+ mon_data_ext.flowctrl[i] |= 0x03;
+
+ if (iflag & (IXON | IXOFF))
+ mon_data_ext.flowctrl[i] |= 0x0C;
+
+ if (port->type == PORT_16550A)
+ mon_data_ext.fifo[i] = 1;
+ else
+ mon_data_ext.fifo[i] = 0;
+
+ p = i % 4;
+ shiftbit = p * 2;
+ opmode = inb(port->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+
+ mon_data_ext.iftype[i] = opmode;
+
+ }
+ if (copy_to_user(argp, &mon_data_ext,
+ sizeof(mon_data_ext)))
+ return -EFAULT;
+
+ return 0;
+
+ } default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int mxser_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mxser_port *info = tty->driver_data;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser;
+ unsigned long templ;
+ unsigned long flags;
+ unsigned int i;
+ void __user *argp = (void __user *)arg;
+ int retval;
+
+ if (tty->index == MXSER_PORTS)
+ return mxser_ioctl_special(cmd, argp);
+
+ if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
+ int p;
+ unsigned long opmode;
+ static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
+ int shiftbit;
+ unsigned char val, mask;
+
+ p = tty->index % 4;
+ if (cmd == MOXA_SET_OP_MODE) {
+ if (get_user(opmode, (int __user *) argp))
+ return -EFAULT;
+ if (opmode != RS232_MODE &&
+ opmode != RS485_2WIRE_MODE &&
+ opmode != RS422_MODE &&
+ opmode != RS485_4WIRE_MODE)
+ return -EFAULT;
+ mask = ModeMask[p];
+ shiftbit = p * 2;
+ val = inb(info->opmode_ioaddr);
+ val &= mask;
+ val |= (opmode << shiftbit);
+ outb(val, info->opmode_ioaddr);
+ } else {
+ shiftbit = p * 2;
+ opmode = inb(info->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+ if (copy_to_user(argp, &opmode, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+
+ if (cmd == MOXA_SET_SPECIAL_BAUD_RATE) {
+ int speed;
+
+ if (get_user(speed, (int __user *)argp))
+ return -EFAULT;
+ if (speed <= 0 || speed > info->max_baud)
+ return -EFAULT;
+ if (!info->tty || !info->tty->termios || !info->ioaddr)
+ return 0;
+ info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX);
+ for (i = 0; i < BAUD_TABLE_NO; i++)
+ if (speed == mxvar_baud_table[i])
+ break;
+ if (i == BAUD_TABLE_NO) {
+ info->tty->termios->c_cflag |= B_SPEC;
+ } else if (speed != 0)
+ info->tty->termios->c_cflag |= mxvar_baud_table1[i];
+
+ info->speed = speed;
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_change_speed(info, NULL);
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ return 0;
+ } else if (cmd == MOXA_GET_SPECIAL_BAUD_RATE) {
+ if (copy_to_user(argp, &info->speed, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ }
+
+ if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
+ test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ mxser_send_break(info, HZ / 4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+ return 0;
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
+ case TIOCSSOFTCAR:
+ if (get_user(templ, (unsigned long __user *) argp))
+ return -EFAULT;
+ arg = templ;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCGSERIAL:
+ return mxser_get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ return mxser_set_serial_info(info, argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return mxser_get_lsr_info(info, argp);
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ wait_event_interruptible(info->delta_msr_wait, ({
+ cprev = cnow;
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount; /* atomic copy */
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
+ }));
+ break;
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->slock, flags);
+ p_cuser = argp;
+ if (put_user(cnow.frame, &p_cuser->frame))
+ return -EFAULT;
+ if (put_user(cnow.brk, &p_cuser->brk))
+ return -EFAULT;
+ if (put_user(cnow.overrun, &p_cuser->overrun))
+ return -EFAULT;
+ if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+ return -EFAULT;
+ if (put_user(cnow.parity, &p_cuser->parity))
+ return -EFAULT;
+ if (put_user(cnow.rx, &p_cuser->rx))
+ return -EFAULT;
+ if (put_user(cnow.tx, &p_cuser->tx))
+ return -EFAULT;
+ put_user(cnow.cts, &p_cuser->cts);
+ put_user(cnow.dsr, &p_cuser->dsr);
+ put_user(cnow.rng, &p_cuser->rng);
+ put_user(cnow.dcd, &p_cuser->dcd);
+ return 0;
+ case MOXA_HighSpeedOn:
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+ case MOXA_SDS_RSTICOUNTER:
+ info->mon_data.rxcnt = 0;
+ info->mon_data.txcnt = 0;
+ return 0;
+ case MOXA_ASPP_SETBAUD:{
+ long baud;
+ if (get_user(baud, (long __user *)argp))
+ return -EFAULT;
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_set_baud(info, baud);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+ case MOXA_ASPP_GETBAUD:
+ if (copy_to_user(argp, &info->realbaud, sizeof(long)))
+ return -EFAULT;
+
+ return 0;
+
+ case MOXA_ASPP_OQUEUE:{
+ int len, lsr;
+
+ len = mxser_chars_in_buffer(tty);
+
+ lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
+
+ len += (lsr ? 0 : 1);
+
+ if (copy_to_user(argp, &len, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case MOXA_ASPP_MON: {
+ int mcr, status;
+
+ status = mxser_get_msr(info->ioaddr, 1, tty->index);
+ mxser_check_modem_status(info, status);
+
+ mcr = inb(info->ioaddr + UART_MCR);
+ if (mcr & MOXA_MUST_MCR_XON_FLAG)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
+
+ if (mcr & MOXA_MUST_MCR_TX_XON)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
+
+ if (info->tty->hw_stopped)
+ info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
+ else
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
+
+ if (copy_to_user(argp, &info->mon_data,
+ sizeof(struct mxser_mon)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case MOXA_ASPP_LSTATUS: {
+ if (copy_to_user(argp, &info->err_shadow,
+ sizeof(unsigned char)))
+ return -EFAULT;
+
+ info->err_shadow = 0;
+ return 0;
+ }
+ case MOXA_SET_BAUD_METHOD: {
+ int method;
+
+ if (get_user(method, (int __user *)argp))
+ return -EFAULT;
+ mxser_set_baud_method[tty->index] = method;
+ if (copy_to_user(argp, &method, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void mxser_stoprx(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ info->ldisc_stop_rx = 1;
+ if (I_IXOFF(tty)) {
+ if (info->board->chip_flag) {
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->ioaddr + UART_IER);
+ } else {
+ info->x_char = STOP_CHAR(tty);
+ outb(0, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ }
+
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR &= ~UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ }
+}
+
+/*
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ */
+static void mxser_throttle(struct tty_struct *tty)
+{
+ mxser_stoprx(tty);
+}
+
+static void mxser_unthrottle(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ /* startrx */
+ info->ldisc_stop_rx = 0;
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ if (info->board->chip_flag) {
+ info->IER |= MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->ioaddr + UART_IER);
+ } else {
+ info->x_char = START_CHAR(tty);
+ outb(0, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ }
+ }
+
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR |= UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ }
+}
+
+/*
+ * mxser_stop() and mxser_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ */
+static void mxser_stop(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (info->IER & UART_IER_THRI) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_start(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (info->xmit_cnt && info->xmit_buf) {
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_change_speed(info, old_termios);
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
+ }
+
+ /* Handle sw stopped */
+ if ((old_termios->c_iflag & IXON) &&
+ !(tty->termios->c_iflag & IXON)) {
+ tty->stopped = 0;
+
+ if (info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+
+ mxser_start(tty);
+ }
+}
+
+/*
+ * mxser_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+ int lsr;
+
+ if (info->type == PORT_UNKNOWN)
+ return;
+
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout && timeout < char_time)
+ char_time = timeout;
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2 * info->timeout)
+ timeout = 2 * info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+ timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+ while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+ schedule_timeout_interruptible(char_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+static void mxser_hangup(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ mxser_flush_buffer(tty);
+ mxser_shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ info->tty = NULL;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * mxser_rs_break() --- routine which turns the break handling on or off
+ */
+static void mxser_rs_break(struct tty_struct *tty, int break_state)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (break_state == -1)
+ outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ else
+ outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_receive_chars(struct mxser_port *port, int *status)
+{
+ struct tty_struct *tty = port->tty;
+ unsigned char ch, gdl;
+ int ignored = 0;
+ int cnt = 0;
+ int recv_room;
+ int max = 256;
+
+ recv_room = tty->receive_room;
+ if ((recv_room == 0) && (!port->ldisc_stop_rx))
+ mxser_stoprx(tty);
+
+ if (port->board->chip_flag != MOXA_OTHER_UART) {
+
+ if (*status & UART_LSR_SPECIAL)
+ goto intr_old;
+ if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
+ (*status & MOXA_MUST_LSR_RERR))
+ goto intr_old;
+ if (*status & MOXA_MUST_LSR_RERR)
+ goto intr_old;
+
+ gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
+
+ if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
+ gdl &= MOXA_MUST_GDL_MASK;
+ if (gdl >= recv_room) {
+ if (!port->ldisc_stop_rx)
+ mxser_stoprx(tty);
+ }
+ while (gdl--) {
+ ch = inb(port->ioaddr + UART_RX);
+ tty_insert_flip_char(tty, ch, 0);
+ cnt++;
+ }
+ goto end_intr;
+ }
+intr_old:
+
+ do {
+ if (max-- < 0)
+ break;
+
+ ch = inb(port->ioaddr + UART_RX);
+ if (port->board->chip_flag && (*status & UART_LSR_OE))
+ outb(0x23, port->ioaddr + UART_FCR);
+ *status &= port->read_status_mask;
+ if (*status & port->ignore_status_mask) {
+ if (++ignored > 100)
+ break;
+ } else {
+ char flag = 0;
+ if (*status & UART_LSR_SPECIAL) {
+ if (*status & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ port->icount.brk++;
+
+ if (port->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (*status & UART_LSR_PE) {
+ flag = TTY_PARITY;
+ port->icount.parity++;
+ } else if (*status & UART_LSR_FE) {
+ flag = TTY_FRAME;
+ port->icount.frame++;
+ } else if (*status & UART_LSR_OE) {
+ flag = TTY_OVERRUN;
+ port->icount.overrun++;
+ } else
+ flag = TTY_BREAK;
+ }
+ tty_insert_flip_char(tty, ch, flag);
+ cnt++;
+ if (cnt >= recv_room) {
+ if (!port->ldisc_stop_rx)
+ mxser_stoprx(tty);
+ break;
+ }
+
+ }
+
+ if (port->board->chip_flag)
+ break;
+
+ *status = inb(port->ioaddr + UART_LSR);
+ } while (*status & UART_LSR_DR);
+
+end_intr:
+ mxvar_log.rxcnt[port->tty->index] += cnt;
+ port->mon_data.rxcnt += cnt;
+ port->mon_data.up_rxcnt += cnt;
+
+ /*
+ * We are called from an interrupt context with &port->slock
+ * being held. Drop it temporarily in order to prevent
+ * recursive locking.
+ */
+ spin_unlock(&port->slock);
+ tty_flip_buffer_push(tty);
+ spin_lock(&port->slock);
+}
+
+static void mxser_transmit_chars(struct mxser_port *port)
+{
+ int count, cnt;
+
+ if (port->x_char) {
+ outb(port->x_char, port->ioaddr + UART_TX);
+ port->x_char = 0;
+ mxvar_log.txcnt[port->tty->index]++;
+ port->mon_data.txcnt++;
+ port->mon_data.up_txcnt++;
+ port->icount.tx++;
+ return;
+ }
+
+ if (port->xmit_buf == 0)
+ return;
+
+ if ((port->xmit_cnt <= 0) || port->tty->stopped ||
+ (port->tty->hw_stopped &&
+ (port->type != PORT_16550A) &&
+ (!port->board->chip_flag))) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr + UART_IER);
+ return;
+ }
+
+ cnt = port->xmit_cnt;
+ count = port->xmit_fifo_size;
+ do {
+ outb(port->xmit_buf[port->xmit_tail++],
+ port->ioaddr + UART_TX);
+ port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ if (--port->xmit_cnt <= 0)
+ break;
+ } while (--count > 0);
+ mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
+
+ port->mon_data.txcnt += (cnt - port->xmit_cnt);
+ port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
+ port->icount.tx += (cnt - port->xmit_cnt);
+
+ if (port->xmit_cnt < WAKEUP_CHARS)
+ tty_wakeup(port->tty);
+
+ if (port->xmit_cnt <= 0) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr + UART_IER);
+ }
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
+{
+ int status, iir, i;
+ struct mxser_board *brd = NULL;
+ struct mxser_port *port;
+ int max, irqbits, bits, msr;
+ unsigned int int_cnt, pass_counter = 0;
+ int handled = IRQ_NONE;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (dev_id == &mxser_boards[i]) {
+ brd = dev_id;
+ break;
+ }
+
+ if (i == MXSER_BOARDS)
+ goto irq_stop;
+ if (brd == NULL)
+ goto irq_stop;
+ max = brd->info->nports;
+ while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
+ irqbits = inb(brd->vector) & brd->vector_mask;
+ if (irqbits == brd->vector_mask)
+ break;
+
+ handled = IRQ_HANDLED;
+ for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+ if (irqbits == brd->vector_mask)
+ break;
+ if (bits & irqbits)
+ continue;
+ port = &brd->ports[i];
+
+ int_cnt = 0;
+ spin_lock(&port->slock);
+ do {
+ iir = inb(port->ioaddr + UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ break;
+ iir &= MOXA_MUST_IIR_MASK;
+ if (!port->tty ||
+ (port->flags & ASYNC_CLOSING) ||
+ !(port->flags &
+ ASYNC_INITIALIZED)) {
+ status = inb(port->ioaddr + UART_LSR);
+ outb(0x27, port->ioaddr + UART_FCR);
+ inb(port->ioaddr + UART_MSR);
+ break;
+ }
+
+ status = inb(port->ioaddr + UART_LSR);
+
+ if (status & UART_LSR_PE)
+ port->err_shadow |= NPPI_NOTIFY_PARITY;
+ if (status & UART_LSR_FE)
+ port->err_shadow |= NPPI_NOTIFY_FRAMING;
+ if (status & UART_LSR_OE)
+ port->err_shadow |=
+ NPPI_NOTIFY_HW_OVERRUN;
+ if (status & UART_LSR_BI)
+ port->err_shadow |= NPPI_NOTIFY_BREAK;
+
+ if (port->board->chip_flag) {
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
+ mxser_receive_chars(port,
+ &status);
+
+ } else {
+ status &= port->read_status_mask;
+ if (status & UART_LSR_DR)
+ mxser_receive_chars(port,
+ &status);
+ }
+ msr = inb(port->ioaddr + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(port, msr);
+
+ if (port->board->chip_flag) {
+ if (iir == 0x02 && (status &
+ UART_LSR_THRE))
+ mxser_transmit_chars(port);
+ } else {
+ if (status & UART_LSR_THRE)
+ mxser_transmit_chars(port);
+ }
+ } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
+ spin_unlock(&port->slock);
+ }
+ }
+
+irq_stop:
+ return handled;
+}
+
+static const struct tty_operations mxser_ops = {
+ .open = mxser_open,
+ .close = mxser_close,
+ .write = mxser_write,
+ .put_char = mxser_put_char,
+ .flush_chars = mxser_flush_chars,
+ .write_room = mxser_write_room,
+ .chars_in_buffer = mxser_chars_in_buffer,
+ .flush_buffer = mxser_flush_buffer,
+ .ioctl = mxser_ioctl,
+ .throttle = mxser_throttle,
+ .unthrottle = mxser_unthrottle,
+ .set_termios = mxser_set_termios,
+ .stop = mxser_stop,
+ .start = mxser_start,
+ .hangup = mxser_hangup,
+ .break_ctl = mxser_rs_break,
+ .wait_until_sent = mxser_wait_until_sent,
+ .tiocmget = mxser_tiocmget,
+ .tiocmset = mxser_tiocmset,
+};
+
+/*
+ * The MOXA Smartio/Industio serial driver boot-time initialization code!
+ */
+
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+ unsigned int irq)
+{
+ if (irq)
+ free_irq(brd->irq, brd);
+ if (pdev != NULL) { /* PCI */
+#ifdef CONFIG_PCI
+ pci_release_region(pdev, 2);
+ pci_release_region(pdev, 3);
+#endif
+ } else {
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+ release_region(brd->vector, 1);
+ }
+}
+
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+ struct pci_dev *pdev)
+{
+ struct mxser_port *info;
+ unsigned int i;
+ int retval;
+
+ printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
+
+ for (i = 0; i < brd->info->nports; i++) {
+ info = &brd->ports[i];
+ info->board = brd;
+ info->stop_rx = 0;
+ info->ldisc_stop_rx = 0;
+
+ /* Enhance mode enabled here */
+ if (brd->chip_flag != MOXA_OTHER_UART)
+ ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+
+ info->flags = ASYNC_SHARE_IRQ;
+ info->type = brd->uart_type;
+
+ process_txrx_fifo(info);
+
+ info->custom_divisor = info->baud_base * 16;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = 30 * HZ;
+ info->normal_termios = mxvar_sdriver->init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ info->speed = 9600;
+ memset(&info->mon_data, 0, sizeof(struct mxser_mon));
+ info->err_shadow = 0;
+ spin_lock_init(&info->slock);
+
+ /* before set INT ISR, disable all int */
+ outb(inb(info->ioaddr + UART_IER) & 0xf0,
+ info->ioaddr + UART_IER);
+ }
+
+ retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
+ brd);
+ if (retval) {
+ printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
+ "conflict with another device.\n",
+ brd->info->name, brd->irq);
+ /* We hold resources, we need to release them. */
+ mxser_release_res(brd, pdev, 0);
+ }
+ return retval;
+}
+
+static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
+{
+ int id, i, bits;
+ unsigned short regs[16], irq;
+ unsigned char scratch, scratch2;
+
+ brd->chip_flag = MOXA_OTHER_UART;
+
+ id = mxser_read_register(cap, regs);
+ switch (id) {
+ case C168_ASIC_ID:
+ brd->info = &mxser_cards[0];
+ break;
+ case C104_ASIC_ID:
+ brd->info = &mxser_cards[1];
+ break;
+ case CI104J_ASIC_ID:
+ brd->info = &mxser_cards[2];
+ break;
+ case C102_ASIC_ID:
+ brd->info = &mxser_cards[5];
+ break;
+ case CI132_ASIC_ID:
+ brd->info = &mxser_cards[6];
+ break;
+ case CI134_ASIC_ID:
+ brd->info = &mxser_cards[7];
+ break;
+ default:
+ return 0;
+ }
+
+ irq = 0;
+ /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
+ Flag-hack checks if configuration should be read as 2-port here. */
+ if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ if (irq != (regs[9] & 0xFF00))
+ return MXSER_ERR_IRQ_CONFLIT;
+ } else if (brd->info->nports == 4) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ irq = irq | (irq >> 8);
+ if (irq != regs[9])
+ return MXSER_ERR_IRQ_CONFLIT;
+ } else if (brd->info->nports == 8) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ irq = irq | (irq >> 8);
+ if ((irq != regs[9]) || (irq != regs[10]))
+ return MXSER_ERR_IRQ_CONFLIT;
+ }
+
+ if (!irq)
+ return MXSER_ERR_IRQ;
+ brd->irq = ((int)(irq & 0xF000) >> 12);
+ for (i = 0; i < 8; i++)
+ brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
+ if ((regs[12] & 0x80) == 0)
+ return MXSER_ERR_VECTOR;
+ brd->vector = (int)regs[11]; /* interrupt vector */
+ if (id == 1)
+ brd->vector_mask = 0x00FF;
+ else
+ brd->vector_mask = 0x000F;
+ for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
+ if (regs[12] & bits) {
+ brd->ports[i].baud_base = 921600;
+ brd->ports[i].max_baud = 921600;
+ } else {
+ brd->ports[i].baud_base = 115200;
+ brd->ports[i].max_baud = 115200;
+ }
+ }
+ scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
+ outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
+ outb(0, cap + UART_EFR); /* EFR is the same as FCR */
+ outb(scratch2, cap + UART_LCR);
+ outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
+ scratch = inb(cap + UART_IIR);
+
+ if (scratch & 0xC0)
+ brd->uart_type = PORT_16550A;
+ else
+ brd->uart_type = PORT_16450;
+ if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
+ "mxser(IO)"))
+ return MXSER_ERR_IOADDR;
+ if (!request_region(brd->vector, 1, "mxser(vector)")) {
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+ return MXSER_ERR_VECTOR;
+ }
+ return brd->info->nports;
+}
+
+static int __devinit mxser_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+#ifdef CONFIG_PCI
+ struct mxser_board *brd;
+ unsigned int i, j;
+ unsigned long ioaddress;
+ int retval = -EINVAL;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info == NULL)
+ break;
+
+ if (i >= MXSER_BOARDS) {
+ printk(KERN_ERR "Too many Smartio/Industio family boards found "
+ "(maximum %d), board not configured\n", MXSER_BOARDS);
+ goto err;
+ }
+
+ brd = &mxser_boards[i];
+ brd->idx = i * MXSER_PORTS_PER_BOARD;
+ printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+ mxser_cards[ent->driver_data].name,
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ goto err;
+ }
+
+ /* io address */
+ ioaddress = pci_resource_start(pdev, 2);
+ retval = pci_request_region(pdev, 2, "mxser(IO)");
+ if (retval)
+ goto err;
+
+ brd->info = &mxser_cards[ent->driver_data];
+ for (i = 0; i < brd->info->nports; i++)
+ brd->ports[i].ioaddr = ioaddress + 8 * i;
+
+ /* vector */
+ ioaddress = pci_resource_start(pdev, 3);
+ retval = pci_request_region(pdev, 3, "mxser(vector)");
+ if (retval)
+ goto err_relio;
+ brd->vector = ioaddress;
+
+ /* irq */
+ brd->irq = pdev->irq;
+
+ brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
+ brd->uart_type = PORT_16550A;
+ brd->vector_mask = 0;
+
+ for (i = 0; i < brd->info->nports; i++) {
+ for (j = 0; j < UART_INFO_NUM; j++) {
+ if (Gpci_uart_info[j].type == brd->chip_flag) {
+ brd->ports[i].max_baud =
+ Gpci_uart_info[j].max_baud;
+
+ /* exception....CP-102 */
+ if (brd->info->flags & MXSER_HIGHBAUD)
+ brd->ports[i].max_baud = 921600;
+ break;
+ }
+ }
+ }
+
+ if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
+ for (i = 0; i < brd->info->nports; i++) {
+ if (i < 4)
+ brd->ports[i].opmode_ioaddr = ioaddress + 4;
+ else
+ brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
+ }
+ outb(0, ioaddress + 4); /* default set to RS232 mode */
+ outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
+ }
+
+ for (i = 0; i < brd->info->nports; i++) {
+ brd->vector_mask |= (1 << i);
+ brd->ports[i].baud_base = 921600;
+ }
+
+ /* mxser_initbrd will hook ISR. */
+ retval = mxser_initbrd(brd, pdev);
+ if (retval)
+ goto err_null;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+ pci_set_drvdata(pdev, brd);
+
+ return 0;
+err_relio:
+ pci_release_region(pdev, 2);
+err_null:
+ brd->info = NULL;
+err:
+ return retval;
+#else
+ return -ENODEV;
+#endif
+}
+
+static void __devexit mxser_remove(struct pci_dev *pdev)
+{
+ struct mxser_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_unregister_device(mxvar_sdriver, brd->idx + i);
+
+ mxser_release_res(brd, pdev, 1);
+ brd->info = NULL;
+}
+
+static struct pci_driver mxser_driver = {
+ .name = "mxser",
+ .id_table = mxser_pcibrds,
+ .probe = mxser_probe,
+ .remove = __devexit_p(mxser_remove)
+};
+
+static int __init mxser_module_init(void)
+{
+ struct mxser_board *brd;
+ unsigned long cap;
+ unsigned int i, m, isaloop;
+ int retval, b;
+
+ pr_debug("Loading module mxser ...\n");
+
+ mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
+ if (!mxvar_sdriver)
+ return -ENOMEM;
+
+ printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+ MXSER_VERSION);
+
+ /* Initialize the tty_driver structure */
+ mxvar_sdriver->owner = THIS_MODULE;
+ mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
+ mxvar_sdriver->name = "ttyMI";
+ mxvar_sdriver->major = ttymajor;
+ mxvar_sdriver->minor_start = 0;
+ mxvar_sdriver->num = MXSER_PORTS + 1;
+ mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
+ mxvar_sdriver->init_termios = tty_std_termios;
+ mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(mxvar_sdriver, &mxser_ops);
+
+ retval = tty_register_driver(mxvar_sdriver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
+ "tty driver !\n");
+ goto err_put;
+ }
+
+ mxvar_diagflag = 0;
+
+ m = 0;
+ /* Start finding ISA boards here */
+ for (isaloop = 0; isaloop < 2; isaloop++)
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ if (!isaloop)
+ cap = mxserBoardCAP[b]; /* predefined */
+ else
+ cap = ioaddr[b]; /* module param */
+
+ if (!cap)
+ continue;
+
+ brd = &mxser_boards[m];
+ retval = mxser_get_ISA_conf(cap, brd);
+
+ if (retval != 0)
+ printk(KERN_INFO "Found MOXA %s board "
+ "(CAP=0x%x)\n",
+ brd->info->name, ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk(KERN_ERR "Invalid interrupt "
+ "number, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk(KERN_ERR "Invalid interrupt "
+ "number, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk(KERN_ERR "Invalid interrupt "
+ "vector, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
+
+ brd->info = NULL;
+ continue;
+ }
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
+ continue;
+ }
+
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i,
+ NULL);
+
+ m++;
+ }
+
+ retval = pci_register_driver(&mxser_driver);
+ if (retval) {
+ printk(KERN_ERR "Can't register pci driver\n");
+ if (!m) {
+ retval = -ENODEV;
+ goto err_unr;
+ } /* else: we have some ISA cards under control */
+ }
+
+ pr_debug("Done.\n");
+
+ return 0;
+err_unr:
+ tty_unregister_driver(mxvar_sdriver);
+err_put:
+ put_tty_driver(mxvar_sdriver);
+ return retval;
+}
+
+static void __exit mxser_module_exit(void)
+{
+ unsigned int i, j;
+
+ pr_debug("Unloading module mxser ...\n");
+
+ pci_unregister_driver(&mxser_driver);
+
+ for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+ if (mxser_boards[i].info != NULL)
+ for (j = 0; j < mxser_boards[i].info->nports; j++)
+ tty_unregister_device(mxvar_sdriver,
+ mxser_boards[i].idx + j);
+ tty_unregister_driver(mxvar_sdriver);
+ put_tty_driver(mxvar_sdriver);
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info != NULL)
+ mxser_release_res(&mxser_boards[i], NULL, 1);
+
+ pr_debug("Done.\n");
+}
+
+module_init(mxser_module_init);
+module_exit(mxser_module_exit);
diff --git a/trunk/drivers/char/mxser_new.h b/trunk/drivers/char/mxser_new.h
new file mode 100644
index 000000000000..d42f7766c652
--- /dev/null
+++ b/trunk/drivers/char/mxser_new.h
@@ -0,0 +1,293 @@
+#ifndef _MXSER_H
+#define _MXSER_H
+
+/*
+ * Semi-public control interfaces
+ */
+
+/*
+ * MOXA ioctls
+ */
+
+#define MOXA 0x400
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_CONF (MOXA + 35)
+#define MOXA_DIAGNOSE (MOXA + 50)
+#define MOXA_CHKPORTENABLE (MOXA + 60)
+#define MOXA_HighSpeedOn (MOXA + 61)
+#define MOXA_GET_MAJOR (MOXA + 63)
+#define MOXA_GET_CUMAJOR (MOXA + 64)
+#define MOXA_GETMSTATUS (MOXA + 65)
+#define MOXA_SET_OP_MODE (MOXA + 66)
+#define MOXA_GET_OP_MODE (MOXA + 67)
+
+#define RS232_MODE 0
+#define RS485_2WIRE_MODE 1
+#define RS422_MODE 2
+#define RS485_4WIRE_MODE 3
+#define OP_MODE_MASK 3
+
+#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
+#define MOXA_ASPP_OQUEUE (MOXA + 70)
+#define MOXA_ASPP_SETBAUD (MOXA + 71)
+#define MOXA_ASPP_GETBAUD (MOXA + 72)
+#define MOXA_ASPP_MON (MOXA + 73)
+#define MOXA_ASPP_LSTATUS (MOXA + 74)
+#define MOXA_ASPP_MON_EXT (MOXA + 75)
+#define MOXA_SET_BAUD_METHOD (MOXA + 76)
+#define MOXA_SET_SPECIAL_BAUD_RATE (MOXA + 77)
+#define MOXA_GET_SPECIAL_BAUD_RATE (MOXA + 78)
+
+/* --------------------------------------------------- */
+
+#define NPPI_NOTIFY_PARITY 0x01
+#define NPPI_NOTIFY_FRAMING 0x02
+#define NPPI_NOTIFY_HW_OVERRUN 0x04
+#define NPPI_NOTIFY_SW_OVERRUN 0x08
+#define NPPI_NOTIFY_BREAK 0x10
+
+#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */
+#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */
+#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */
+#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */
+
+/* follow just for Moxa Must chip define. */
+/* */
+/* when LCR register (offset 0x03) write following value, */
+/* the Must chip will enter enchance mode. And write value */
+/* on EFR (offset 0x02) bit 6,7 to change bank. */
+#define MOXA_MUST_ENTER_ENCHANCE 0xBF
+
+/* when enhance mode enable, access on general bank register */
+#define MOXA_MUST_GDL_REGISTER 0x07
+#define MOXA_MUST_GDL_MASK 0x7F
+#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
+
+#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */
+/* enchance register bank select and enchance mode setting register */
+/* when LCR register equal to 0xBF */
+#define MOXA_MUST_EFR_REGISTER 0x02
+/* enchance mode enable */
+#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
+/* enchance reister bank set 0, 1, 2 */
+#define MOXA_MUST_EFR_BANK0 0x00
+#define MOXA_MUST_EFR_BANK1 0x40
+#define MOXA_MUST_EFR_BANK2 0x80
+#define MOXA_MUST_EFR_BANK3 0xC0
+#define MOXA_MUST_EFR_BANK_MASK 0xC0
+
+/* set XON1 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XON1_REGISTER 0x04
+
+/* set XON2 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XON2_REGISTER 0x05
+
+/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XOFF1_REGISTER 0x06
+
+/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XOFF2_REGISTER 0x07
+
+#define MOXA_MUST_RBRTL_REGISTER 0x04
+#define MOXA_MUST_RBRTH_REGISTER 0x05
+#define MOXA_MUST_RBRTI_REGISTER 0x06
+#define MOXA_MUST_THRTL_REGISTER 0x07
+#define MOXA_MUST_ENUM_REGISTER 0x04
+#define MOXA_MUST_HWID_REGISTER 0x05
+#define MOXA_MUST_ECR_REGISTER 0x06
+#define MOXA_MUST_CSR_REGISTER 0x07
+
+/* good data mode enable */
+#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
+/* only good data put into RxFIFO */
+#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
+
+/* enable CTS interrupt */
+#define MOXA_MUST_IER_ECTSI 0x80
+/* enable RTS interrupt */
+#define MOXA_MUST_IER_ERTSI 0x40
+/* enable Xon/Xoff interrupt */
+#define MOXA_MUST_IER_XINT 0x20
+/* enable GDA interrupt */
+#define MOXA_MUST_IER_EGDAI 0x10
+
+#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
+
+/* GDA interrupt pending */
+#define MOXA_MUST_IIR_GDA 0x1C
+#define MOXA_MUST_IIR_RDA 0x04
+#define MOXA_MUST_IIR_RTO 0x0C
+#define MOXA_MUST_IIR_LSR 0x06
+
+/* recieved Xon/Xoff or specical interrupt pending */
+#define MOXA_MUST_IIR_XSC 0x10
+
+/* RTS/CTS change state interrupt pending */
+#define MOXA_MUST_IIR_RTSCTS 0x20
+#define MOXA_MUST_IIR_MASK 0x3E
+
+#define MOXA_MUST_MCR_XON_FLAG 0x40
+#define MOXA_MUST_MCR_XON_ANY 0x80
+#define MOXA_MUST_MCR_TX_XON 0x08
+
+/* software flow control on chip mask value */
+#define MOXA_MUST_EFR_SF_MASK 0x0F
+/* send Xon1/Xoff1 */
+#define MOXA_MUST_EFR_SF_TX1 0x08
+/* send Xon2/Xoff2 */
+#define MOXA_MUST_EFR_SF_TX2 0x04
+/* send Xon1,Xon2/Xoff1,Xoff2 */
+#define MOXA_MUST_EFR_SF_TX12 0x0C
+/* don't send Xon/Xoff */
+#define MOXA_MUST_EFR_SF_TX_NO 0x00
+/* Tx software flow control mask */
+#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
+/* don't receive Xon/Xoff */
+#define MOXA_MUST_EFR_SF_RX_NO 0x00
+/* receive Xon1/Xoff1 */
+#define MOXA_MUST_EFR_SF_RX1 0x02
+/* receive Xon2/Xoff2 */
+#define MOXA_MUST_EFR_SF_RX2 0x01
+/* receive Xon1,Xon2/Xoff1,Xoff2 */
+#define MOXA_MUST_EFR_SF_RX12 0x03
+/* Rx software flow control mask */
+#define MOXA_MUST_EFR_SF_RX_MASK 0x03
+
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_FIFO_VALUE(info) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((info)->ioaddr+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
+ __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)((info)->rx_high_water), (info)->ioaddr+ \
+ MOXA_MUST_RBRTH_REGISTER); \
+ outb((u8)((info)->rx_trigger), (info)->ioaddr+ \
+ MOXA_MUST_RBRTI_REGISTER); \
+ outb((u8)((info)->rx_low_water), (info)->ioaddr+ \
+ MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (info)->ioaddr+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#endif
diff --git a/trunk/drivers/char/riscom8.c b/trunk/drivers/char/riscom8.c
index 8fc4fe4e38f1..d130b87d8ed7 100644
--- a/trunk/drivers/char/riscom8.c
+++ b/trunk/drivers/char/riscom8.c
@@ -78,6 +78,8 @@
ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \
ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
+#define RS_EVENT_WRITE_WAKEUP 0
+
static struct tty_driver *riscom_driver;
static DEFINE_SPINLOCK(riscom_lock);
@@ -312,6 +314,12 @@ static int __init rc_probe(struct riscom_board *bp)
*
*/
+static inline void rc_mark_event(struct riscom_port * port, int event)
+{
+ set_bit(event, &port->event);
+ schedule_work(&port->tqueue);
+}
+
static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
unsigned char const * what)
{
@@ -478,7 +486,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
rc_out(bp, CD180_IER, port->IER);
}
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
}
static inline void rc_check_modem(struct riscom_board const * bp)
@@ -497,7 +505,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
if (rc_in(bp, CD180_MSVR) & MSVR_CD)
wake_up_interruptible(&port->open_wait);
else
- tty_hangup(tty);
+ schedule_work(&port->tqueue_hangup);
}
#ifdef RISCOM_BRAIN_DAMAGED_CTS
@@ -506,7 +514,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
tty->hw_stopped = 0;
port->IER |= IER_TXRDY;
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
} else {
tty->hw_stopped = 1;
port->IER &= ~IER_TXRDY;
@@ -518,7 +526,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
tty->hw_stopped = 0;
port->IER |= IER_TXRDY;
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
} else {
tty->hw_stopped = 1;
port->IER &= ~IER_TXRDY;
@@ -1083,6 +1091,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
tty_ldisc_flush(tty);
tty->closing = 0;
+ port->event = 0;
port->tty = NULL;
if (port->blocked_open) {
if (port->close_delay) {
@@ -1517,6 +1526,25 @@ static void rc_start(struct tty_struct * tty)
spin_unlock_irqrestore(&riscom_lock, flags);
}
+/*
+ * This routine is called from the work queue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (workqueue) ->
+ * do_rc_hangup() -> tty->hangup() -> rc_hangup()
+ *
+ */
+static void do_rc_hangup(struct work_struct *ugly_api)
+{
+ struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue_hangup);
+ struct tty_struct *tty;
+
+ tty = port->tty;
+ if (tty)
+ tty_hangup(tty); /* FIXME: module removal race still here */
+}
+
static void rc_hangup(struct tty_struct * tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
@@ -1528,6 +1556,7 @@ static void rc_hangup(struct tty_struct * tty)
bp = port_Board(port);
rc_shutdown_port(bp, port);
+ port->event = 0;
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
port->tty = NULL;
@@ -1557,6 +1586,18 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio
}
}
+static void do_softint(struct work_struct *ugly_api)
+{
+ struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue);
+ struct tty_struct *tty;
+
+ if(!(tty = port->tty))
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
+ tty_wakeup(tty);
+}
+
static const struct tty_operations riscom_ops = {
.open = rc_open,
.close = rc_close,
@@ -1577,7 +1618,7 @@ static const struct tty_operations riscom_ops = {
.tiocmset = rc_tiocmset,
};
-static int __init rc_init_drivers(void)
+static inline int rc_init_drivers(void)
{
int error;
int i;
@@ -1609,6 +1650,8 @@ static int __init rc_init_drivers(void)
memset(rc_port, 0, sizeof(rc_port));
for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
rc_port[i].magic = RISCOM8_MAGIC;
+ INIT_WORK(&rc_port[i].tqueue, do_softint);
+ INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup);
rc_port[i].close_delay = 50 * HZ/100;
rc_port[i].closing_wait = 3000 * HZ/100;
init_waitqueue_head(&rc_port[i].open_wait);
diff --git a/trunk/drivers/char/riscom8.h b/trunk/drivers/char/riscom8.h
index cdfdf4394477..9cc1313d5e67 100644
--- a/trunk/drivers/char/riscom8.h
+++ b/trunk/drivers/char/riscom8.h
@@ -71,6 +71,7 @@ struct riscom_port {
struct tty_struct * tty;
int count;
int blocked_open;
+ unsigned long event; /* long req'd for set_bit --RR */
int timeout;
int close_delay;
unsigned char * xmit_buf;
@@ -80,6 +81,8 @@ struct riscom_port {
int xmit_cnt;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
+ struct work_struct tqueue;
+ struct work_struct tqueue_hangup;
short wakeup_chars;
short break_length;
unsigned short closing_wait;
diff --git a/trunk/drivers/char/rocket.c b/trunk/drivers/char/rocket.c
index 68c289fe2dc2..d83419c3857e 100644
--- a/trunk/drivers/char/rocket.c
+++ b/trunk/drivers/char/rocket.c
@@ -40,6 +40,12 @@
*/
/****** Defines ******/
+#ifdef PCI_NUM_RESOURCES
+#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
+#else
+#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r])
+#endif
+
#define ROCKET_PARANOIA_CHECK
#define ROCKET_DISABLE_SIMUSAGE
@@ -299,8 +305,8 @@ static inline int rocket_paranoia_check(struct r_port *info,
if (!info)
return 1;
if (info->magic != RPORT_MAGIC) {
- printk(KERN_WARNING "Warning: bad magic number for rocketport "
- "struct in %s\n", routine);
+ printk(KERN_INFO "Warning: bad magic number for rocketport struct in %s\n",
+ routine);
return 1;
}
#endif
@@ -322,7 +328,7 @@ static void rp_do_receive(struct r_port *info,
ToRecv = sGetRxCnt(cp);
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
+ printk(KERN_INFO "rp_do_receive(%d)...", ToRecv);
#endif
if (ToRecv == 0)
return;
@@ -335,7 +341,7 @@ static void rp_do_receive(struct r_port *info,
if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
if (!(ChanStatus & STATMODE)) {
#ifdef ROCKET_DEBUG_RECEIVE
- printk(KERN_INFO "Entering STATMODE...\n");
+ printk(KERN_INFO "Entering STATMODE...");
#endif
ChanStatus |= STATMODE;
sEnRxStatusMode(cp);
@@ -349,15 +355,15 @@ static void rp_do_receive(struct r_port *info,
*/
if (ChanStatus & STATMODE) {
#ifdef ROCKET_DEBUG_RECEIVE
- printk(KERN_INFO "Ignore %x, read %x...\n",
- info->ignore_status_mask, info->read_status_mask);
+ printk(KERN_INFO "Ignore %x, read %x...", info->ignore_status_mask,
+ info->read_status_mask);
#endif
while (ToRecv) {
char flag;
CharNStat = sInW(sGetTxRxDataIO(cp));
#ifdef ROCKET_DEBUG_RECEIVE
- printk(KERN_INFO "%x...\n", CharNStat);
+ printk(KERN_INFO "%x...", CharNStat);
#endif
if (CharNStat & STMBREAKH)
CharNStat &= ~(STMFRAMEH | STMPARITYH);
@@ -429,13 +435,12 @@ static void rp_do_transmit(struct r_port *info)
unsigned long flags;
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_DEBUG "%s\n", __func__);
+ printk(KERN_INFO "rp_do_transmit ");
#endif
if (!info)
return;
if (!info->tty) {
- printk(KERN_WARNING "rp: WARNING %s called with "
- "info->tty==NULL\n", __func__);
+ printk(KERN_INFO "rp: WARNING rp_do_transmit called with info->tty==NULL\n");
clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
return;
}
@@ -459,7 +464,7 @@ static void rp_do_transmit(struct r_port *info)
info->xmit_cnt -= c;
info->xmit_fifo_room -= c;
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_INFO "tx %d chars...\n", c);
+ printk(KERN_INFO "tx %d chars...", c);
#endif
}
@@ -476,7 +481,7 @@ static void rp_do_transmit(struct r_port *info)
spin_unlock_irqrestore(&info->slock, flags);
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
+ printk(KERN_INFO "(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,
info->xmit_tail, info->xmit_fifo_room);
#endif
}
@@ -496,13 +501,11 @@ static void rp_handle_port(struct r_port *info)
return;
if ((info->flags & ROCKET_INITIALIZED) == 0) {
- printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
- "info->flags & NOT_INIT\n");
+ printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n");
return;
}
if (!info->tty) {
- printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
- "info->tty==NULL\n");
+ printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->tty==NULL\n");
return;
}
cp = &info->channel;
@@ -510,7 +513,7 @@ static void rp_handle_port(struct r_port *info)
IntMask = sGetChanIntID(cp) & info->intmask;
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
+ printk(KERN_INFO "rp_interrupt %02x...", IntMask);
#endif
ChanStatus = sGetChanStatus(cp);
if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
@@ -518,7 +521,7 @@ static void rp_handle_port(struct r_port *info)
}
if (IntMask & DELTA_CD) { /* CD change */
#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
- printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
+ printk(KERN_INFO "ttyR%d CD now %s...", info->line,
(ChanStatus & CD_ACT) ? "on" : "off");
#endif
if (!(ChanStatus & CD_ACT) && info->cd_status) {
@@ -635,8 +638,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
/* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
if (!info) {
- printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
- line);
+ printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);
return;
}
@@ -666,8 +668,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
- printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
- board, aiop, chan);
+ printk(KERN_INFO "RocketPort sInitChan(%d, %d, %d) failed!\n", board, aiop, chan);
kfree(info);
return;
}
@@ -975,7 +976,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
CHANNEL_t *cp;
unsigned long page;
- line = tty->index;
+ line = TTY_GET_LINE(tty);
if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
return -ENXIO;
@@ -1006,8 +1007,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
atomic_inc(&rp_num_ports_open);
#ifdef ROCKET_DEBUG_OPEN
- printk(KERN_INFO "rocket mod++ = %d...\n",
- atomic_read(&rp_num_ports_open));
+ printk(KERN_INFO "rocket mod++ = %d...", atomic_read(&rp_num_ports_open));
#endif
}
#ifdef ROCKET_DEBUG_OPEN
@@ -1103,13 +1103,13 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk(KERN_WARNING "rp_close: bad serial port count; "
- "tty->count is 1, info->count is %d\n", info->count);
+ printk(KERN_INFO "rp_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
- printk(KERN_WARNING "rp_close: bad serial port count for "
- "ttyR%d: %d\n", info->line, info->count);
+ printk(KERN_INFO "rp_close: bad serial port count for ttyR%d: %d\n",
+ info->line, info->count);
info->count = 0;
}
if (info->count) {
@@ -1160,7 +1160,8 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
if (C_HUPCL(tty))
sClrDTR(cp);
- rp_flush_buffer(tty);
+ if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty))
+ TTY_DRIVER_FLUSH_BUFFER(tty);
tty_ldisc_flush(tty);
@@ -1183,8 +1184,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
atomic_dec(&rp_num_ports_open);
#ifdef ROCKET_DEBUG_OPEN
- printk(KERN_INFO "rocket mod-- = %d...\n",
- atomic_read(&rp_num_ports_open));
+ printk(KERN_INFO "rocket mod-- = %d...", atomic_read(&rp_num_ports_open));
printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
#endif
@@ -1569,9 +1569,9 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
orig_jiffies = jiffies;
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
- printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
+ printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...", timeout,
jiffies);
- printk(KERN_INFO "cps=%d...\n", info->cps);
+ printk(KERN_INFO "cps=%d...", info->cps);
#endif
while (1) {
txcnt = sGetTxCnt(cp);
@@ -1592,8 +1592,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
if (check_time == 0)
check_time = 1;
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
- printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
- jiffies, check_time);
+ printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time);
#endif
msleep_interruptible(jiffies_to_msecs(check_time));
if (signal_pending(current))
@@ -1617,7 +1616,7 @@ static void rp_hangup(struct tty_struct *tty)
return;
#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
- printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
+ printk(KERN_INFO "rp_hangup of ttyR%d...", info->line);
#endif
rp_flush_buffer(tty);
if (info->flags & ROCKET_CLOSING)
@@ -1665,7 +1664,7 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
mutex_lock(&info->write_mtx);
#ifdef ROCKET_DEBUG_WRITE
- printk(KERN_INFO "rp_put_char %c...\n", ch);
+ printk(KERN_INFO "rp_put_char %c...", ch);
#endif
spin_lock_irqsave(&info->slock, flags);
@@ -1710,7 +1709,7 @@ static int rp_write(struct tty_struct *tty,
return -ERESTARTSYS;
#ifdef ROCKET_DEBUG_WRITE
- printk(KERN_INFO "rp_write %d chars...\n", count);
+ printk(KERN_INFO "rp_write %d chars...", count);
#endif
cp = &info->channel;
@@ -1799,7 +1798,7 @@ static int rp_write_room(struct tty_struct *tty)
if (ret < 0)
ret = 0;
#ifdef ROCKET_DEBUG_WRITE
- printk(KERN_INFO "rp_write_room returns %d...\n", ret);
+ printk(KERN_INFO "rp_write_room returns %d...", ret);
#endif
return ret;
}
@@ -1819,7 +1818,7 @@ static int rp_chars_in_buffer(struct tty_struct *tty)
cp = &info->channel;
#ifdef ROCKET_DEBUG_WRITE
- printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
+ printk(KERN_INFO "rp_chars_in_buffer returns %d...", info->xmit_cnt);
#endif
return info->xmit_cnt;
}
@@ -2162,11 +2161,14 @@ static __init int register_PCI(int i, struct pci_dev *dev)
for (aiop = 0; aiop < max_num_aiops; aiop++)
ctlp->AiopNumChan[aiop] = ports_per_aiop;
- dev_info(&dev->dev, "comtrol PCI controller #%d found at "
- "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
- i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
- rocketModel[i].startingPortNumber,
- rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
+ printk("Comtrol PCI controller #%d ID 0x%x found in bus:slot:fn %s at address %04lx, "
+ "%d AIOP(s) (%s)\n", i, dev->device, pci_name(dev),
+ rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString);
+ printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
+ rocketModel[i].modelString,
+ rocketModel[i].startingPortNumber,
+ rocketModel[i].startingPortNumber +
+ rocketModel[i].numPorts - 1);
if (num_aiops <= 0) {
rcktpt_io_addr[i] = 0;
@@ -2189,10 +2191,10 @@ static __init int register_PCI(int i, struct pci_dev *dev)
num_chan = ports_per_aiop;
for (chan = 0; chan < num_chan; chan++)
sPCIModemReset(ctlp, chan, 1);
- msleep(500);
+ mdelay(500);
for (chan = 0; chan < num_chan; chan++)
sPCIModemReset(ctlp, chan, 0);
- msleep(500);
+ mdelay(500);
rmSpeakerReset(ctlp, rocketModel[i].model);
}
return (1);
@@ -2238,9 +2240,7 @@ static int __init init_ISA(int i)
/* Reserve the IO region */
if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
- printk(KERN_ERR "Unable to reserve IO region for configured "
- "ISA RocketPort at address 0x%lx, board not "
- "installed...\n", rcktpt_io_addr[i]);
+ printk(KERN_INFO "Unable to reserve IO region for configured ISA RocketPort at address 0x%lx, board not installed...\n", rcktpt_io_addr[i]);
rcktpt_io_addr[i] = 0;
return (0);
}
@@ -2309,10 +2309,10 @@ static int __init init_ISA(int i)
total_num_chan = num_chan;
for (chan = 0; chan < num_chan; chan++)
sModemReset(ctlp, chan, 1);
- msleep(500);
+ mdelay(500);
for (chan = 0; chan < num_chan; chan++)
sModemReset(ctlp, chan, 0);
- msleep(500);
+ mdelay(500);
strcpy(rocketModel[i].modelString, "RocketModem ISA");
} else {
strcpy(rocketModel[i].modelString, "RocketPort ISA");
@@ -2480,7 +2480,7 @@ static void rp_cleanup_module(void)
retval = tty_unregister_driver(rocket_driver);
if (retval)
- printk(KERN_ERR "Error %d while trying to unregister "
+ printk(KERN_INFO "Error %d while trying to unregister "
"rocketport driver\n", -retval);
for (i = 0; i < MAX_RP_PORTS; i++)
diff --git a/trunk/drivers/char/rocket_int.h b/trunk/drivers/char/rocket_int.h
index f3a75791b811..55b8f2d71a96 100644
--- a/trunk/drivers/char/rocket_int.h
+++ b/trunk/drivers/char/rocket_int.h
@@ -42,7 +42,7 @@ typedef unsigned int DWordIO_t;
static inline void sOutB(unsigned short port, unsigned char value)
{
#ifdef ROCKET_DEBUG_IO
- printk(KERN_DEBUG "sOutB(%x, %x)...\n", port, value);
+ printk("sOutB(%x, %x)...", port, value);
#endif
outb_p(value, port);
}
@@ -50,7 +50,7 @@ static inline void sOutB(unsigned short port, unsigned char value)
static inline void sOutW(unsigned short port, unsigned short value)
{
#ifdef ROCKET_DEBUG_IO
- printk(KERN_DEBUG "sOutW(%x, %x)...\n", port, value);
+ printk("sOutW(%x, %x)...", port, value);
#endif
outw_p(value, port);
}
@@ -58,7 +58,7 @@ static inline void sOutW(unsigned short port, unsigned short value)
static inline void sOutDW(unsigned short port, unsigned long value)
{
#ifdef ROCKET_DEBUG_IO
- printk(KERN_DEBUG "sOutDW(%x, %lx)...\n", port, value);
+ printk("sOutDW(%x, %lx)...", port, value);
#endif
outl_p(cpu_to_le32(value), port);
}
@@ -105,6 +105,12 @@ static inline unsigned short sInW(unsigned short port)
#define AIOPID_NULL -1 /* no AIOP or channel exists */
#define AIOPID_0001 0x0001 /* AIOP release 1 */
+#define NULLDEV -1 /* identifies non-existant device */
+#define NULLCTL -1 /* identifies non-existant controller */
+#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */
+#define NULLAIOP -1 /* identifies non-existant AIOP */
+#define NULLCHAN -1 /* identifies non-existant channel */
+
/************************************************************************
Global Register Offsets - Direct Access - Fixed values
************************************************************************/
@@ -1181,6 +1187,9 @@ struct r_port {
#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */
#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */
+/* tty subtypes */
+#define SERIAL_TYPE_NORMAL 1
+
/*
* Assigned major numbers for the Comtrol Rocketport
*/
@@ -1231,3 +1240,12 @@ struct r_port {
/* Compact PCI device */
#define PCI_DEVICE_ID_CRP16INTF 0x0903 /* Rocketport Compact PCI 16 port w/external I/F */
+#define TTY_GET_LINE(t) t->index
+#define TTY_DRIVER_MINOR_START(t) t->driver->minor_start
+#define TTY_DRIVER_SUBTYPE(t) t->driver->subtype
+#define TTY_DRIVER_NAME(t) t->driver->name
+#define TTY_DRIVER_NAME_BASE(t) t->driver->name_base
+#define TTY_DRIVER_FLUSH_BUFFER_EXISTS(t) t->driver->flush_buffer
+#define TTY_DRIVER_FLUSH_BUFFER(t) t->driver->flush_buffer(t)
+
+
diff --git a/trunk/drivers/char/serial167.c b/trunk/drivers/char/serial167.c
index df8cd0ca97eb..f1497cecffd8 100644
--- a/trunk/drivers/char/serial167.c
+++ b/trunk/drivers/char/serial167.c
@@ -90,6 +90,8 @@
#define STD_COM_FLAGS (0)
+#define SERIAL_TYPE_NORMAL 1
+
static struct tty_driver *cy_serial_driver;
extern int serial_console;
static struct cyclades_port *serial_console_info = NULL;
@@ -357,6 +359,18 @@ static void cy_start(struct tty_struct *tty)
local_irq_restore(flags);
} /* cy_start */
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver
+ * (also known as the "bottom half"). This can be called any
+ * number of times for any channel without harm.
+ */
+static inline void cy_sched_event(struct cyclades_port *info, int event)
+{
+ info->event |= 1 << event; /* remember what kind of event and who */
+ schedule_work(&info->tqueue);
+} /* cy_sched_event */
+
/* The real interrupt service routines are called
whenever the card wants its hand held--chars
received, out buffer empty, modem change, etc.
@@ -471,12 +485,10 @@ static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
&& (info->flags & ASYNC_CHECK_CD)) {
if (mdm_status & CyDCD) {
/* CP('!'); */
- wake_up_interruptible(&info->open_wait);
+ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
} else {
/* CP('@'); */
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ cy_sched_event(info, Cy_EVENT_HANGUP);
}
}
if ((mdm_change & CyCTS)
@@ -486,7 +498,8 @@ static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
/* !!! cy_start isn't used because... */
info->tty->stopped = 0;
base_addr[CyIER] |= CyTxMpty;
- tty_wakeup(info->tty);
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
}
} else {
if (!(mdm_status & CyCTS)) {
@@ -532,6 +545,9 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
info->last_active = jiffies;
if (info->tty == 0) {
base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
base_addr[CyTEOIR] = CyNOTRANS;
return IRQ_HANDLED;
}
@@ -613,9 +629,9 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
}
}
- if (info->xmit_cnt < WAKEUP_CHARS)
- tty_wakeup(info->tty);
-
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
return IRQ_HANDLED;
} /* cy_tx_interrupt */
@@ -676,6 +692,49 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
} /* cy_rx_interrupt */
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using cy_sched_event(), and they get done here.
+ *
+ * This is done through one level of indirection--the task queue.
+ * When a hardware interrupt service routine wants service by the
+ * driver's bottom half, it enqueues the appropriate tq_struct (one
+ * per port) to the keventd work queue and sets a request flag
+ * that the work queue be processed.
+ *
+ * Although this may seem unwieldy, it gives the system a way to
+ * pass an argument (in this case the pointer to the cyclades_port
+ * structure) to the bottom half of the driver. Previous kernels
+ * had to poll every port to see if that port needed servicing.
+ */
+static void do_softint(struct work_struct *ugly_api)
+{
+ struct cyclades_port *info =
+ container_of(ugly_api, struct cyclades_port, tqueue);
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ }
+ if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->open_wait);
+ }
+ if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+ tty_wakeup(tty);
+ }
+} /* do_softint */
+
/* This is called whenever a port becomes active;
interrupts are enabled and DTR & RTS are turned on.
*/
@@ -1686,6 +1745,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
+ info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
if (info->close_delay) {
@@ -2176,6 +2236,7 @@ static int __init serial167_init(void)
info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
info->close_delay = 0;
info->x_char = 0;
+ info->event = 0;
info->count = 0;
#ifdef SERIAL_DEBUG_COUNT
printk("cyc: %d: setting count to 0\n",
@@ -2184,6 +2245,7 @@ static int __init serial167_init(void)
info->blocked_open = 0;
info->default_threshold = 0;
info->default_timeout = 0;
+ INIT_WORK(&info->tqueue, do_softint);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
/* info->session */
diff --git a/trunk/drivers/char/specialix.c b/trunk/drivers/char/specialix.c
index c0e08c7bca2f..455855631aef 100644
--- a/trunk/drivers/char/specialix.c
+++ b/trunk/drivers/char/specialix.c
@@ -178,6 +178,9 @@ static int sx_poll = HZ;
ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \
ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
+#undef RS_EVENT_WRITE_WAKEUP
+#define RS_EVENT_WRITE_WAKEUP 0
+
static struct tty_driver *specialix_driver;
static struct specialix_board sx_board[SX_NBOARD] = {
@@ -599,6 +602,17 @@ static int sx_probe(struct specialix_board *bp)
* Interrupt processing routines.
* */
+static inline void sx_mark_event(struct specialix_port * port, int event)
+{
+ func_enter();
+
+ set_bit(event, &port->event);
+ schedule_work(&port->tqueue);
+
+ func_exit();
+}
+
+
static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
unsigned char const * what)
{
@@ -795,7 +809,7 @@ static inline void sx_transmit(struct specialix_board * bp)
sx_out(bp, CD186x_IER, port->IER);
}
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
func_exit();
}
@@ -825,7 +839,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
wake_up_interruptible(&port->open_wait);
} else {
dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
- tty_hangup(tty);
+ schedule_work(&port->tqueue_hangup);
}
}
@@ -835,7 +849,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
tty->hw_stopped = 0;
port->IER |= IER_TXRDY;
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
} else {
tty->hw_stopped = 1;
port->IER &= ~IER_TXRDY;
@@ -847,7 +861,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
tty->hw_stopped = 0;
port->IER |= IER_TXRDY;
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
} else {
tty->hw_stopped = 1;
port->IER &= ~IER_TXRDY;
@@ -1604,6 +1618,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
tty_ldisc_flush(tty);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
+ port->event = 0;
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
if (port->blocked_open) {
@@ -2220,6 +2235,32 @@ static void sx_start(struct tty_struct * tty)
func_exit();
}
+
+/*
+ * This routine is called from the work-queue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (workqueue) ->
+ * do_sx_hangup() -> tty->hangup() -> sx_hangup()
+ *
+ */
+static void do_sx_hangup(struct work_struct *work)
+{
+ struct specialix_port *port =
+ container_of(work, struct specialix_port, tqueue_hangup);
+ struct tty_struct *tty;
+
+ func_enter();
+
+ tty = port->tty;
+ if (tty)
+ tty_hangup(tty); /* FIXME: module removal race here */
+
+ func_exit();
+}
+
+
static void sx_hangup(struct tty_struct * tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
@@ -2237,6 +2278,7 @@ static void sx_hangup(struct tty_struct * tty)
sx_shutdown_port(bp, port);
spin_lock_irqsave(&port->lock, flags);
+ port->event = 0;
bp->count -= port->count;
if (bp->count < 0) {
printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
@@ -2278,6 +2320,26 @@ static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termio
}
}
+
+static void do_softint(struct work_struct *work)
+{
+ struct specialix_port *port =
+ container_of(work, struct specialix_port, tqueue);
+ struct tty_struct *tty;
+
+ func_enter();
+
+ if(!(tty = port->tty)) {
+ func_exit();
+ return;
+ }
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
+ tty_wakeup(tty);
+
+ func_exit();
+}
+
static const struct tty_operations sx_ops = {
.open = sx_open,
.close = sx_close,
@@ -2335,6 +2397,8 @@ static int sx_init_drivers(void)
memset(sx_port, 0, sizeof(sx_port));
for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
sx_port[i].magic = SPECIALIX_MAGIC;
+ INIT_WORK(&sx_port[i].tqueue, do_softint);
+ INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup);
sx_port[i].close_delay = 50 * HZ/100;
sx_port[i].closing_wait = 3000 * HZ/100;
init_waitqueue_head(&sx_port[i].open_wait);
diff --git a/trunk/drivers/char/specialix_io8.h b/trunk/drivers/char/specialix_io8.h
index 3f2f85bdf516..895bd90de363 100644
--- a/trunk/drivers/char/specialix_io8.h
+++ b/trunk/drivers/char/specialix_io8.h
@@ -112,6 +112,7 @@ struct specialix_port {
struct tty_struct * tty;
int count;
int blocked_open;
+ ulong event;
int timeout;
int close_delay;
unsigned char * xmit_buf;
@@ -121,6 +122,8 @@ struct specialix_port {
int xmit_cnt;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
+ struct work_struct tqueue;
+ struct work_struct tqueue_hangup;
short wakeup_chars;
short break_length;
unsigned short closing_wait;
diff --git a/trunk/drivers/char/stallion.c b/trunk/drivers/char/stallion.c
index feac54e32a12..45758d5b56ef 100644
--- a/trunk/drivers/char/stallion.c
+++ b/trunk/drivers/char/stallion.c
@@ -145,7 +145,8 @@ static struct stlbrd *stl_brds[STL_MAXBRDS];
*/
#define ASYI_TXBUSY 1
#define ASYI_TXLOW 2
-#define ASYI_TXFLOWED 3
+#define ASYI_DCDCHANGE 3
+#define ASYI_TXFLOWED 4
/*
* Define an array of board names as printable strings. Handy for
@@ -609,23 +610,6 @@ static const struct file_operations stl_fsiomem = {
static struct class *stallion_class;
-static void stl_cd_change(struct stlport *portp)
-{
- unsigned int oldsigs = portp->sigs;
-
- if (!portp->tty)
- return;
-
- portp->sigs = stl_getsignals(portp);
-
- if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
- wake_up_interruptible(&portp->open_wait);
-
- if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
- if (portp->flags & ASYNC_CHECK_CD)
- tty_hangup(portp->tty);
-}
-
/*
* Check for any arguments passed in on the module load command line.
*/
@@ -1786,6 +1770,41 @@ static int stl_echpci64intr(struct stlbrd *brdp)
/*****************************************************************************/
+/*
+ * Service an off-level request for some channel.
+ */
+static void stl_offintr(struct work_struct *work)
+{
+ struct stlport *portp = container_of(work, struct stlport, tqueue);
+ struct tty_struct *tty;
+ unsigned int oldsigs;
+
+ pr_debug("stl_offintr(portp=%p)\n", portp);
+
+ if (portp == NULL)
+ return;
+
+ tty = portp->tty;
+ if (tty == NULL)
+ return;
+
+ if (test_bit(ASYI_TXLOW, &portp->istate))
+ tty_wakeup(tty);
+
+ if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
+ clear_bit(ASYI_DCDCHANGE, &portp->istate);
+ oldsigs = portp->sigs;
+ portp->sigs = stl_getsignals(portp);
+ if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
+ wake_up_interruptible(&portp->open_wait);
+ if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
+ if (portp->flags & ASYNC_CHECK_CD)
+ tty_hangup(tty); /* FIXME: module removal race here - AKPM */
+ }
+}
+
+/*****************************************************************************/
+
/*
* Initialize all the ports on a panel.
*/
@@ -1821,6 +1840,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
portp->baud_base = STL_BAUDBASE;
portp->close_delay = STL_CLOSEDELAY;
portp->closing_wait = 30 * HZ;
+ INIT_WORK(&portp->tqueue, stl_offintr);
init_waitqueue_head(&portp->open_wait);
init_waitqueue_head(&portp->close_wait);
portp->stats.brd = portp->brdnr;
@@ -3510,8 +3530,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
if ((len == 0) || ((len < STL_TXBUFLOW) &&
(test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
- if (portp->tty)
- tty_wakeup(portp->tty);
+ schedule_work(&portp->tqueue);
}
if (len == 0) {
@@ -3527,8 +3546,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
} else {
len = min(len, CD1400_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = min_t(unsigned int, len,
- (portp->tx.buf + STL_TXBUFSIZE) - tail);
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb((TDR + portp->uartaddr), ioaddr);
outsb((ioaddr + EREG_DATA), tail, stlen);
len -= stlen;
@@ -3581,7 +3599,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
outb((RDCR + portp->uartaddr), ioaddr);
len = inb(ioaddr + EREG_DATA);
if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
- len = min_t(unsigned int, len, sizeof(stl_unwanted));
+ len = min(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
@@ -3674,7 +3692,8 @@ static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr)
outb((MISR + portp->uartaddr), ioaddr);
misr = inb(ioaddr + EREG_DATA);
if (misr & MISR_DCD) {
- stl_cd_change(portp);
+ set_bit(ASYI_DCDCHANGE, &portp->istate);
+ schedule_work(&portp->tqueue);
portp->stats.modem++;
}
@@ -4428,8 +4447,7 @@ static void stl_sc26198txisr(struct stlport *portp)
if ((len == 0) || ((len < STL_TXBUFLOW) &&
(test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
- if (portp->tty)
- tty_wakeup(portp->tty);
+ schedule_work(&portp->tqueue);
}
if (len == 0) {
@@ -4447,8 +4465,7 @@ static void stl_sc26198txisr(struct stlport *portp)
} else {
len = min(len, SC26198_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = min_t(unsigned int, len,
- (portp->tx.buf + STL_TXBUFSIZE) - tail);
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb(GTXFIFO, (ioaddr + XP_ADDR));
outsb((ioaddr + XP_DATA), tail, stlen);
len -= stlen;
@@ -4489,7 +4506,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
- len = min_t(unsigned int, len, sizeof(stl_unwanted));
+ len = min(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
@@ -4630,7 +4647,8 @@ static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack)
case CIR_SUBCOS:
ipr = stl_sc26198getreg(portp, IPR);
if (ipr & IPR_DCDCHANGE) {
- stl_cd_change(portp);
+ set_bit(ASYI_DCDCHANGE, &portp->istate);
+ schedule_work(&portp->tqueue);
portp->stats.modem++;
}
break;
diff --git a/trunk/drivers/char/sx.h b/trunk/drivers/char/sx.h
index 87c2defdead7..70d9783c7323 100644
--- a/trunk/drivers/char/sx.h
+++ b/trunk/drivers/char/sx.h
@@ -88,6 +88,8 @@ struct vpd_prom {
#define IS_CF_BOARD(board) (board->flags & (SX_CFISA_BOARD | SX_CFPCI_BOARD))
+#define SERIAL_TYPE_NORMAL 1
+
/* The SI processor clock is required to calculate the cc_int_count register
value for the SI cards. */
#define SI_PROCESSOR_CLOCK 25000000
diff --git a/trunk/drivers/char/xilinx_hwicap/Makefile b/trunk/drivers/char/xilinx_hwicap/Makefile
deleted file mode 100644
index 5491cbc42f43..000000000000
--- a/trunk/drivers/char/xilinx_hwicap/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Xilinx OPB hwicap driver
-#
-
-obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o
-
-xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o
diff --git a/trunk/drivers/char/xilinx_hwicap/buffer_icap.c b/trunk/drivers/char/xilinx_hwicap/buffer_icap.c
deleted file mode 100644
index dfea2bde162b..000000000000
--- a/trunk/drivers/char/xilinx_hwicap/buffer_icap.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*****************************************************************************
- *
- * Author: Xilinx, Inc.
- *
- * 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.
- *
- * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
- * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
- * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
- * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
- * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
- * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
- * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
- * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
- * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
- * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
- * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
- * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE.
- *
- * Xilinx products are not intended for use in life support appliances,
- * devices, or systems. Use in such applications is expressly prohibited.
- *
- * (c) Copyright 2003-2008 Xilinx Inc.
- * All rights reserved.
- *
- * 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.
- *
- *****************************************************************************/
-
-#include "buffer_icap.h"
-
-/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
-#define XHI_MAX_BUFFER_BYTES 2048
-#define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2)
-
-/* File access and error constants */
-#define XHI_DEVICE_READ_ERROR -1
-#define XHI_DEVICE_WRITE_ERROR -2
-#define XHI_BUFFER_OVERFLOW_ERROR -3
-
-#define XHI_DEVICE_READ 0x1
-#define XHI_DEVICE_WRITE 0x0
-
-/* Constants for checking transfer status */
-#define XHI_CYCLE_DONE 0
-#define XHI_CYCLE_EXECUTING 1
-
-/* buffer_icap register offsets */
-
-/* Size of transfer, read & write */
-#define XHI_SIZE_REG_OFFSET 0x800L
-/* offset into bram, read & write */
-#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
-/* Read not Configure, direction of transfer. Write only */
-#define XHI_RNC_REG_OFFSET 0x808L
-/* Indicates transfer complete. Read only */
-#define XHI_STATUS_REG_OFFSET 0x80CL
-
-/* Constants for setting the RNC register */
-#define XHI_CONFIGURE 0x0UL
-#define XHI_READBACK 0x1UL
-
-/* Constants for the Done register */
-#define XHI_NOT_FINISHED 0x0UL
-#define XHI_FINISHED 0x1UL
-
-#define XHI_BUFFER_START 0
-
-/**
- * buffer_icap_get_status: Get the contents of the status register.
- * @parameter base_address: is the base address of the device
- *
- * The status register contains the ICAP status and the done bit.
- *
- * D8 - cfgerr
- * D7 - dalign
- * D6 - rip
- * D5 - in_abort_l
- * D4 - Always 1
- * D3 - Always 1
- * D2 - Always 1
- * D1 - Always 1
- * D0 - Done bit
- **/
-static inline u32 buffer_icap_get_status(void __iomem *base_address)
-{
- return in_be32(base_address + XHI_STATUS_REG_OFFSET);
-}
-
-/**
- * buffer_icap_get_bram: Reads data from the storage buffer bram.
- * @parameter base_address: contains the base address of the component.
- * @parameter offset: The word offset from which the data should be read.
- *
- * A bram is used as a configuration memory cache. One frame of data can
- * be stored in this "storage buffer".
- **/
-static inline u32 buffer_icap_get_bram(void __iomem *base_address,
- u32 offset)
-{
- return in_be32(base_address + (offset << 2));
-}
-
-/**
- * buffer_icap_busy: Return true if the icap device is busy
- * @parameter base_address: is the base address of the device
- *
- * The queries the low order bit of the status register, which
- * indicates whether the current configuration or readback operation
- * has completed.
- **/
-static inline bool buffer_icap_busy(void __iomem *base_address)
-{
- return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;
-}
-
-/**
- * buffer_icap_busy: Return true if the icap device is not busy
- * @parameter base_address: is the base address of the device
- *
- * The queries the low order bit of the status register, which
- * indicates whether the current configuration or readback operation
- * has completed.
- **/
-static inline bool buffer_icap_done(void __iomem *base_address)
-{
- return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;
-}
-
-/**
- * buffer_icap_set_size: Set the size register.
- * @parameter base_address: is the base address of the device
- * @parameter data: The size in bytes.
- *
- * The size register holds the number of 8 bit bytes to transfer between
- * bram and the icap (or icap to bram).
- **/
-static inline void buffer_icap_set_size(void __iomem *base_address,
- u32 data)
-{
- out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
-}
-
-/**
- * buffer_icap_mSetoffsetReg: Set the bram offset register.
- * @parameter base_address: contains the base address of the device.
- * @parameter data: is the value to be written to the data register.
- *
- * The bram offset register holds the starting bram address to transfer
- * data from during configuration or write data to during readback.
- **/
-static inline void buffer_icap_set_offset(void __iomem *base_address,
- u32 data)
-{
- out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
-}
-
-/**
- * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
- * @parameter base_address: contains the base address of the device.
- * @parameter data: is the value to be written to the data register.
- *
- * The RNC register determines the direction of the data transfer. It
- * controls whether a configuration or readback take place. Writing to
- * this register initiates the transfer. A value of 1 initiates a
- * readback while writing a value of 0 initiates a configuration.
- **/
-static inline void buffer_icap_set_rnc(void __iomem *base_address,
- u32 data)
-{
- out_be32(base_address + XHI_RNC_REG_OFFSET, data);
-}
-
-/**
- * buffer_icap_set_bram: Write data to the storage buffer bram.
- * @parameter base_address: contains the base address of the component.
- * @parameter offset: The word offset at which the data should be written.
- * @parameter data: The value to be written to the bram offset.
- *
- * A bram is used as a configuration memory cache. One frame of data can
- * be stored in this "storage buffer".
- **/
-static inline void buffer_icap_set_bram(void __iomem *base_address,
- u32 offset, u32 data)
-{
- out_be32(base_address + (offset << 2), data);
-}
-
-/**
- * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
- * @parameter drvdata: a pointer to the drvdata.
- * @parameter offset: The storage buffer start address.
- * @parameter count: The number of words (32 bit) to read from the
- * device (ICAP).
- **/
-static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
- u32 offset, u32 count)
-{
-
- s32 retries = 0;
- void __iomem *base_address = drvdata->base_address;
-
- if (buffer_icap_busy(base_address))
- return -EBUSY;
-
- if ((offset + count) > XHI_MAX_BUFFER_INTS)
- return -EINVAL;
-
- /* setSize count*4 to get bytes. */
- buffer_icap_set_size(base_address, (count << 2));
- buffer_icap_set_offset(base_address, offset);
- buffer_icap_set_rnc(base_address, XHI_READBACK);
-
- while (buffer_icap_busy(base_address)) {
- retries++;
- if (retries > XHI_MAX_RETRIES)
- return -EBUSY;
- }
- return 0;
-
-};
-
-/**
- * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
- * @parameter drvdata: a pointer to the drvdata.
- * @parameter offset: The storage buffer start address.
- * @parameter count: The number of words (32 bit) to read from the
- * device (ICAP).
- **/
-static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
- u32 offset, u32 count)
-{
-
- s32 retries = 0;
- void __iomem *base_address = drvdata->base_address;
-
- if (buffer_icap_busy(base_address))
- return -EBUSY;
-
- if ((offset + count) > XHI_MAX_BUFFER_INTS)
- return -EINVAL;
-
- /* setSize count*4 to get bytes. */
- buffer_icap_set_size(base_address, count << 2);
- buffer_icap_set_offset(base_address, offset);
- buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
-
- while (buffer_icap_busy(base_address)) {
- retries++;
- if (retries > XHI_MAX_RETRIES)
- return -EBUSY;
- }
- return 0;
-
-};
-
-/**
- * buffer_icap_reset: Reset the logic of the icap device.
- * @parameter drvdata: a pointer to the drvdata.
- *
- * Writing to the status register resets the ICAP logic in an internal
- * version of the core. For the version of the core published in EDK,
- * this is a noop.
- **/
-void buffer_icap_reset(struct hwicap_drvdata *drvdata)
-{
- out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
-}
-
-/**
- * buffer_icap_set_configuration: Load a partial bitstream from system memory.
- * @parameter drvdata: a pointer to the drvdata.
- * @parameter data: Kernel address of the partial bitstream.
- * @parameter size: the size of the partial bitstream in 32 bit words.
- **/
-int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
- u32 size)
-{
- int status;
- s32 buffer_count = 0;
- s32 num_writes = 0;
- bool dirty = 0;
- u32 i;
- void __iomem *base_address = drvdata->base_address;
-
- /* Loop through all the data */
- for (i = 0, buffer_count = 0; i < size; i++) {
-
- /* Copy data to bram */
- buffer_icap_set_bram(base_address, buffer_count, data[i]);
- dirty = 1;
-
- if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
- buffer_count++;
- continue;
- }
-
- /* Write data to ICAP */
- status = buffer_icap_device_write(
- drvdata,
- XHI_BUFFER_START,
- XHI_MAX_BUFFER_INTS);
- if (status != 0) {
- /* abort. */
- buffer_icap_reset(drvdata);
- return status;
- }
-
- buffer_count = 0;
- num_writes++;
- dirty = 0;
- }
-
- /* Write unwritten data to ICAP */
- if (dirty) {
- /* Write data to ICAP */
- status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
- buffer_count);
- if (status != 0) {
- /* abort. */
- buffer_icap_reset(drvdata);
- }
- return status;
- }
-
- return 0;
-};
-
-/**
- * buffer_icap_get_configuration: Read configuration data from the device.
- * @parameter drvdata: a pointer to the drvdata.
- * @parameter data: Address of the data representing the partial bitstream
- * @parameter size: the size of the partial bitstream in 32 bit words.
- **/
-int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
- u32 size)
-{
- int status;
- s32 buffer_count = 0;
- s32 read_count = 0;
- u32 i;
- void __iomem *base_address = drvdata->base_address;
-
- /* Loop through all the data */
- for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
- if (buffer_count == XHI_MAX_BUFFER_INTS) {
- u32 words_remaining = size - i;
- u32 words_to_read =
- words_remaining <
- XHI_MAX_BUFFER_INTS ? words_remaining :
- XHI_MAX_BUFFER_INTS;
-
- /* Read data from ICAP */
- status = buffer_icap_device_read(
- drvdata,
- XHI_BUFFER_START,
- words_to_read);
- if (status != 0) {
- /* abort. */
- buffer_icap_reset(drvdata);
- return status;
- }
-
- buffer_count = 0;
- read_count++;
- }
-
- /* Copy data from bram */
- data[i] = buffer_icap_get_bram(base_address, buffer_count);
- buffer_count++;
- }
-
- return 0;
-};
diff --git a/trunk/drivers/char/xilinx_hwicap/buffer_icap.h b/trunk/drivers/char/xilinx_hwicap/buffer_icap.h
deleted file mode 100644
index 03184959fa00..000000000000
--- a/trunk/drivers/char/xilinx_hwicap/buffer_icap.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*****************************************************************************
- *
- * Author: Xilinx, Inc.
- *
- * 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.
- *
- * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
- * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
- * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
- * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
- * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
- * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
- * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
- * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
- * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
- * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
- * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
- * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE.
- *
- * Xilinx products are not intended for use in life support appliances,
- * devices, or systems. Use in such applications is expressly prohibited.
- *
- * (c) Copyright 2003-2008 Xilinx Inc.
- * All rights reserved.
- *
- * 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 XILINX_BUFFER_ICAP_H_ /* prevent circular inclusions */
-#define XILINX_BUFFER_ICAP_H_ /* by using protection macros */
-
-#include
-#include
-#include
-#include
-
-#include