diff options
338 files changed, 10745 insertions, 9330 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 73060819ed99..438277800103 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX | |||
@@ -159,8 +159,6 @@ hayes-esp.txt | |||
159 | - info on using the Hayes ESP serial driver. | 159 | - info on using the Hayes ESP serial driver. |
160 | highuid.txt | 160 | highuid.txt |
161 | - notes on the change from 16 bit to 32 bit user/group IDs. | 161 | - notes on the change from 16 bit to 32 bit user/group IDs. |
162 | hpet.txt | ||
163 | - High Precision Event Timer Driver for Linux. | ||
164 | timers/ | 162 | timers/ |
165 | - info on the timer related topics | 163 | - info on the timer related topics |
166 | hw_random.txt | 164 | hw_random.txt |
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 3d2d0c29f027..cc8093c15cf5 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -287,14 +287,6 @@ Who: Glauber Costa <gcosta@redhat.com> | |||
287 | 287 | ||
288 | --------------------------- | 288 | --------------------------- |
289 | 289 | ||
290 | What: old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE) | ||
291 | When: 2.6.28 | ||
292 | Why: This driver still uses the old interface and has been replaced | ||
293 | by CONFIG_SERIAL_MCF. | ||
294 | Who: Sebastian Siewior <sebastian@breakpoint.cc> | ||
295 | |||
296 | --------------------------- | ||
297 | |||
298 | What: /sys/o2cb symlink | 290 | What: /sys/o2cb symlink |
299 | When: January 2010 | 291 | When: January 2010 |
300 | Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb | 292 | Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb |
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index d831d24d2a6c..b488edad743c 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt | |||
@@ -1331,13 +1331,6 @@ determine whether or not they are still functioning properly. | |||
1331 | Because the NMI watchdog shares registers with oprofile, by disabling the NMI | 1331 | Because the NMI watchdog shares registers with oprofile, by disabling the NMI |
1332 | watchdog, oprofile may have more registers to utilize. | 1332 | watchdog, oprofile may have more registers to utilize. |
1333 | 1333 | ||
1334 | maps_protect | ||
1335 | ------------ | ||
1336 | |||
1337 | Enables/Disables the protection of the per-process proc entries "maps" and | ||
1338 | "smaps". When enabled, the contents of these files are visible only to | ||
1339 | readers that are allowed to ptrace() the given process. | ||
1340 | |||
1341 | msgmni | 1334 | msgmni |
1342 | ------ | 1335 | ------ |
1343 | 1336 | ||
diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX new file mode 100644 index 000000000000..397dc35e1323 --- /dev/null +++ b/Documentation/timers/00-INDEX | |||
@@ -0,0 +1,10 @@ | |||
1 | 00-INDEX | ||
2 | - this file | ||
3 | highres.txt | ||
4 | - High resolution timers and dynamic ticks design notes | ||
5 | hpet.txt | ||
6 | - High Precision Event Timer Driver for Linux | ||
7 | hrtimers.txt | ||
8 | - subsystem for high-resolution kernel timers | ||
9 | timer_stats.txt | ||
10 | - timer usage statistics | ||
diff --git a/Documentation/hpet.txt b/Documentation/timers/hpet.txt index 6ad52d9dad6c..e7c09abcfab4 100644 --- a/Documentation/hpet.txt +++ b/Documentation/timers/hpet.txt | |||
@@ -1,21 +1,32 @@ | |||
1 | High Precision Event Timer Driver for Linux | 1 | High Precision Event Timer Driver for Linux |
2 | 2 | ||
3 | The High Precision Event Timer (HPET) hardware is the future replacement | 3 | The High Precision Event Timer (HPET) hardware follows a specification |
4 | for the 8254 and Real Time Clock (RTC) periodic timer functionality. | 4 | by Intel and Microsoft which can be found at |
5 | Each HPET can have up to 32 timers. It is possible to configure the | 5 | |
6 | first two timers as legacy replacements for 8254 and RTC periodic timers. | 6 | http://www.intel.com/technology/architecture/hpetspec.htm |
7 | A specification done by Intel and Microsoft can be found at | 7 | |
8 | <http://www.intel.com/technology/architecture/hpetspec.htm>. | 8 | Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision") |
9 | and up to 32 comparators. Normally three or more comparators are provided, | ||
10 | each of which can generate oneshot interupts and at least one of which has | ||
11 | additional hardware to support periodic interrupts. The comparators are | ||
12 | also called "timers", which can be misleading since usually timers are | ||
13 | independent of each other ... these share a counter, complicating resets. | ||
14 | |||
15 | HPET devices can support two interrupt routing modes. In one mode, the | ||
16 | comparators are additional interrupt sources with no particular system | ||
17 | role. Many x86 BIOS writers don't route HPET interrupts at all, which | ||
18 | prevents use of that mode. They support the other "legacy replacement" | ||
19 | mode where the first two comparators block interrupts from 8254 timers | ||
20 | and from the RTC. | ||
9 | 21 | ||
10 | The driver supports detection of HPET driver allocation and initialization | 22 | The driver supports detection of HPET driver allocation and initialization |
11 | of the HPET before the driver module_init routine is called. This enables | 23 | of the HPET before the driver module_init routine is called. This enables |
12 | platform code which uses timer 0 or 1 as the main timer to intercept HPET | 24 | platform code which uses timer 0 or 1 as the main timer to intercept HPET |
13 | initialization. An example of this initialization can be found in | 25 | initialization. An example of this initialization can be found in |
14 | arch/i386/kernel/time_hpet.c. | 26 | arch/x86/kernel/hpet.c. |
15 | 27 | ||
16 | The driver provides two APIs which are very similar to the API found in | 28 | The driver provides a userspace API which resembles the API found in the |
17 | the rtc.c driver. There is a user space API and a kernel space API. | 29 | RTC driver framework. An example user space program is provided below. |
18 | An example user space program is provided below. | ||
19 | 30 | ||
20 | #include <stdio.h> | 31 | #include <stdio.h> |
21 | #include <stdlib.h> | 32 | #include <stdlib.h> |
@@ -286,15 +297,3 @@ out: | |||
286 | 297 | ||
287 | return; | 298 | return; |
288 | } | 299 | } |
289 | |||
290 | The kernel API has three interfaces exported from the driver: | ||
291 | |||
292 | hpet_register(struct hpet_task *tp, int periodic) | ||
293 | hpet_unregister(struct hpet_task *tp) | ||
294 | hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) | ||
295 | |||
296 | The kernel module using this interface fills in the ht_func and ht_data | ||
297 | members of the hpet_task structure before calling hpet_register. | ||
298 | hpet_control simply vectors to the hpet_ioctl routine and has the same | ||
299 | commands and respective arguments as the user API. hpet_unregister | ||
300 | is used to terminate usage of the HPET timer reserved by hpet_register. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 6ba3ee822838..74b808205312 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2797,15 +2797,6 @@ L: linux-mtd@lists.infradead.org | |||
2797 | T: git git://git.infradead.org/mtd-2.6.git | 2797 | T: git git://git.infradead.org/mtd-2.6.git |
2798 | S: Maintained | 2798 | S: Maintained |
2799 | 2799 | ||
2800 | MEI MN10300/AM33 PORT | ||
2801 | P: David Howells | ||
2802 | M: dhowells@redhat.com | ||
2803 | P: Koichi Yasutake | ||
2804 | M: yasutake.koichi@jp.panasonic.com | ||
2805 | L: linux-am33-list@redhat.com (moderated for non-subscribers) | ||
2806 | W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/ | ||
2807 | S: Maintained | ||
2808 | |||
2809 | MICROTEK X6 SCANNER | 2800 | MICROTEK X6 SCANNER |
2810 | P: Oliver Neukum | 2801 | P: Oliver Neukum |
2811 | M: oliver@neukum.name | 2802 | M: oliver@neukum.name |
@@ -3170,6 +3161,15 @@ M: olof@lixom.net | |||
3170 | L: i2c@lm-sensors.org | 3161 | L: i2c@lm-sensors.org |
3171 | S: Maintained | 3162 | S: Maintained |
3172 | 3163 | ||
3164 | PANASONIC MN10300/AM33 PORT | ||
3165 | P: David Howells | ||
3166 | M: dhowells@redhat.com | ||
3167 | P: Koichi Yasutake | ||
3168 | M: yasutake.koichi@jp.panasonic.com | ||
3169 | L: linux-am33-list@redhat.com (moderated for non-subscribers) | ||
3170 | W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/ | ||
3171 | S: Maintained | ||
3172 | |||
3173 | PARALLEL PORT SUPPORT | 3173 | PARALLEL PORT SUPPORT |
3174 | L: linux-parport@lists.infradead.org (subscribers-only) | 3174 | L: linux-parport@lists.infradead.org (subscribers-only) |
3175 | S: Orphan | 3175 | S: Orphan |
diff --git a/arch/Kconfig b/arch/Kconfig index 364c6dadde0a..0267babe5eb9 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -13,6 +13,20 @@ config OPROFILE | |||
13 | 13 | ||
14 | If unsure, say N. | 14 | If unsure, say N. |
15 | 15 | ||
16 | config OPROFILE_IBS | ||
17 | bool "OProfile AMD IBS support (EXPERIMENTAL)" | ||
18 | default n | ||
19 | depends on OPROFILE && SMP && X86 | ||
20 | help | ||
21 | Instruction-Based Sampling (IBS) is a new profiling | ||
22 | technique that provides rich, precise program performance | ||
23 | information. IBS is introduced by AMD Family10h processors | ||
24 | (AMD Opteron Quad-Core processor “Barcelona”) to overcome | ||
25 | the limitations of conventional performance counter | ||
26 | sampling. | ||
27 | |||
28 | If unsure, say N. | ||
29 | |||
16 | config HAVE_OPROFILE | 30 | config HAVE_OPROFILE |
17 | def_bool n | 31 | def_bool n |
18 | 32 | ||
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 1bec55d63ef6..ee35226c44e9 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | config ALPHA | 5 | config ALPHA |
6 | bool | 6 | bool |
7 | default y | 7 | default y |
8 | select HAVE_AOUT | ||
8 | select HAVE_IDE | 9 | select HAVE_IDE |
9 | select HAVE_OPROFILE | 10 | select HAVE_OPROFILE |
10 | help | 11 | help |
@@ -68,9 +69,6 @@ config AUTO_IRQ_AFFINITY | |||
68 | depends on SMP | 69 | depends on SMP |
69 | default y | 70 | default y |
70 | 71 | ||
71 | config ARCH_SUPPORTS_AOUT | ||
72 | def_bool y | ||
73 | |||
74 | source "init/Kconfig" | 72 | source "init/Kconfig" |
75 | 73 | ||
76 | 74 | ||
diff --git a/arch/alpha/include/asm/statfs.h b/arch/alpha/include/asm/statfs.h index ad15830baefe..de35cd438a10 100644 --- a/arch/alpha/include/asm/statfs.h +++ b/arch/alpha/include/asm/statfs.h | |||
@@ -1,6 +1,10 @@ | |||
1 | #ifndef _ALPHA_STATFS_H | 1 | #ifndef _ALPHA_STATFS_H |
2 | #define _ALPHA_STATFS_H | 2 | #define _ALPHA_STATFS_H |
3 | 3 | ||
4 | /* Alpha is the only 64-bit platform with 32-bit statfs. And doesn't | ||
5 | even seem to implement statfs64 */ | ||
6 | #define __statfs_word __u32 | ||
7 | |||
4 | #include <asm-generic/statfs.h> | 8 | #include <asm-generic/statfs.h> |
5 | 9 | ||
6 | #endif | 10 | #endif |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index efeed65b4a66..4853f9df37bd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration" | |||
8 | config ARM | 8 | config ARM |
9 | bool | 9 | bool |
10 | default y | 10 | default y |
11 | select HAVE_AOUT | ||
11 | select HAVE_IDE | 12 | select HAVE_IDE |
12 | select RTC_LIB | 13 | select RTC_LIB |
13 | select SYS_SUPPORTS_APM_EMULATION | 14 | select SYS_SUPPORTS_APM_EMULATION |
@@ -140,9 +141,6 @@ config GENERIC_CALIBRATE_DELAY | |||
140 | bool | 141 | bool |
141 | default y | 142 | default y |
142 | 143 | ||
143 | config ARCH_SUPPORTS_AOUT | ||
144 | def_bool y | ||
145 | |||
146 | config ARCH_MAY_HAVE_PC_FDC | 144 | config ARCH_MAY_HAVE_PC_FDC |
147 | bool | 145 | bool |
148 | 146 | ||
diff --git a/arch/arm/include/asm/statfs.h b/arch/arm/include/asm/statfs.h index a02e6a8c3d70..079447c05ba7 100644 --- a/arch/arm/include/asm/statfs.h +++ b/arch/arm/include/asm/statfs.h | |||
@@ -1,42 +1,12 @@ | |||
1 | #ifndef _ASMARM_STATFS_H | 1 | #ifndef _ASMARM_STATFS_H |
2 | #define _ASMARM_STATFS_H | 2 | #define _ASMARM_STATFS_H |
3 | 3 | ||
4 | #ifndef __KERNEL_STRICT_NAMES | ||
5 | # include <linux/types.h> | ||
6 | typedef __kernel_fsid_t fsid_t; | ||
7 | #endif | ||
8 | |||
9 | struct statfs { | ||
10 | __u32 f_type; | ||
11 | __u32 f_bsize; | ||
12 | __u32 f_blocks; | ||
13 | __u32 f_bfree; | ||
14 | __u32 f_bavail; | ||
15 | __u32 f_files; | ||
16 | __u32 f_ffree; | ||
17 | __kernel_fsid_t f_fsid; | ||
18 | __u32 f_namelen; | ||
19 | __u32 f_frsize; | ||
20 | __u32 f_spare[5]; | ||
21 | }; | ||
22 | |||
23 | /* | 4 | /* |
24 | * With EABI there is 4 bytes of padding added to this structure. | 5 | * With EABI there is 4 bytes of padding added to this structure. |
25 | * Let's pack it so the padding goes away to simplify dual ABI support. | 6 | * Let's pack it so the padding goes away to simplify dual ABI support. |
26 | * Note that user space does NOT have to pack this structure. | 7 | * Note that user space does NOT have to pack this structure. |
27 | */ | 8 | */ |
28 | struct statfs64 { | 9 | #define ARCH_PACK_STATFS64 __attribute__((packed,aligned(4))) |
29 | __u32 f_type; | ||
30 | __u32 f_bsize; | ||
31 | __u64 f_blocks; | ||
32 | __u64 f_bfree; | ||
33 | __u64 f_bavail; | ||
34 | __u64 f_files; | ||
35 | __u64 f_ffree; | ||
36 | __kernel_fsid_t f_fsid; | ||
37 | __u32 f_namelen; | ||
38 | __u32 f_frsize; | ||
39 | __u32 f_spare[5]; | ||
40 | } __attribute__ ((packed,aligned(4))); | ||
41 | 10 | ||
11 | #include <asm-generic/statfs.h> | ||
42 | #endif | 12 | #endif |
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index ba99a2035523..d006085ed7e7 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c | |||
@@ -26,23 +26,6 @@ EXPORT_SYMBOL(dma_spin_lock); | |||
26 | static dma_t dma_chan[MAX_DMA_CHANNELS]; | 26 | static dma_t dma_chan[MAX_DMA_CHANNELS]; |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Get dma list for /proc/dma | ||
30 | */ | ||
31 | int get_dma_list(char *buf) | ||
32 | { | ||
33 | dma_t *dma; | ||
34 | char *p = buf; | ||
35 | int i; | ||
36 | |||
37 | for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++) | ||
38 | if (dma->lock) | ||
39 | p += sprintf(p, "%2d: %14s %s\n", i, | ||
40 | dma->d_ops->type, dma->device_id); | ||
41 | |||
42 | return p - buf; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Request DMA channel | 29 | * Request DMA channel |
47 | * | 30 | * |
48 | * On certain platforms, we have to allocate an interrupt as well... | 31 | * On certain platforms, we have to allocate an interrupt as well... |
diff --git a/arch/avr32/include/asm/a.out.h b/arch/avr32/include/asm/a.out.h deleted file mode 100644 index e46375a34a72..000000000000 --- a/arch/avr32/include/asm/a.out.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef __ASM_AVR32_A_OUT_H | ||
2 | #define __ASM_AVR32_A_OUT_H | ||
3 | |||
4 | struct exec | ||
5 | { | ||
6 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
7 | unsigned a_text; /* length of text, in bytes */ | ||
8 | unsigned a_data; /* length of data, in bytes */ | ||
9 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
10 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
11 | unsigned a_entry; /* start address */ | ||
12 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
13 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
14 | }; | ||
15 | |||
16 | #define N_TRSIZE(a) ((a).a_trsize) | ||
17 | #define N_DRSIZE(a) ((a).a_drsize) | ||
18 | #define N_SYMSIZE(a) ((a).a_syms) | ||
19 | |||
20 | #endif /* __ASM_AVR32_A_OUT_H */ | ||
diff --git a/arch/blackfin/include/asm/a.out.h b/arch/blackfin/include/asm/a.out.h deleted file mode 100644 index 6c3d652ebd33..000000000000 --- a/arch/blackfin/include/asm/a.out.h +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | #ifndef __BFIN_A_OUT_H__ | ||
2 | #define __BFIN_A_OUT_H__ | ||
3 | |||
4 | struct exec { | ||
5 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
6 | unsigned a_text; /* length of text, in bytes */ | ||
7 | unsigned a_data; /* length of data, in bytes */ | ||
8 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
9 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
10 | unsigned a_entry; /* start address */ | ||
11 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
12 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
13 | }; | ||
14 | |||
15 | #define N_TRSIZE(a) ((a).a_trsize) | ||
16 | #define N_DRSIZE(a) ((a).a_drsize) | ||
17 | #define N_SYMSIZE(a) ((a).a_syms) | ||
18 | |||
19 | #endif /* __BFIN_A_OUT_H__ */ | ||
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 93229b3d6e3e..339293d677cc 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c | |||
@@ -117,15 +117,14 @@ int request_dma(unsigned int channel, char *device_id) | |||
117 | 117 | ||
118 | #ifdef CONFIG_BF54x | 118 | #ifdef CONFIG_BF54x |
119 | if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { | 119 | if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { |
120 | if (strncmp(device_id, "BFIN_UART", 9) == 0) { | 120 | unsigned int per_map; |
121 | dma_ch[channel].regs->peripheral_map &= 0x0FFF; | 121 | per_map = dma_ch[channel].regs->peripheral_map & 0xFFF; |
122 | dma_ch[channel].regs->peripheral_map |= | 122 | if (strncmp(device_id, "BFIN_UART", 9) == 0) |
123 | dma_ch[channel].regs->peripheral_map = per_map | | ||
123 | ((channel - CH_UART2_RX + 0xC)<<12); | 124 | ((channel - CH_UART2_RX + 0xC)<<12); |
124 | } else { | 125 | else |
125 | dma_ch[channel].regs->peripheral_map &= 0x0FFF; | 126 | dma_ch[channel].regs->peripheral_map = per_map | |
126 | dma_ch[channel].regs->peripheral_map |= | ||
127 | ((channel - CH_UART2_RX + 0x6)<<12); | 127 | ((channel - CH_UART2_RX + 0x6)<<12); |
128 | } | ||
129 | } | 128 | } |
130 | #endif | 129 | #endif |
131 | 130 | ||
diff --git a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h index 2526b6ed6faa..75722d6008b0 100644 --- a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h +++ b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h | |||
@@ -78,6 +78,9 @@ | |||
78 | # define CONFIG_UART1_RTS_PIN -1 | 78 | # define CONFIG_UART1_RTS_PIN -1 |
79 | # endif | 79 | # endif |
80 | #endif | 80 | #endif |
81 | |||
82 | #define BFIN_UART_TX_FIFO_SIZE 2 | ||
83 | |||
81 | /* | 84 | /* |
82 | * The pin configuration is different from schematic | 85 | * The pin configuration is different from schematic |
83 | */ | 86 | */ |
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | |||
119 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | 122 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); |
120 | } | 123 | } |
121 | 124 | ||
122 | struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; | ||
123 | struct bfin_serial_res { | 125 | struct bfin_serial_res { |
124 | unsigned long uart_base_addr; | 126 | unsigned long uart_base_addr; |
125 | int uart_irq; | 127 | int uart_irq; |
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = { | |||
164 | #endif | 166 | #endif |
165 | }; | 167 | }; |
166 | 168 | ||
167 | int nr_ports = ARRAY_SIZE(bfin_serial_resource); | ||
168 | |||
169 | #define DRIVER_NAME "bfin-uart" | 169 | #define DRIVER_NAME "bfin-uart" |
170 | 170 | ||
171 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) | 171 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) |
diff --git a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h index ebf592b59aab..815bfe5dd1a9 100644 --- a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h +++ b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h | |||
@@ -69,6 +69,8 @@ | |||
69 | # endif | 69 | # endif |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #define BFIN_UART_TX_FIFO_SIZE 2 | ||
73 | |||
72 | struct bfin_serial_port { | 74 | struct bfin_serial_port { |
73 | struct uart_port port; | 75 | struct uart_port port; |
74 | unsigned int old_status; | 76 | unsigned int old_status; |
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | |||
111 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | 113 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); |
112 | } | 114 | } |
113 | 115 | ||
114 | struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; | ||
115 | struct bfin_serial_res { | 116 | struct bfin_serial_res { |
116 | unsigned long uart_base_addr; | 117 | unsigned long uart_base_addr; |
117 | int uart_irq; | 118 | int uart_irq; |
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = { | |||
142 | 143 | ||
143 | #define DRIVER_NAME "bfin-uart" | 144 | #define DRIVER_NAME "bfin-uart" |
144 | 145 | ||
145 | int nr_ports = BFIN_UART_NR_PORTS; | ||
146 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) | 146 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) |
147 | { | 147 | { |
148 | 148 | ||
diff --git a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h index 1bf56ffa22f9..b3f87e1d16a2 100644 --- a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h +++ b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h | |||
@@ -78,6 +78,9 @@ | |||
78 | # define CONFIG_UART1_RTS_PIN -1 | 78 | # define CONFIG_UART1_RTS_PIN -1 |
79 | # endif | 79 | # endif |
80 | #endif | 80 | #endif |
81 | |||
82 | #define BFIN_UART_TX_FIFO_SIZE 2 | ||
83 | |||
81 | /* | 84 | /* |
82 | * The pin configuration is different from schematic | 85 | * The pin configuration is different from schematic |
83 | */ | 86 | */ |
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | |||
119 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | 122 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); |
120 | } | 123 | } |
121 | 124 | ||
122 | struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; | ||
123 | struct bfin_serial_res { | 125 | struct bfin_serial_res { |
124 | unsigned long uart_base_addr; | 126 | unsigned long uart_base_addr; |
125 | int uart_irq; | 127 | int uart_irq; |
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = { | |||
164 | #endif | 166 | #endif |
165 | }; | 167 | }; |
166 | 168 | ||
167 | int nr_ports = ARRAY_SIZE(bfin_serial_resource); | ||
168 | |||
169 | #define DRIVER_NAME "bfin-uart" | 169 | #define DRIVER_NAME "bfin-uart" |
170 | 170 | ||
171 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) | 171 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) |
diff --git a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h index 5e29446a8e03..e4cf35e7ab9f 100644 --- a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h +++ b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h | |||
@@ -82,6 +82,9 @@ | |||
82 | # define CONFIG_UART1_RTS_PIN -1 | 82 | # define CONFIG_UART1_RTS_PIN -1 |
83 | # endif | 83 | # endif |
84 | #endif | 84 | #endif |
85 | |||
86 | #define BFIN_UART_TX_FIFO_SIZE 2 | ||
87 | |||
85 | /* | 88 | /* |
86 | * The pin configuration is different from schematic | 89 | * The pin configuration is different from schematic |
87 | */ | 90 | */ |
@@ -105,7 +108,6 @@ struct bfin_serial_port { | |||
105 | #endif | 108 | #endif |
106 | }; | 109 | }; |
107 | 110 | ||
108 | struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; | ||
109 | struct bfin_serial_res { | 111 | struct bfin_serial_res { |
110 | unsigned long uart_base_addr; | 112 | unsigned long uart_base_addr; |
111 | int uart_irq; | 113 | int uart_irq; |
@@ -170,8 +172,6 @@ struct bfin_serial_res bfin_serial_resource[] = { | |||
170 | #endif | 172 | #endif |
171 | }; | 173 | }; |
172 | 174 | ||
173 | int nr_ports = ARRAY_SIZE(bfin_serial_resource); | ||
174 | |||
175 | #define DRIVER_NAME "bfin-uart" | 175 | #define DRIVER_NAME "bfin-uart" |
176 | 176 | ||
177 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) | 177 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) |
diff --git a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h index 8aa02780e642..e0ce0c1843d4 100644 --- a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h +++ b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h | |||
@@ -69,6 +69,8 @@ | |||
69 | # endif | 69 | # endif |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #define BFIN_UART_TX_FIFO_SIZE 2 | ||
73 | |||
72 | struct bfin_serial_port { | 74 | struct bfin_serial_port { |
73 | struct uart_port port; | 75 | struct uart_port port; |
74 | unsigned int old_status; | 76 | unsigned int old_status; |
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) | |||
111 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); | 113 | bfin_write16(uart->port.membase + OFFSET_LSR, -1); |
112 | } | 114 | } |
113 | 115 | ||
114 | struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; | ||
115 | struct bfin_serial_res { | 116 | struct bfin_serial_res { |
116 | unsigned long uart_base_addr; | 117 | unsigned long uart_base_addr; |
117 | int uart_irq; | 118 | int uart_irq; |
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = { | |||
142 | 143 | ||
143 | #define DRIVER_NAME "bfin-uart" | 144 | #define DRIVER_NAME "bfin-uart" |
144 | 145 | ||
145 | int nr_ports = BFIN_UART_NR_PORTS; | ||
146 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) | 146 | static void bfin_serial_hw_init(struct bfin_serial_port *uart) |
147 | { | 147 | { |
148 | 148 | ||
diff --git a/arch/cris/arch-v10/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c index 2f9bbb26d603..c8adef364160 100644 --- a/arch/cris/arch-v10/boot/tools/build.c +++ b/arch/cris/arch-v10/boot/tools/build.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <sys/sysmacros.h> | 30 | #include <sys/sysmacros.h> |
31 | #include <unistd.h> /* contains read/write */ | 31 | #include <unistd.h> /* contains read/write */ |
32 | #include <fcntl.h> | 32 | #include <fcntl.h> |
33 | #include <linux/a.out.h> | ||
34 | #include <errno.h> | 33 | #include <errno.h> |
35 | 34 | ||
36 | #define MINIX_HEADER 32 | 35 | #define MINIX_HEADER 32 |
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 396ab059efa3..107cb5bb9f39 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig | |||
@@ -66,9 +66,6 @@ config TIME_LOW_RES | |||
66 | bool | 66 | bool |
67 | default y | 67 | default y |
68 | 68 | ||
69 | config ARCH_SUPPORTS_AOUT | ||
70 | def_bool y | ||
71 | |||
72 | config NO_IOPORT | 69 | config NO_IOPORT |
73 | def_bool y | 70 | def_bool y |
74 | 71 | ||
diff --git a/arch/h8300/include/asm/a.out.h b/arch/h8300/include/asm/a.out.h deleted file mode 100644 index ded780f0a492..000000000000 --- a/arch/h8300/include/asm/a.out.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef __H8300_A_OUT_H__ | ||
2 | #define __H8300_A_OUT_H__ | ||
3 | |||
4 | struct exec | ||
5 | { | ||
6 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
7 | unsigned a_text; /* length of text, in bytes */ | ||
8 | unsigned a_data; /* length of data, in bytes */ | ||
9 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
10 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
11 | unsigned a_entry; /* start address */ | ||
12 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
13 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
14 | }; | ||
15 | |||
16 | #define N_TRSIZE(a) ((a).a_trsize) | ||
17 | #define N_DRSIZE(a) ((a).a_drsize) | ||
18 | #define N_SYMSIZE(a) ((a).a_syms) | ||
19 | |||
20 | #endif /* __H8300_A_OUT_H__ */ | ||
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index dfbe7ab9ffe2..a8ef654a5a0b 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/ptrace.h> | 34 | #include <linux/ptrace.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/user.h> | 36 | #include <linux/user.h> |
37 | #include <linux/a.out.h> | ||
38 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
39 | #include <linux/reboot.h> | 38 | #include <linux/reboot.h> |
40 | #include <linux/fs.h> | 39 | #include <linux/fs.h> |
diff --git a/arch/ia64/include/asm/a.out.h b/arch/ia64/include/asm/a.out.h deleted file mode 100644 index 193dcfb67596..000000000000 --- a/arch/ia64/include/asm/a.out.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | #ifndef _ASM_IA64_A_OUT_H | ||
2 | #define _ASM_IA64_A_OUT_H | ||
3 | |||
4 | /* | ||
5 | * No a.out format has been (or should be) defined so this file is | ||
6 | * just a dummy that allows us to get binfmt_elf compiled. It | ||
7 | * probably would be better to clean up binfmt_elf.c so it does not | ||
8 | * necessarily depend on there being a.out support. | ||
9 | * | ||
10 | * Modified 1998-2002 | ||
11 | * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co. | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | |||
16 | struct exec { | ||
17 | unsigned long a_info; | ||
18 | unsigned long a_text; | ||
19 | unsigned long a_data; | ||
20 | unsigned long a_bss; | ||
21 | unsigned long a_entry; | ||
22 | }; | ||
23 | |||
24 | #define N_TXTADDR(x) 0 | ||
25 | #define N_DATADDR(x) 0 | ||
26 | #define N_BSSADDR(x) 0 | ||
27 | #define N_DRSIZE(x) 0 | ||
28 | #define N_TRSIZE(x) 0 | ||
29 | #define N_SYMSIZE(x) 0 | ||
30 | #define N_TXTOFF(x) 0 | ||
31 | |||
32 | #endif /* _ASM_IA64_A_OUT_H */ | ||
diff --git a/arch/ia64/include/asm/statfs.h b/arch/ia64/include/asm/statfs.h index 811097974f31..1e589669de56 100644 --- a/arch/ia64/include/asm/statfs.h +++ b/arch/ia64/include/asm/statfs.h | |||
@@ -8,55 +8,13 @@ | |||
8 | * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co | 8 | * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef __KERNEL_STRICT_NAMES | ||
12 | # include <linux/types.h> | ||
13 | typedef __kernel_fsid_t fsid_t; | ||
14 | #endif | ||
15 | |||
16 | /* | 11 | /* |
17 | * This is ugly --- we're already 64-bit, so just duplicate the definitions | 12 | * We need compat_statfs64 to be packed, because the i386 ABI won't |
13 | * add padding at the end to bring it to a multiple of 8 bytes, but | ||
14 | * the IA64 ABI will. | ||
18 | */ | 15 | */ |
19 | struct statfs { | 16 | #define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4))) |
20 | long f_type; | ||
21 | long f_bsize; | ||
22 | long f_blocks; | ||
23 | long f_bfree; | ||
24 | long f_bavail; | ||
25 | long f_files; | ||
26 | long f_ffree; | ||
27 | __kernel_fsid_t f_fsid; | ||
28 | long f_namelen; | ||
29 | long f_frsize; | ||
30 | long f_spare[5]; | ||
31 | }; | ||
32 | |||
33 | |||
34 | struct statfs64 { | ||
35 | long f_type; | ||
36 | long f_bsize; | ||
37 | long f_blocks; | ||
38 | long f_bfree; | ||
39 | long f_bavail; | ||
40 | long f_files; | ||
41 | long f_ffree; | ||
42 | __kernel_fsid_t f_fsid; | ||
43 | long f_namelen; | ||
44 | long f_frsize; | ||
45 | long f_spare[5]; | ||
46 | }; | ||
47 | 17 | ||
48 | struct compat_statfs64 { | 18 | #include <asm-generic/statfs.h> |
49 | __u32 f_type; | ||
50 | __u32 f_bsize; | ||
51 | __u64 f_blocks; | ||
52 | __u64 f_bfree; | ||
53 | __u64 f_bavail; | ||
54 | __u64 f_files; | ||
55 | __u64 f_ffree; | ||
56 | __kernel_fsid_t f_fsid; | ||
57 | __u32 f_namelen; | ||
58 | __u32 f_frsize; | ||
59 | __u32 f_spare[5]; | ||
60 | } __attribute__((packed)); | ||
61 | 19 | ||
62 | #endif /* _ASM_IA64_STATFS_H */ | 20 | #endif /* _ASM_IA64_STATFS_H */ |
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 200100ea7610..f482a9098e32 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/kexec.h> | 22 | #include <linux/kexec.h> |
23 | 23 | ||
24 | #include <asm/a.out.h> | ||
25 | #include <asm/dma.h> | 24 | #include <asm/dma.h> |
26 | #include <asm/ia32.h> | 25 | #include <asm/ia32.h> |
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index f57113f1f892..00289c178f89 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig | |||
@@ -36,9 +36,6 @@ config NO_IOPORT | |||
36 | config NO_DMA | 36 | config NO_DMA |
37 | def_bool y | 37 | def_bool y |
38 | 38 | ||
39 | config ARCH_SUPPORTS_AOUT | ||
40 | def_bool y | ||
41 | |||
42 | config HZ | 39 | config HZ |
43 | int | 40 | int |
44 | default 100 | 41 | default 100 |
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 8c5e1de68fcb..41e5bf02e230 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | config M68K | 5 | config M68K |
6 | bool | 6 | bool |
7 | default y | 7 | default y |
8 | select HAVE_AOUT | ||
8 | select HAVE_IDE | 9 | select HAVE_IDE |
9 | 10 | ||
10 | config MMU | 11 | config MMU |
@@ -53,9 +54,6 @@ config NO_IOPORT | |||
53 | config NO_DMA | 54 | config NO_DMA |
54 | def_bool SUN3 | 55 | def_bool SUN3 |
55 | 56 | ||
56 | config ARCH_SUPPORTS_AOUT | ||
57 | def_bool y | ||
58 | |||
59 | config HZ | 57 | config HZ |
60 | int | 58 | int |
61 | default 100 | 59 | default 100 |
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 2e7515e8db98..0a8998315e5e 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig | |||
@@ -73,9 +73,6 @@ config GENERIC_CLOCKEVENTS | |||
73 | config NO_IOPORT | 73 | config NO_IOPORT |
74 | def_bool y | 74 | def_bool y |
75 | 75 | ||
76 | config ARCH_SUPPORTS_AOUT | ||
77 | def_bool y | ||
78 | |||
79 | source "init/Kconfig" | 76 | source "init/Kconfig" |
80 | 77 | ||
81 | menu "Processor type and features" | 78 | menu "Processor type and features" |
diff --git a/arch/m68knommu/include/asm/a.out.h b/arch/m68knommu/include/asm/a.out.h deleted file mode 100644 index ce18ef99de04..000000000000 --- a/arch/m68knommu/include/asm/a.out.h +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | #include <asm-m68k/a.out.h> | ||
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 47502d5ec19f..3f2d7745f31e 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/user.h> | 27 | #include <linux/user.h> |
28 | #include <linux/a.out.h> | ||
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
30 | #include <linux/reboot.h> | 29 | #include <linux/reboot.h> |
31 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c index 46f8f9d0c408..5d5d56bcd0ef 100644 --- a/arch/m68knommu/kernel/traps.c +++ b/arch/m68knommu/kernel/traps.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/a.out.h> | ||
26 | #include <linux/user.h> | 25 | #include <linux/user.h> |
27 | #include <linux/string.h> | 26 | #include <linux/string.h> |
28 | #include <linux/linkage.h> | 27 | #include <linux/linkage.h> |
diff --git a/arch/mips/include/asm/a.out.h b/arch/mips/include/asm/a.out.h deleted file mode 100644 index cad8371422ab..000000000000 --- a/arch/mips/include/asm/a.out.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1994 - 1999, 2003 by Ralf Baechle | ||
7 | */ | ||
8 | #ifndef _ASM_A_OUT_H | ||
9 | #define _ASM_A_OUT_H | ||
10 | |||
11 | #ifdef __KERNEL__ | ||
12 | |||
13 | |||
14 | #endif | ||
15 | |||
16 | struct exec | ||
17 | { | ||
18 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
19 | unsigned a_text; /* length of text, in bytes */ | ||
20 | unsigned a_data; /* length of data, in bytes */ | ||
21 | unsigned a_bss; /* length of uninitialized data area for | ||
22 | file, in bytes */ | ||
23 | unsigned a_syms; /* length of symbol table data in file, | ||
24 | in bytes */ | ||
25 | unsigned a_entry; /* start address */ | ||
26 | unsigned a_trsize; /* length of relocation info for text, in | ||
27 | bytes */ | ||
28 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
29 | }; | ||
30 | |||
31 | #define N_TRSIZE(a) ((a).a_trsize) | ||
32 | #define N_DRSIZE(a) ((a).a_drsize) | ||
33 | #define N_SYMSIZE(a) ((a).a_syms) | ||
34 | |||
35 | #endif /* _ASM_A_OUT_H */ | ||
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 22fc19bbe87f..ca2e4026ad20 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/personality.h> | 22 | #include <linux/personality.h> |
23 | #include <linux/sys.h> | 23 | #include <linux/sys.h> |
24 | #include <linux/user.h> | 24 | #include <linux/user.h> |
25 | #include <linux/a.out.h> | ||
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/completion.h> | 26 | #include <linux/completion.h> |
28 | #include <linux/kallsyms.h> | 27 | #include <linux/kallsyms.h> |
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 343015a2f418..37970d9b2186 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
@@ -7,7 +7,6 @@ | |||
7 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 7 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
8 | * Copyright (C) 2001 MIPS Technologies, Inc. | 8 | * Copyright (C) 2001 MIPS Technologies, Inc. |
9 | */ | 9 | */ |
10 | #include <linux/a.out.h> | ||
11 | #include <linux/capability.h> | 10 | #include <linux/capability.h> |
12 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
13 | #include <linux/linkage.h> | 12 | #include <linux/linkage.h> |
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index e856218da90d..dd557c9cf001 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig | |||
@@ -53,9 +53,6 @@ config QUICKLIST | |||
53 | config ARCH_HAS_ILOG2_U32 | 53 | config ARCH_HAS_ILOG2_U32 |
54 | def_bool y | 54 | def_bool y |
55 | 55 | ||
56 | config ARCH_SUPPORTS_AOUT | ||
57 | def_bool n | ||
58 | |||
59 | # Use the generic interrupt handling code in kernel/irq/ | 56 | # Use the generic interrupt handling code in kernel/irq/ |
60 | config GENERIC_HARDIRQS | 57 | config GENERIC_HARDIRQS |
61 | def_bool y | 58 | def_bool y |
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index a7d4fd353c2b..8313fccced5e 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -76,9 +76,6 @@ config IRQ_PER_CPU | |||
76 | bool | 76 | bool |
77 | default y | 77 | default y |
78 | 78 | ||
79 | config ARCH_SUPPORTS_AOUT | ||
80 | def_bool y | ||
81 | |||
82 | # unless you want to implement ACPI on PA-RISC ... ;-) | 79 | # unless you want to implement ACPI on PA-RISC ... ;-) |
83 | config PM | 80 | config PM |
84 | bool | 81 | bool |
diff --git a/arch/powerpc/include/asm/a.out.h b/arch/powerpc/include/asm/a.out.h deleted file mode 100644 index 89cead6b176e..000000000000 --- a/arch/powerpc/include/asm/a.out.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef _ASM_POWERPC_A_OUT_H | ||
2 | #define _ASM_POWERPC_A_OUT_H | ||
3 | |||
4 | struct exec | ||
5 | { | ||
6 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
7 | unsigned a_text; /* length of text, in bytes */ | ||
8 | unsigned a_data; /* length of data, in bytes */ | ||
9 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
10 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
11 | unsigned a_entry; /* start address */ | ||
12 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
13 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
14 | }; | ||
15 | |||
16 | #define N_TRSIZE(a) ((a).a_trsize) | ||
17 | #define N_DRSIZE(a) ((a).a_drsize) | ||
18 | #define N_SYMSIZE(a) ((a).a_syms) | ||
19 | |||
20 | #endif /* _ASM_POWERPC_A_OUT_H */ | ||
diff --git a/arch/powerpc/include/asm/statfs.h b/arch/powerpc/include/asm/statfs.h index 67024026c10d..5244834583a4 100644 --- a/arch/powerpc/include/asm/statfs.h +++ b/arch/powerpc/include/asm/statfs.h | |||
@@ -1,60 +1,6 @@ | |||
1 | #ifndef _ASM_POWERPC_STATFS_H | 1 | #ifndef _ASM_POWERPC_STATFS_H |
2 | #define _ASM_POWERPC_STATFS_H | 2 | #define _ASM_POWERPC_STATFS_H |
3 | 3 | ||
4 | /* For ppc32 we just use the generic definitions, not so simple on ppc64 */ | ||
5 | |||
6 | #ifndef __powerpc64__ | ||
7 | #include <asm-generic/statfs.h> | 4 | #include <asm-generic/statfs.h> |
8 | #else | ||
9 | |||
10 | #ifndef __KERNEL_STRICT_NAMES | ||
11 | #include <linux/types.h> | ||
12 | typedef __kernel_fsid_t fsid_t; | ||
13 | #endif | ||
14 | |||
15 | /* | ||
16 | * We're already 64-bit, so duplicate the definition | ||
17 | */ | ||
18 | struct statfs { | ||
19 | long f_type; | ||
20 | long f_bsize; | ||
21 | long f_blocks; | ||
22 | long f_bfree; | ||
23 | long f_bavail; | ||
24 | long f_files; | ||
25 | long f_ffree; | ||
26 | __kernel_fsid_t f_fsid; | ||
27 | long f_namelen; | ||
28 | long f_frsize; | ||
29 | long f_spare[5]; | ||
30 | }; | ||
31 | |||
32 | struct statfs64 { | ||
33 | long f_type; | ||
34 | long f_bsize; | ||
35 | long f_blocks; | ||
36 | long f_bfree; | ||
37 | long f_bavail; | ||
38 | long f_files; | ||
39 | long f_ffree; | ||
40 | __kernel_fsid_t f_fsid; | ||
41 | long f_namelen; | ||
42 | long f_frsize; | ||
43 | long f_spare[5]; | ||
44 | }; | ||
45 | 5 | ||
46 | struct compat_statfs64 { | ||
47 | __u32 f_type; | ||
48 | __u32 f_bsize; | ||
49 | __u64 f_blocks; | ||
50 | __u64 f_bfree; | ||
51 | __u64 f_bavail; | ||
52 | __u64 f_files; | ||
53 | __u64 f_ffree; | ||
54 | __kernel_fsid_t f_fsid; | ||
55 | __u32 f_namelen; | ||
56 | __u32 f_frsize; | ||
57 | __u32 f_spare[5]; | ||
58 | }; | ||
59 | #endif /* ! __powerpc64__ */ | ||
60 | #endif | 6 | #endif |
diff --git a/arch/powerpc/kernel/softemu8xx.c b/arch/powerpc/kernel/softemu8xx.c index c906c4bf6835..23c8c5e7dc4d 100644 --- a/arch/powerpc/kernel/softemu8xx.c +++ b/arch/powerpc/kernel/softemu8xx.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/user.h> | 25 | #include <linux/user.h> |
26 | #include <linux/a.out.h> | ||
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
28 | 27 | ||
29 | #include <asm/pgtable.h> | 28 | #include <asm/pgtable.h> |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 81ccb8dd1a54..f5def6cf5cd6 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/user.h> | 25 | #include <linux/user.h> |
26 | #include <linux/a.out.h> | ||
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/module.h> | 28 | #include <linux/module.h> |
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 1ba7ce5aafae..272d79a8d289 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/user.h> | 19 | #include <linux/user.h> |
20 | #include <linux/a.out.h> | ||
21 | #include <linux/tty.h> | 20 | #include <linux/tty.h> |
22 | #include <linux/major.h> | 21 | #include <linux/major.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 364714757cf1..d4c61c3c9669 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/user.h> | 25 | #include <linux/user.h> |
26 | #include <linux/a.out.h> | ||
27 | #include <linux/tty.h> | 26 | #include <linux/tty.h> |
28 | #include <linux/string.h> | 27 | #include <linux/string.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 88ccf3a08a9c..82c14d203d8b 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/ptrace.h> | 33 | #include <linux/ptrace.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/user.h> | 35 | #include <linux/user.h> |
36 | #include <linux/a.out.h> | ||
37 | #include <linux/tty.h> | 36 | #include <linux/tty.h> |
38 | #include <linux/string.h> | 37 | #include <linux/string.h> |
39 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 7b01d67b4e48..ec341707e41b 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/unistd.h> | 25 | #include <linux/unistd.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/user.h> | 27 | #include <linux/user.h> |
28 | #include <linux/a.out.h> | ||
29 | #include <linux/tty.h> | 28 | #include <linux/tty.h> |
30 | #include <linux/major.h> | 29 | #include <linux/major.h> |
31 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
diff --git a/arch/s390/include/asm/statfs.h b/arch/s390/include/asm/statfs.h index 099a45579190..06cc70307ece 100644 --- a/arch/s390/include/asm/statfs.h +++ b/arch/s390/include/asm/statfs.h | |||
@@ -12,19 +12,16 @@ | |||
12 | #ifndef __s390x__ | 12 | #ifndef __s390x__ |
13 | #include <asm-generic/statfs.h> | 13 | #include <asm-generic/statfs.h> |
14 | #else | 14 | #else |
15 | /* | ||
16 | * We can't use <asm-generic/statfs.h> because in 64-bit mode | ||
17 | * we mix ints of different sizes in our struct statfs. | ||
18 | */ | ||
15 | 19 | ||
16 | #ifndef __KERNEL_STRICT_NAMES | 20 | #ifndef __KERNEL_STRICT_NAMES |
17 | |||
18 | #include <linux/types.h> | 21 | #include <linux/types.h> |
19 | |||
20 | typedef __kernel_fsid_t fsid_t; | 22 | typedef __kernel_fsid_t fsid_t; |
21 | |||
22 | #endif | 23 | #endif |
23 | 24 | ||
24 | /* | ||
25 | * This is ugly -- we're already 64-bit clean, so just duplicate the | ||
26 | * definitions. | ||
27 | */ | ||
28 | struct statfs { | 25 | struct statfs { |
29 | int f_type; | 26 | int f_type; |
30 | int f_bsize; | 27 | int f_bsize; |
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild index 2ba7183bc1f0..2d2769d766ec 100644 --- a/arch/sparc/include/asm/Kbuild +++ b/arch/sparc/include/asm/Kbuild | |||
@@ -15,8 +15,6 @@ header-y += signal_32.h | |||
15 | header-y += signal_64.h | 15 | header-y += signal_64.h |
16 | header-y += stat_32.h | 16 | header-y += stat_32.h |
17 | header-y += stat_64.h | 17 | header-y += stat_64.h |
18 | header-y += statfs_32.h | ||
19 | header-y += statfs_64.h | ||
20 | header-y += unistd_32.h | 18 | header-y += unistd_32.h |
21 | header-y += unistd_64.h | 19 | header-y += unistd_64.h |
22 | 20 | ||
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h new file mode 100644 index 000000000000..f90d61c28059 --- /dev/null +++ b/arch/sparc/include/asm/serial.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __SPARC_SERIAL_H | ||
2 | #define __SPARC_SERIAL_H | ||
3 | |||
4 | #define BASE_BAUD ( 1843200 / 16 ) | ||
5 | |||
6 | #endif /* __SPARC_SERIAL_H */ | ||
diff --git a/arch/sparc/include/asm/statfs.h b/arch/sparc/include/asm/statfs.h index 5e937a73743d..55e607ad461d 100644 --- a/arch/sparc/include/asm/statfs.h +++ b/arch/sparc/include/asm/statfs.h | |||
@@ -1,8 +1,6 @@ | |||
1 | #ifndef ___ASM_SPARC_STATFS_H | 1 | #ifndef ___ASM_SPARC_STATFS_H |
2 | #define ___ASM_SPARC_STATFS_H | 2 | #define ___ASM_SPARC_STATFS_H |
3 | #if defined(__sparc__) && defined(__arch64__) | 3 | |
4 | #include <asm/statfs_64.h> | 4 | #include <asm-generic/statfs.h> |
5 | #else | 5 | |
6 | #include <asm/statfs_32.h> | ||
7 | #endif | ||
8 | #endif | 6 | #endif |
diff --git a/arch/sparc/include/asm/statfs_32.h b/arch/sparc/include/asm/statfs_32.h deleted file mode 100644 index 304520fa8863..000000000000 --- a/arch/sparc/include/asm/statfs_32.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef _SPARC_STATFS_H | ||
2 | #define _SPARC_STATFS_H | ||
3 | |||
4 | #include <asm-generic/statfs.h> | ||
5 | |||
6 | #endif | ||
diff --git a/arch/sparc/include/asm/statfs_64.h b/arch/sparc/include/asm/statfs_64.h deleted file mode 100644 index 79b3c890a5fa..000000000000 --- a/arch/sparc/include/asm/statfs_64.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | #ifndef _SPARC64_STATFS_H | ||
2 | #define _SPARC64_STATFS_H | ||
3 | |||
4 | #ifndef __KERNEL_STRICT_NAMES | ||
5 | |||
6 | #include <linux/types.h> | ||
7 | |||
8 | typedef __kernel_fsid_t fsid_t; | ||
9 | |||
10 | #endif | ||
11 | |||
12 | struct statfs { | ||
13 | long f_type; | ||
14 | long f_bsize; | ||
15 | long f_blocks; | ||
16 | long f_bfree; | ||
17 | long f_bavail; | ||
18 | long f_files; | ||
19 | long f_ffree; | ||
20 | __kernel_fsid_t f_fsid; | ||
21 | long f_namelen; | ||
22 | long f_frsize; | ||
23 | long f_spare[5]; | ||
24 | }; | ||
25 | |||
26 | struct statfs64 { | ||
27 | long f_type; | ||
28 | long f_bsize; | ||
29 | long f_blocks; | ||
30 | long f_bfree; | ||
31 | long f_bavail; | ||
32 | long f_files; | ||
33 | long f_ffree; | ||
34 | __kernel_fsid_t f_fsid; | ||
35 | long f_namelen; | ||
36 | long f_frsize; | ||
37 | long f_spare[5]; | ||
38 | }; | ||
39 | |||
40 | struct compat_statfs64 { | ||
41 | __u32 f_type; | ||
42 | __u32 f_bsize; | ||
43 | __u64 f_blocks; | ||
44 | __u64 f_bfree; | ||
45 | __u64 f_bavail; | ||
46 | __u64 f_files; | ||
47 | __u64 f_ffree; | ||
48 | __kernel_fsid_t f_fsid; | ||
49 | __u32 f_namelen; | ||
50 | __u32 f_frsize; | ||
51 | __u32 f_spare[5]; | ||
52 | }; | ||
53 | |||
54 | #endif | ||
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 index e09edfa560da..1f57c113df6d 100644 --- a/arch/um/Kconfig.i386 +++ b/arch/um/Kconfig.i386 | |||
@@ -9,8 +9,9 @@ config UML_X86 | |||
9 | default y | 9 | default y |
10 | 10 | ||
11 | config X86_32 | 11 | config X86_32 |
12 | bool | 12 | bool |
13 | default y | 13 | default y |
14 | select HAVE_AOUT | ||
14 | 15 | ||
15 | config RWSEM_XCHGADD_ALGORITHM | 16 | config RWSEM_XCHGADD_ALGORITHM |
16 | def_bool y | 17 | def_bool y |
@@ -42,6 +43,3 @@ config ARCH_REUSE_HOST_VSYSCALL_AREA | |||
42 | config GENERIC_HWEIGHT | 43 | config GENERIC_HWEIGHT |
43 | bool | 44 | bool |
44 | default y | 45 | default y |
45 | |||
46 | config ARCH_SUPPORTS_AOUT | ||
47 | def_bool y | ||
diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64 index 5696e7b374b3..40b3407cfe16 100644 --- a/arch/um/Kconfig.x86_64 +++ b/arch/um/Kconfig.x86_64 | |||
@@ -37,6 +37,3 @@ config SMP_BROKEN | |||
37 | config GENERIC_HWEIGHT | 37 | config GENERIC_HWEIGHT |
38 | bool | 38 | bool |
39 | default y | 39 | default y |
40 | |||
41 | config ARCH_SUPPORTS_AOUT | ||
42 | def_bool y | ||
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index d741f35d7b3a..14a102e877d6 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -275,6 +275,8 @@ int line_ioctl(struct tty_struct *tty, struct file * file, | |||
275 | case TIOCGLTC: | 275 | case TIOCGLTC: |
276 | case TIOCSLTC: | 276 | case TIOCSLTC: |
277 | #endif | 277 | #endif |
278 | /* Note: these are out of date as we now have TCGETS2 etc but this | ||
279 | whole lot should probably go away */ | ||
278 | case TCGETS: | 280 | case TCGETS: |
279 | case TCSETSF: | 281 | case TCSETSF: |
280 | case TCSETSW: | 282 | case TCSETSW: |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fc8351f374fd..f65c2744d573 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -18,6 +18,7 @@ config X86_64 | |||
18 | ### Arch settings | 18 | ### Arch settings |
19 | config X86 | 19 | config X86 |
20 | def_bool y | 20 | def_bool y |
21 | select HAVE_AOUT if X86_32 | ||
21 | select HAVE_UNSTABLE_SCHED_CLOCK | 22 | select HAVE_UNSTABLE_SCHED_CLOCK |
22 | select HAVE_IDE | 23 | select HAVE_IDE |
23 | select HAVE_OPROFILE | 24 | select HAVE_OPROFILE |
@@ -152,9 +153,6 @@ config AUDIT_ARCH | |||
152 | bool | 153 | bool |
153 | default X86_64 | 154 | default X86_64 |
154 | 155 | ||
155 | config ARCH_SUPPORTS_AOUT | ||
156 | def_bool y | ||
157 | |||
158 | config ARCH_SUPPORTS_OPTIMIZED_INLINING | 156 | config ARCH_SUPPORTS_OPTIMIZED_INLINING |
159 | def_bool y | 157 | def_bool y |
160 | 158 | ||
@@ -1885,7 +1883,7 @@ config IA32_EMULATION | |||
1885 | 1883 | ||
1886 | config IA32_AOUT | 1884 | config IA32_AOUT |
1887 | tristate "IA32 a.out support" | 1885 | tristate "IA32 a.out support" |
1888 | depends on IA32_EMULATION && ARCH_SUPPORTS_AOUT | 1886 | depends on IA32_EMULATION |
1889 | help | 1887 | help |
1890 | Support old a.out binaries in the 32bit emulation. | 1888 | Support old a.out binaries in the 32bit emulation. |
1891 | 1889 | ||
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index c5f101360520..0b7c4a3f0651 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu | |||
@@ -38,8 +38,7 @@ config M386 | |||
38 | - "Crusoe" for the Transmeta Crusoe series. | 38 | - "Crusoe" for the Transmeta Crusoe series. |
39 | - "Efficeon" for the Transmeta Efficeon series. | 39 | - "Efficeon" for the Transmeta Efficeon series. |
40 | - "Winchip-C6" for original IDT Winchip. | 40 | - "Winchip-C6" for original IDT Winchip. |
41 | - "Winchip-2" for IDT Winchip 2. | 41 | - "Winchip-2" for IDT Winchips with 3dNow! capabilities. |
42 | - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. | ||
43 | - "GeodeGX1" for Geode GX1 (Cyrix MediaGX). | 42 | - "GeodeGX1" for Geode GX1 (Cyrix MediaGX). |
44 | - "Geode GX/LX" For AMD Geode GX and LX processors. | 43 | - "Geode GX/LX" For AMD Geode GX and LX processors. |
45 | - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3. | 44 | - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3. |
@@ -194,19 +193,11 @@ config MWINCHIPC6 | |||
194 | treat this chip as a 586TSC with some extended instructions | 193 | treat this chip as a 586TSC with some extended instructions |
195 | and alignment requirements. | 194 | and alignment requirements. |
196 | 195 | ||
197 | config MWINCHIP2 | ||
198 | bool "Winchip-2" | ||
199 | depends on X86_32 | ||
200 | help | ||
201 | Select this for an IDT Winchip-2. Linux and GCC | ||
202 | treat this chip as a 586TSC with some extended instructions | ||
203 | and alignment requirements. | ||
204 | |||
205 | config MWINCHIP3D | 196 | config MWINCHIP3D |
206 | bool "Winchip-2A/Winchip-3" | 197 | bool "Winchip-2/Winchip-2A/Winchip-3" |
207 | depends on X86_32 | 198 | depends on X86_32 |
208 | help | 199 | help |
209 | Select this for an IDT Winchip-2A or 3. Linux and GCC | 200 | Select this for an IDT Winchip-2, 2A or 3. Linux and GCC |
210 | treat this chip as a 586TSC with some extended instructions | 201 | treat this chip as a 586TSC with some extended instructions |
211 | and alignment requirements. Also enable out of order memory | 202 | and alignment requirements. Also enable out of order memory |
212 | stores for this CPU, which can increase performance of some | 203 | stores for this CPU, which can increase performance of some |
@@ -318,7 +309,7 @@ config X86_L1_CACHE_SHIFT | |||
318 | int | 309 | int |
319 | default "7" if MPENTIUM4 || X86_GENERIC || GENERIC_CPU || MPSC | 310 | default "7" if MPENTIUM4 || X86_GENERIC || GENERIC_CPU || MPSC |
320 | default "4" if X86_ELAN || M486 || M386 || MGEODEGX1 | 311 | default "4" if X86_ELAN || M486 || M386 || MGEODEGX1 |
321 | default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX | 312 | default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX |
322 | default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7 | 313 | default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7 |
323 | 314 | ||
324 | config X86_XADD | 315 | config X86_XADD |
@@ -360,7 +351,7 @@ config X86_POPAD_OK | |||
360 | 351 | ||
361 | config X86_ALIGNMENT_16 | 352 | config X86_ALIGNMENT_16 |
362 | def_bool y | 353 | def_bool y |
363 | depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 | 354 | depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 |
364 | 355 | ||
365 | config X86_INTEL_USERCOPY | 356 | config X86_INTEL_USERCOPY |
366 | def_bool y | 357 | def_bool y |
@@ -368,7 +359,7 @@ config X86_INTEL_USERCOPY | |||
368 | 359 | ||
369 | config X86_USE_PPRO_CHECKSUM | 360 | config X86_USE_PPRO_CHECKSUM |
370 | def_bool y | 361 | def_bool y |
371 | depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 | 362 | depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 |
372 | 363 | ||
373 | config X86_USE_3DNOW | 364 | config X86_USE_3DNOW |
374 | def_bool y | 365 | def_bool y |
@@ -376,7 +367,7 @@ config X86_USE_3DNOW | |||
376 | 367 | ||
377 | config X86_OOSTORE | 368 | config X86_OOSTORE |
378 | def_bool y | 369 | def_bool y |
379 | depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR | 370 | depends on (MWINCHIP3D || MWINCHIPC6) && MTRR |
380 | 371 | ||
381 | # | 372 | # |
382 | # P6_NOPs are a relatively minor optimization that require a family >= | 373 | # P6_NOPs are a relatively minor optimization that require a family >= |
@@ -396,7 +387,7 @@ config X86_P6_NOP | |||
396 | 387 | ||
397 | config X86_TSC | 388 | config X86_TSC |
398 | def_bool y | 389 | def_bool y |
399 | depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64 | 390 | depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64 |
400 | 391 | ||
401 | config X86_CMPXCHG64 | 392 | config X86_CMPXCHG64 |
402 | def_bool y | 393 | def_bool y |
@@ -406,7 +397,7 @@ config X86_CMPXCHG64 | |||
406 | # generates cmov. | 397 | # generates cmov. |
407 | config X86_CMOV | 398 | config X86_CMOV |
408 | def_bool y | 399 | def_bool y |
409 | depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64) | 400 | depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64) |
410 | 401 | ||
411 | config X86_MINIMUM_CPU_FAMILY | 402 | config X86_MINIMUM_CPU_FAMILY |
412 | int | 403 | int |
@@ -417,7 +408,7 @@ config X86_MINIMUM_CPU_FAMILY | |||
417 | 408 | ||
418 | config X86_DEBUGCTLMSR | 409 | config X86_DEBUGCTLMSR |
419 | def_bool y | 410 | def_bool y |
420 | depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) | 411 | depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) |
421 | 412 | ||
422 | menuconfig PROCESSOR_SELECT | 413 | menuconfig PROCESSOR_SELECT |
423 | bool "Supported processor vendors" if EMBEDDED | 414 | bool "Supported processor vendors" if EMBEDDED |
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index b72b4f753113..80177ec052f0 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu | |||
@@ -28,7 +28,6 @@ cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,-march=athlon) | |||
28 | cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 | 28 | cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 |
29 | cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 | 29 | cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 |
30 | cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) | 30 | cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) |
31 | cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586) | ||
32 | cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586) | 31 | cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586) |
33 | cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 | 32 | cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 |
34 | cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) | 33 | cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) |
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index ca226ca31288..52d0359719d7 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig | |||
@@ -213,7 +213,6 @@ CONFIG_M686=y | |||
213 | # CONFIG_MCRUSOE is not set | 213 | # CONFIG_MCRUSOE is not set |
214 | # CONFIG_MEFFICEON is not set | 214 | # CONFIG_MEFFICEON is not set |
215 | # CONFIG_MWINCHIPC6 is not set | 215 | # CONFIG_MWINCHIPC6 is not set |
216 | # CONFIG_MWINCHIP2 is not set | ||
217 | # CONFIG_MWINCHIP3D is not set | 216 | # CONFIG_MWINCHIP3D is not set |
218 | # CONFIG_MGEODEGX1 is not set | 217 | # CONFIG_MGEODEGX1 is not set |
219 | # CONFIG_MGEODE_LX is not set | 218 | # CONFIG_MGEODE_LX is not set |
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 2c4b1c771e28..f0a03d7a7d63 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig | |||
@@ -210,7 +210,6 @@ CONFIG_X86_PC=y | |||
210 | # CONFIG_MCRUSOE is not set | 210 | # CONFIG_MCRUSOE is not set |
211 | # CONFIG_MEFFICEON is not set | 211 | # CONFIG_MEFFICEON is not set |
212 | # CONFIG_MWINCHIPC6 is not set | 212 | # CONFIG_MWINCHIPC6 is not set |
213 | # CONFIG_MWINCHIP2 is not set | ||
214 | # CONFIG_MWINCHIP3D is not set | 213 | # CONFIG_MWINCHIP3D is not set |
215 | # CONFIG_MGEODEGX1 is not set | 214 | # CONFIG_MGEODEGX1 is not set |
216 | # CONFIG_MGEODE_LX is not set | 215 | # CONFIG_MGEODE_LX is not set |
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index ffc1bb4fed7d..eb4314768bf7 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S | |||
@@ -39,11 +39,11 @@ | |||
39 | .endm | 39 | .endm |
40 | 40 | ||
41 | /* clobbers %eax */ | 41 | /* clobbers %eax */ |
42 | .macro CLEAR_RREGS | 42 | .macro CLEAR_RREGS _r9=rax |
43 | xorl %eax,%eax | 43 | xorl %eax,%eax |
44 | movq %rax,R11(%rsp) | 44 | movq %rax,R11(%rsp) |
45 | movq %rax,R10(%rsp) | 45 | movq %rax,R10(%rsp) |
46 | movq %rax,R9(%rsp) | 46 | movq %\_r9,R9(%rsp) |
47 | movq %rax,R8(%rsp) | 47 | movq %rax,R8(%rsp) |
48 | .endm | 48 | .endm |
49 | 49 | ||
@@ -52,11 +52,10 @@ | |||
52 | * We don't reload %eax because syscall_trace_enter() returned | 52 | * We don't reload %eax because syscall_trace_enter() returned |
53 | * the value it wants us to use in the table lookup. | 53 | * the value it wants us to use in the table lookup. |
54 | */ | 54 | */ |
55 | .macro LOAD_ARGS32 offset | 55 | .macro LOAD_ARGS32 offset, _r9=0 |
56 | movl \offset(%rsp),%r11d | 56 | .if \_r9 |
57 | movl \offset+8(%rsp),%r10d | ||
58 | movl \offset+16(%rsp),%r9d | 57 | movl \offset+16(%rsp),%r9d |
59 | movl \offset+24(%rsp),%r8d | 58 | .endif |
60 | movl \offset+40(%rsp),%ecx | 59 | movl \offset+40(%rsp),%ecx |
61 | movl \offset+48(%rsp),%edx | 60 | movl \offset+48(%rsp),%edx |
62 | movl \offset+56(%rsp),%esi | 61 | movl \offset+56(%rsp),%esi |
@@ -145,7 +144,7 @@ ENTRY(ia32_sysenter_target) | |||
145 | SAVE_ARGS 0,0,1 | 144 | SAVE_ARGS 0,0,1 |
146 | /* no need to do an access_ok check here because rbp has been | 145 | /* no need to do an access_ok check here because rbp has been |
147 | 32bit zero extended */ | 146 | 32bit zero extended */ |
148 | 1: movl (%rbp),%r9d | 147 | 1: movl (%rbp),%ebp |
149 | .section __ex_table,"a" | 148 | .section __ex_table,"a" |
150 | .quad 1b,ia32_badarg | 149 | .quad 1b,ia32_badarg |
151 | .previous | 150 | .previous |
@@ -157,7 +156,7 @@ ENTRY(ia32_sysenter_target) | |||
157 | cmpl $(IA32_NR_syscalls-1),%eax | 156 | cmpl $(IA32_NR_syscalls-1),%eax |
158 | ja ia32_badsys | 157 | ja ia32_badsys |
159 | sysenter_do_call: | 158 | sysenter_do_call: |
160 | IA32_ARG_FIXUP 1 | 159 | IA32_ARG_FIXUP |
161 | sysenter_dispatch: | 160 | sysenter_dispatch: |
162 | call *ia32_sys_call_table(,%rax,8) | 161 | call *ia32_sys_call_table(,%rax,8) |
163 | movq %rax,RAX-ARGOFFSET(%rsp) | 162 | movq %rax,RAX-ARGOFFSET(%rsp) |
@@ -234,20 +233,17 @@ sysexit_audit: | |||
234 | #endif | 233 | #endif |
235 | 234 | ||
236 | sysenter_tracesys: | 235 | sysenter_tracesys: |
237 | xchgl %r9d,%ebp | ||
238 | #ifdef CONFIG_AUDITSYSCALL | 236 | #ifdef CONFIG_AUDITSYSCALL |
239 | testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10) | 237 | testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10) |
240 | jz sysenter_auditsys | 238 | jz sysenter_auditsys |
241 | #endif | 239 | #endif |
242 | SAVE_REST | 240 | SAVE_REST |
243 | CLEAR_RREGS | 241 | CLEAR_RREGS |
244 | movq %r9,R9(%rsp) | ||
245 | movq $-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */ | 242 | movq $-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */ |
246 | movq %rsp,%rdi /* &pt_regs -> arg1 */ | 243 | movq %rsp,%rdi /* &pt_regs -> arg1 */ |
247 | call syscall_trace_enter | 244 | call syscall_trace_enter |
248 | LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ | 245 | LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ |
249 | RESTORE_REST | 246 | RESTORE_REST |
250 | xchgl %ebp,%r9d | ||
251 | cmpl $(IA32_NR_syscalls-1),%eax | 247 | cmpl $(IA32_NR_syscalls-1),%eax |
252 | ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */ | 248 | ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */ |
253 | jmp sysenter_do_call | 249 | jmp sysenter_do_call |
@@ -314,9 +310,9 @@ ENTRY(ia32_cstar_target) | |||
314 | testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) | 310 | testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) |
315 | CFI_REMEMBER_STATE | 311 | CFI_REMEMBER_STATE |
316 | jnz cstar_tracesys | 312 | jnz cstar_tracesys |
317 | cstar_do_call: | ||
318 | cmpl $IA32_NR_syscalls-1,%eax | 313 | cmpl $IA32_NR_syscalls-1,%eax |
319 | ja ia32_badsys | 314 | ja ia32_badsys |
315 | cstar_do_call: | ||
320 | IA32_ARG_FIXUP 1 | 316 | IA32_ARG_FIXUP 1 |
321 | cstar_dispatch: | 317 | cstar_dispatch: |
322 | call *ia32_sys_call_table(,%rax,8) | 318 | call *ia32_sys_call_table(,%rax,8) |
@@ -357,15 +353,13 @@ cstar_tracesys: | |||
357 | #endif | 353 | #endif |
358 | xchgl %r9d,%ebp | 354 | xchgl %r9d,%ebp |
359 | SAVE_REST | 355 | SAVE_REST |
360 | CLEAR_RREGS | 356 | CLEAR_RREGS r9 |
361 | movq %r9,R9(%rsp) | ||
362 | movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */ | 357 | movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */ |
363 | movq %rsp,%rdi /* &pt_regs -> arg1 */ | 358 | movq %rsp,%rdi /* &pt_regs -> arg1 */ |
364 | call syscall_trace_enter | 359 | call syscall_trace_enter |
365 | LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ | 360 | LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */ |
366 | RESTORE_REST | 361 | RESTORE_REST |
367 | xchgl %ebp,%r9d | 362 | xchgl %ebp,%r9d |
368 | movl RSP-ARGOFFSET(%rsp), %r8d | ||
369 | cmpl $(IA32_NR_syscalls-1),%eax | 363 | cmpl $(IA32_NR_syscalls-1),%eax |
370 | ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */ | 364 | ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */ |
371 | jmp cstar_do_call | 365 | jmp cstar_do_call |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 5098585f87ce..0d41f0343dc0 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -23,7 +23,7 @@ CFLAGS_hpet.o := $(nostackp) | |||
23 | CFLAGS_tsc.o := $(nostackp) | 23 | CFLAGS_tsc.o := $(nostackp) |
24 | 24 | ||
25 | obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o | 25 | obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o |
26 | obj-y += traps_$(BITS).o irq_$(BITS).o | 26 | obj-y += traps.o irq_$(BITS).o dumpstack_$(BITS).o |
27 | obj-y += time_$(BITS).o ioport.o ldt.o | 27 | obj-y += time_$(BITS).o ioport.o ldt.o |
28 | obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o | 28 | obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o |
29 | obj-$(CONFIG_X86_VISWS) += visws_quirks.o | 29 | obj-$(CONFIG_X86_VISWS) += visws_quirks.o |
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index fb04e49776ba..a84ac7b570e6 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -444,7 +444,7 @@ void __init alternative_instructions(void) | |||
444 | _text, _etext); | 444 | _text, _etext); |
445 | 445 | ||
446 | /* Only switch to UP mode if we don't immediately boot others */ | 446 | /* Only switch to UP mode if we don't immediately boot others */ |
447 | if (num_possible_cpus() == 1 || setup_max_cpus <= 1) | 447 | if (num_present_cpus() == 1 || setup_max_cpus <= 1) |
448 | alternatives_smp_switch(0); | 448 | alternatives_smp_switch(0); |
449 | } | 449 | } |
450 | #endif | 450 | #endif |
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index a91c57cb666a..21c831d96af3 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
@@ -295,6 +295,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | |||
295 | * | 295 | * |
296 | * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and | 296 | * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and |
297 | * MCE interrupts are supported. Thus MCE offset must be set to 0. | 297 | * MCE interrupts are supported. Thus MCE offset must be set to 0. |
298 | * | ||
299 | * If mask=1, the LVT entry does not generate interrupts while mask=0 | ||
300 | * enables the vector. See also the BKDGs. | ||
298 | */ | 301 | */ |
299 | 302 | ||
300 | #define APIC_EILVT_LVTOFF_MCE 0 | 303 | #define APIC_EILVT_LVTOFF_MCE 0 |
@@ -319,6 +322,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask) | |||
319 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); | 322 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); |
320 | return APIC_EILVT_LVTOFF_IBS; | 323 | return APIC_EILVT_LVTOFF_IBS; |
321 | } | 324 | } |
325 | EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs); | ||
322 | 326 | ||
323 | /* | 327 | /* |
324 | * Program the next event, relative to now | 328 | * Program the next event, relative to now |
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 53898b65a6ae..94ddb69ae15e 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c | |||
@@ -307,6 +307,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | |||
307 | * | 307 | * |
308 | * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and | 308 | * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and |
309 | * MCE interrupts are supported. Thus MCE offset must be set to 0. | 309 | * MCE interrupts are supported. Thus MCE offset must be set to 0. |
310 | * | ||
311 | * If mask=1, the LVT entry does not generate interrupts while mask=0 | ||
312 | * enables the vector. See also the BKDGs. | ||
310 | */ | 313 | */ |
311 | 314 | ||
312 | #define APIC_EILVT_LVTOFF_MCE 0 | 315 | #define APIC_EILVT_LVTOFF_MCE 0 |
@@ -331,6 +334,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask) | |||
331 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); | 334 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); |
332 | return APIC_EILVT_LVTOFF_IBS; | 335 | return APIC_EILVT_LVTOFF_IBS; |
333 | } | 336 | } |
337 | EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs); | ||
334 | 338 | ||
335 | /* | 339 | /* |
336 | * Program the next event, relative to now | 340 | * Program the next event, relative to now |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index fb789dd9e691..25581dcb280e 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -124,18 +124,25 @@ static inline int flag_is_changeable_p(u32 flag) | |||
124 | { | 124 | { |
125 | u32 f1, f2; | 125 | u32 f1, f2; |
126 | 126 | ||
127 | asm("pushfl\n\t" | 127 | /* |
128 | "pushfl\n\t" | 128 | * Cyrix and IDT cpus allow disabling of CPUID |
129 | "popl %0\n\t" | 129 | * so the code below may return different results |
130 | "movl %0,%1\n\t" | 130 | * when it is executed before and after enabling |
131 | "xorl %2,%0\n\t" | 131 | * the CPUID. Add "volatile" to not allow gcc to |
132 | "pushl %0\n\t" | 132 | * optimize the subsequent calls to this function. |
133 | "popfl\n\t" | 133 | */ |
134 | "pushfl\n\t" | 134 | asm volatile ("pushfl\n\t" |
135 | "popl %0\n\t" | 135 | "pushfl\n\t" |
136 | "popfl\n\t" | 136 | "popl %0\n\t" |
137 | : "=&r" (f1), "=&r" (f2) | 137 | "movl %0,%1\n\t" |
138 | : "ir" (flag)); | 138 | "xorl %2,%0\n\t" |
139 | "pushl %0\n\t" | ||
140 | "popfl\n\t" | ||
141 | "pushfl\n\t" | ||
142 | "popl %0\n\t" | ||
143 | "popfl\n\t" | ||
144 | : "=&r" (f1), "=&r" (f2) | ||
145 | : "ir" (flag)); | ||
139 | 146 | ||
140 | return ((f1^f2) & flag) != 0; | 147 | return ((f1^f2) & flag) != 0; |
141 | } | 148 | } |
@@ -719,12 +726,24 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) | |||
719 | #endif | 726 | #endif |
720 | } | 727 | } |
721 | 728 | ||
729 | #ifdef CONFIG_X86_64 | ||
730 | static void vgetcpu_set_mode(void) | ||
731 | { | ||
732 | if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) | ||
733 | vgetcpu_mode = VGETCPU_RDTSCP; | ||
734 | else | ||
735 | vgetcpu_mode = VGETCPU_LSL; | ||
736 | } | ||
737 | #endif | ||
738 | |||
722 | void __init identify_boot_cpu(void) | 739 | void __init identify_boot_cpu(void) |
723 | { | 740 | { |
724 | identify_cpu(&boot_cpu_data); | 741 | identify_cpu(&boot_cpu_data); |
725 | #ifdef CONFIG_X86_32 | 742 | #ifdef CONFIG_X86_32 |
726 | sysenter_setup(); | 743 | sysenter_setup(); |
727 | enable_sep_cpu(); | 744 | enable_sep_cpu(); |
745 | #else | ||
746 | vgetcpu_set_mode(); | ||
728 | #endif | 747 | #endif |
729 | } | 748 | } |
730 | 749 | ||
@@ -797,7 +816,7 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) | |||
797 | else if (c->cpuid_level >= 0) | 816 | else if (c->cpuid_level >= 0) |
798 | vendor = c->x86_vendor_id; | 817 | vendor = c->x86_vendor_id; |
799 | 818 | ||
800 | if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) | 819 | if (vendor && !strstr(c->x86_model_id, vendor)) |
801 | printk(KERN_CONT "%s ", vendor); | 820 | printk(KERN_CONT "%s ", vendor); |
802 | 821 | ||
803 | if (c->x86_model_id[0]) | 822 | if (c->x86_model_id[0]) |
diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c index 395acb12b0d1..b4f14c6c09d9 100644 --- a/arch/x86/kernel/doublefault_32.c +++ b/arch/x86/kernel/doublefault_32.c | |||
@@ -66,6 +66,6 @@ struct tss_struct doublefault_tss __cacheline_aligned = { | |||
66 | .ds = __USER_DS, | 66 | .ds = __USER_DS, |
67 | .fs = __KERNEL_PERCPU, | 67 | .fs = __KERNEL_PERCPU, |
68 | 68 | ||
69 | .__cr3 = __phys_addr_const((unsigned long)swapper_pg_dir) | 69 | .__cr3 = __pa_nodebug(swapper_pg_dir), |
70 | } | 70 | } |
71 | }; | 71 | }; |
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c new file mode 100644 index 000000000000..201ee359a1a9 --- /dev/null +++ b/arch/x86/kernel/dumpstack_32.c | |||
@@ -0,0 +1,447 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
4 | */ | ||
5 | #include <linux/kallsyms.h> | ||
6 | #include <linux/kprobes.h> | ||
7 | #include <linux/uaccess.h> | ||
8 | #include <linux/utsname.h> | ||
9 | #include <linux/hardirq.h> | ||
10 | #include <linux/kdebug.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/kexec.h> | ||
14 | #include <linux/bug.h> | ||
15 | #include <linux/nmi.h> | ||
16 | |||
17 | #include <asm/stacktrace.h> | ||
18 | |||
19 | #define STACKSLOTS_PER_LINE 8 | ||
20 | #define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :) | ||
21 | |||
22 | int panic_on_unrecovered_nmi; | ||
23 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | ||
24 | static unsigned int code_bytes = 64; | ||
25 | static int die_counter; | ||
26 | |||
27 | void printk_address(unsigned long address, int reliable) | ||
28 | { | ||
29 | printk(" [<%p>] %s%pS\n", (void *) address, | ||
30 | reliable ? "" : "? ", (void *) address); | ||
31 | } | ||
32 | |||
33 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
34 | void *p, unsigned int size, void *end) | ||
35 | { | ||
36 | void *t = tinfo; | ||
37 | if (end) { | ||
38 | if (p < end && p >= (end-THREAD_SIZE)) | ||
39 | return 1; | ||
40 | else | ||
41 | return 0; | ||
42 | } | ||
43 | return p > t && p < t + THREAD_SIZE - size; | ||
44 | } | ||
45 | |||
46 | /* The form of the top of the frame on the stack */ | ||
47 | struct stack_frame { | ||
48 | struct stack_frame *next_frame; | ||
49 | unsigned long return_address; | ||
50 | }; | ||
51 | |||
52 | static inline unsigned long | ||
53 | print_context_stack(struct thread_info *tinfo, | ||
54 | unsigned long *stack, unsigned long bp, | ||
55 | const struct stacktrace_ops *ops, void *data, | ||
56 | unsigned long *end) | ||
57 | { | ||
58 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
59 | |||
60 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { | ||
61 | unsigned long addr; | ||
62 | |||
63 | addr = *stack; | ||
64 | if (__kernel_text_address(addr)) { | ||
65 | if ((unsigned long) stack == bp + sizeof(long)) { | ||
66 | ops->address(data, addr, 1); | ||
67 | frame = frame->next_frame; | ||
68 | bp = (unsigned long) frame; | ||
69 | } else { | ||
70 | ops->address(data, addr, bp == 0); | ||
71 | } | ||
72 | } | ||
73 | stack++; | ||
74 | } | ||
75 | return bp; | ||
76 | } | ||
77 | |||
78 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
79 | unsigned long *stack, unsigned long bp, | ||
80 | const struct stacktrace_ops *ops, void *data) | ||
81 | { | ||
82 | if (!task) | ||
83 | task = current; | ||
84 | |||
85 | if (!stack) { | ||
86 | unsigned long dummy; | ||
87 | stack = &dummy; | ||
88 | if (task && task != current) | ||
89 | stack = (unsigned long *)task->thread.sp; | ||
90 | } | ||
91 | |||
92 | #ifdef CONFIG_FRAME_POINTER | ||
93 | if (!bp) { | ||
94 | if (task == current) { | ||
95 | /* Grab bp right from our regs */ | ||
96 | get_bp(bp); | ||
97 | } else { | ||
98 | /* bp is the last reg pushed by switch_to */ | ||
99 | bp = *(unsigned long *) task->thread.sp; | ||
100 | } | ||
101 | } | ||
102 | #endif | ||
103 | |||
104 | for (;;) { | ||
105 | struct thread_info *context; | ||
106 | |||
107 | context = (struct thread_info *) | ||
108 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | ||
109 | bp = print_context_stack(context, stack, bp, ops, data, NULL); | ||
110 | |||
111 | stack = (unsigned long *)context->previous_esp; | ||
112 | if (!stack) | ||
113 | break; | ||
114 | if (ops->stack(data, "IRQ") < 0) | ||
115 | break; | ||
116 | touch_nmi_watchdog(); | ||
117 | } | ||
118 | } | ||
119 | EXPORT_SYMBOL(dump_trace); | ||
120 | |||
121 | static void | ||
122 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
123 | { | ||
124 | printk(data); | ||
125 | print_symbol(msg, symbol); | ||
126 | printk("\n"); | ||
127 | } | ||
128 | |||
129 | static void print_trace_warning(void *data, char *msg) | ||
130 | { | ||
131 | printk("%s%s\n", (char *)data, msg); | ||
132 | } | ||
133 | |||
134 | static int print_trace_stack(void *data, char *name) | ||
135 | { | ||
136 | printk("%s <%s> ", (char *)data, name); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Print one address/symbol entries per line. | ||
142 | */ | ||
143 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
144 | { | ||
145 | touch_nmi_watchdog(); | ||
146 | printk(data); | ||
147 | printk_address(addr, reliable); | ||
148 | } | ||
149 | |||
150 | static const struct stacktrace_ops print_trace_ops = { | ||
151 | .warning = print_trace_warning, | ||
152 | .warning_symbol = print_trace_warning_symbol, | ||
153 | .stack = print_trace_stack, | ||
154 | .address = print_trace_address, | ||
155 | }; | ||
156 | |||
157 | static void | ||
158 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
159 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
160 | { | ||
161 | printk("%sCall Trace:\n", log_lvl); | ||
162 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | ||
163 | } | ||
164 | |||
165 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
166 | unsigned long *stack, unsigned long bp) | ||
167 | { | ||
168 | show_trace_log_lvl(task, regs, stack, bp, ""); | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
173 | unsigned long *sp, unsigned long bp, char *log_lvl) | ||
174 | { | ||
175 | unsigned long *stack; | ||
176 | int i; | ||
177 | |||
178 | if (sp == NULL) { | ||
179 | if (task) | ||
180 | sp = (unsigned long *)task->thread.sp; | ||
181 | else | ||
182 | sp = (unsigned long *)&sp; | ||
183 | } | ||
184 | |||
185 | stack = sp; | ||
186 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
187 | if (kstack_end(stack)) | ||
188 | break; | ||
189 | if (i && ((i % STACKSLOTS_PER_LINE) == 0)) | ||
190 | printk("\n%s", log_lvl); | ||
191 | printk(" %08lx", *stack++); | ||
192 | touch_nmi_watchdog(); | ||
193 | } | ||
194 | printk("\n"); | ||
195 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | ||
196 | } | ||
197 | |||
198 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
199 | { | ||
200 | show_stack_log_lvl(task, NULL, sp, 0, ""); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * The architecture-independent dump_stack generator | ||
205 | */ | ||
206 | void dump_stack(void) | ||
207 | { | ||
208 | unsigned long bp = 0; | ||
209 | unsigned long stack; | ||
210 | |||
211 | #ifdef CONFIG_FRAME_POINTER | ||
212 | if (!bp) | ||
213 | get_bp(bp); | ||
214 | #endif | ||
215 | |||
216 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
217 | current->pid, current->comm, print_tainted(), | ||
218 | init_utsname()->release, | ||
219 | (int)strcspn(init_utsname()->version, " "), | ||
220 | init_utsname()->version); | ||
221 | show_trace(NULL, NULL, &stack, bp); | ||
222 | } | ||
223 | |||
224 | EXPORT_SYMBOL(dump_stack); | ||
225 | |||
226 | void show_registers(struct pt_regs *regs) | ||
227 | { | ||
228 | int i; | ||
229 | |||
230 | print_modules(); | ||
231 | __show_regs(regs, 0); | ||
232 | |||
233 | printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n", | ||
234 | TASK_COMM_LEN, current->comm, task_pid_nr(current), | ||
235 | current_thread_info(), current, task_thread_info(current)); | ||
236 | /* | ||
237 | * When in-kernel, we also print out the stack and code at the | ||
238 | * time of the fault.. | ||
239 | */ | ||
240 | if (!user_mode_vm(regs)) { | ||
241 | unsigned int code_prologue = code_bytes * 43 / 64; | ||
242 | unsigned int code_len = code_bytes; | ||
243 | unsigned char c; | ||
244 | u8 *ip; | ||
245 | |||
246 | printk(KERN_EMERG "Stack:\n"); | ||
247 | show_stack_log_lvl(NULL, regs, ®s->sp, | ||
248 | 0, KERN_EMERG); | ||
249 | |||
250 | printk(KERN_EMERG "Code: "); | ||
251 | |||
252 | ip = (u8 *)regs->ip - code_prologue; | ||
253 | if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { | ||
254 | /* try starting at IP */ | ||
255 | ip = (u8 *)regs->ip; | ||
256 | code_len = code_len - code_prologue + 1; | ||
257 | } | ||
258 | for (i = 0; i < code_len; i++, ip++) { | ||
259 | if (ip < (u8 *)PAGE_OFFSET || | ||
260 | probe_kernel_address(ip, c)) { | ||
261 | printk(" Bad EIP value."); | ||
262 | break; | ||
263 | } | ||
264 | if (ip == (u8 *)regs->ip) | ||
265 | printk("<%02x> ", c); | ||
266 | else | ||
267 | printk("%02x ", c); | ||
268 | } | ||
269 | } | ||
270 | printk("\n"); | ||
271 | } | ||
272 | |||
273 | int is_valid_bugaddr(unsigned long ip) | ||
274 | { | ||
275 | unsigned short ud2; | ||
276 | |||
277 | if (ip < PAGE_OFFSET) | ||
278 | return 0; | ||
279 | if (probe_kernel_address((unsigned short *)ip, ud2)) | ||
280 | return 0; | ||
281 | |||
282 | return ud2 == 0x0b0f; | ||
283 | } | ||
284 | |||
285 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
286 | static int die_owner = -1; | ||
287 | static unsigned int die_nest_count; | ||
288 | |||
289 | unsigned __kprobes long oops_begin(void) | ||
290 | { | ||
291 | unsigned long flags; | ||
292 | |||
293 | oops_enter(); | ||
294 | |||
295 | if (die_owner != raw_smp_processor_id()) { | ||
296 | console_verbose(); | ||
297 | raw_local_irq_save(flags); | ||
298 | __raw_spin_lock(&die_lock); | ||
299 | die_owner = smp_processor_id(); | ||
300 | die_nest_count = 0; | ||
301 | bust_spinlocks(1); | ||
302 | } else { | ||
303 | raw_local_irq_save(flags); | ||
304 | } | ||
305 | die_nest_count++; | ||
306 | return flags; | ||
307 | } | ||
308 | |||
309 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
310 | { | ||
311 | bust_spinlocks(0); | ||
312 | die_owner = -1; | ||
313 | add_taint(TAINT_DIE); | ||
314 | __raw_spin_unlock(&die_lock); | ||
315 | raw_local_irq_restore(flags); | ||
316 | |||
317 | if (!regs) | ||
318 | return; | ||
319 | |||
320 | if (kexec_should_crash(current)) | ||
321 | crash_kexec(regs); | ||
322 | if (in_interrupt()) | ||
323 | panic("Fatal exception in interrupt"); | ||
324 | if (panic_on_oops) | ||
325 | panic("Fatal exception"); | ||
326 | oops_exit(); | ||
327 | do_exit(signr); | ||
328 | } | ||
329 | |||
330 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
331 | { | ||
332 | unsigned short ss; | ||
333 | unsigned long sp; | ||
334 | |||
335 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | ||
336 | #ifdef CONFIG_PREEMPT | ||
337 | printk("PREEMPT "); | ||
338 | #endif | ||
339 | #ifdef CONFIG_SMP | ||
340 | printk("SMP "); | ||
341 | #endif | ||
342 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
343 | printk("DEBUG_PAGEALLOC"); | ||
344 | #endif | ||
345 | printk("\n"); | ||
346 | if (notify_die(DIE_OOPS, str, regs, err, | ||
347 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
348 | return 1; | ||
349 | |||
350 | show_registers(regs); | ||
351 | /* Executive summary in case the oops scrolled away */ | ||
352 | sp = (unsigned long) (®s->sp); | ||
353 | savesegment(ss, ss); | ||
354 | if (user_mode(regs)) { | ||
355 | sp = regs->sp; | ||
356 | ss = regs->ss & 0xffff; | ||
357 | } | ||
358 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | ||
359 | print_symbol("%s", regs->ip); | ||
360 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * This is gone through when something in the kernel has done something bad | ||
366 | * and is about to be terminated: | ||
367 | */ | ||
368 | void die(const char *str, struct pt_regs *regs, long err) | ||
369 | { | ||
370 | unsigned long flags = oops_begin(); | ||
371 | |||
372 | if (die_nest_count < 3) { | ||
373 | report_bug(regs->ip, regs); | ||
374 | |||
375 | if (__die(str, regs, err)) | ||
376 | regs = NULL; | ||
377 | } else { | ||
378 | printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); | ||
379 | } | ||
380 | |||
381 | oops_end(flags, regs, SIGSEGV); | ||
382 | } | ||
383 | |||
384 | static DEFINE_SPINLOCK(nmi_print_lock); | ||
385 | |||
386 | void notrace __kprobes | ||
387 | die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
388 | { | ||
389 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
390 | return; | ||
391 | |||
392 | spin_lock(&nmi_print_lock); | ||
393 | /* | ||
394 | * We are in trouble anyway, lets at least try | ||
395 | * to get a message out: | ||
396 | */ | ||
397 | bust_spinlocks(1); | ||
398 | printk(KERN_EMERG "%s", str); | ||
399 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
400 | smp_processor_id(), regs->ip); | ||
401 | show_registers(regs); | ||
402 | if (do_panic) | ||
403 | panic("Non maskable interrupt"); | ||
404 | console_silent(); | ||
405 | spin_unlock(&nmi_print_lock); | ||
406 | bust_spinlocks(0); | ||
407 | |||
408 | /* | ||
409 | * If we are in kernel we are probably nested up pretty bad | ||
410 | * and might aswell get out now while we still can: | ||
411 | */ | ||
412 | if (!user_mode_vm(regs)) { | ||
413 | current->thread.trap_no = 2; | ||
414 | crash_kexec(regs); | ||
415 | } | ||
416 | |||
417 | do_exit(SIGSEGV); | ||
418 | } | ||
419 | |||
420 | static int __init oops_setup(char *s) | ||
421 | { | ||
422 | if (!s) | ||
423 | return -EINVAL; | ||
424 | if (!strcmp(s, "panic")) | ||
425 | panic_on_oops = 1; | ||
426 | return 0; | ||
427 | } | ||
428 | early_param("oops", oops_setup); | ||
429 | |||
430 | static int __init kstack_setup(char *s) | ||
431 | { | ||
432 | if (!s) | ||
433 | return -EINVAL; | ||
434 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
435 | return 0; | ||
436 | } | ||
437 | early_param("kstack", kstack_setup); | ||
438 | |||
439 | static int __init code_bytes_setup(char *s) | ||
440 | { | ||
441 | code_bytes = simple_strtoul(s, NULL, 0); | ||
442 | if (code_bytes > 8192) | ||
443 | code_bytes = 8192; | ||
444 | |||
445 | return 1; | ||
446 | } | ||
447 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c new file mode 100644 index 000000000000..086cc8118e39 --- /dev/null +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
4 | */ | ||
5 | #include <linux/kallsyms.h> | ||
6 | #include <linux/kprobes.h> | ||
7 | #include <linux/uaccess.h> | ||
8 | #include <linux/utsname.h> | ||
9 | #include <linux/hardirq.h> | ||
10 | #include <linux/kdebug.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/kexec.h> | ||
14 | #include <linux/bug.h> | ||
15 | #include <linux/nmi.h> | ||
16 | |||
17 | #include <asm/stacktrace.h> | ||
18 | |||
19 | #define STACKSLOTS_PER_LINE 4 | ||
20 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) | ||
21 | |||
22 | int panic_on_unrecovered_nmi; | ||
23 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | ||
24 | static unsigned int code_bytes = 64; | ||
25 | static int die_counter; | ||
26 | |||
27 | void printk_address(unsigned long address, int reliable) | ||
28 | { | ||
29 | printk(" [<%p>] %s%pS\n", (void *) address, | ||
30 | reliable ? "" : "? ", (void *) address); | ||
31 | } | ||
32 | |||
33 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | ||
34 | unsigned *usedp, char **idp) | ||
35 | { | ||
36 | static char ids[][8] = { | ||
37 | [DEBUG_STACK - 1] = "#DB", | ||
38 | [NMI_STACK - 1] = "NMI", | ||
39 | [DOUBLEFAULT_STACK - 1] = "#DF", | ||
40 | [STACKFAULT_STACK - 1] = "#SS", | ||
41 | [MCE_STACK - 1] = "#MC", | ||
42 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
43 | [N_EXCEPTION_STACKS ... | ||
44 | N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" | ||
45 | #endif | ||
46 | }; | ||
47 | unsigned k; | ||
48 | |||
49 | /* | ||
50 | * Iterate over all exception stacks, and figure out whether | ||
51 | * 'stack' is in one of them: | ||
52 | */ | ||
53 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { | ||
54 | unsigned long end = per_cpu(orig_ist, cpu).ist[k]; | ||
55 | /* | ||
56 | * Is 'stack' above this exception frame's end? | ||
57 | * If yes then skip to the next frame. | ||
58 | */ | ||
59 | if (stack >= end) | ||
60 | continue; | ||
61 | /* | ||
62 | * Is 'stack' above this exception frame's start address? | ||
63 | * If yes then we found the right frame. | ||
64 | */ | ||
65 | if (stack >= end - EXCEPTION_STKSZ) { | ||
66 | /* | ||
67 | * Make sure we only iterate through an exception | ||
68 | * stack once. If it comes up for the second time | ||
69 | * then there's something wrong going on - just | ||
70 | * break out and return NULL: | ||
71 | */ | ||
72 | if (*usedp & (1U << k)) | ||
73 | break; | ||
74 | *usedp |= 1U << k; | ||
75 | *idp = ids[k]; | ||
76 | return (unsigned long *)end; | ||
77 | } | ||
78 | /* | ||
79 | * If this is a debug stack, and if it has a larger size than | ||
80 | * the usual exception stacks, then 'stack' might still | ||
81 | * be within the lower portion of the debug stack: | ||
82 | */ | ||
83 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
84 | if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { | ||
85 | unsigned j = N_EXCEPTION_STACKS - 1; | ||
86 | |||
87 | /* | ||
88 | * Black magic. A large debug stack is composed of | ||
89 | * multiple exception stack entries, which we | ||
90 | * iterate through now. Dont look: | ||
91 | */ | ||
92 | do { | ||
93 | ++j; | ||
94 | end -= EXCEPTION_STKSZ; | ||
95 | ids[j][4] = '1' + (j - N_EXCEPTION_STACKS); | ||
96 | } while (stack < end - EXCEPTION_STKSZ); | ||
97 | if (*usedp & (1U << j)) | ||
98 | break; | ||
99 | *usedp |= 1U << j; | ||
100 | *idp = ids[j]; | ||
101 | return (unsigned long *)end; | ||
102 | } | ||
103 | #endif | ||
104 | } | ||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * x86-64 can have up to three kernel stacks: | ||
110 | * process stack | ||
111 | * interrupt stack | ||
112 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | ||
113 | */ | ||
114 | |||
115 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
116 | void *p, unsigned int size, void *end) | ||
117 | { | ||
118 | void *t = tinfo; | ||
119 | if (end) { | ||
120 | if (p < end && p >= (end-THREAD_SIZE)) | ||
121 | return 1; | ||
122 | else | ||
123 | return 0; | ||
124 | } | ||
125 | return p > t && p < t + THREAD_SIZE - size; | ||
126 | } | ||
127 | |||
128 | /* The form of the top of the frame on the stack */ | ||
129 | struct stack_frame { | ||
130 | struct stack_frame *next_frame; | ||
131 | unsigned long return_address; | ||
132 | }; | ||
133 | |||
134 | static inline unsigned long | ||
135 | print_context_stack(struct thread_info *tinfo, | ||
136 | unsigned long *stack, unsigned long bp, | ||
137 | const struct stacktrace_ops *ops, void *data, | ||
138 | unsigned long *end) | ||
139 | { | ||
140 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
141 | |||
142 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { | ||
143 | unsigned long addr; | ||
144 | |||
145 | addr = *stack; | ||
146 | if (__kernel_text_address(addr)) { | ||
147 | if ((unsigned long) stack == bp + sizeof(long)) { | ||
148 | ops->address(data, addr, 1); | ||
149 | frame = frame->next_frame; | ||
150 | bp = (unsigned long) frame; | ||
151 | } else { | ||
152 | ops->address(data, addr, bp == 0); | ||
153 | } | ||
154 | } | ||
155 | stack++; | ||
156 | } | ||
157 | return bp; | ||
158 | } | ||
159 | |||
160 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
161 | unsigned long *stack, unsigned long bp, | ||
162 | const struct stacktrace_ops *ops, void *data) | ||
163 | { | ||
164 | const unsigned cpu = get_cpu(); | ||
165 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | ||
166 | unsigned used = 0; | ||
167 | struct thread_info *tinfo; | ||
168 | |||
169 | if (!task) | ||
170 | task = current; | ||
171 | |||
172 | if (!stack) { | ||
173 | unsigned long dummy; | ||
174 | stack = &dummy; | ||
175 | if (task && task != current) | ||
176 | stack = (unsigned long *)task->thread.sp; | ||
177 | } | ||
178 | |||
179 | #ifdef CONFIG_FRAME_POINTER | ||
180 | if (!bp) { | ||
181 | if (task == current) { | ||
182 | /* Grab bp right from our regs */ | ||
183 | get_bp(bp); | ||
184 | } else { | ||
185 | /* bp is the last reg pushed by switch_to */ | ||
186 | bp = *(unsigned long *) task->thread.sp; | ||
187 | } | ||
188 | } | ||
189 | #endif | ||
190 | |||
191 | /* | ||
192 | * Print function call entries in all stacks, starting at the | ||
193 | * current stack address. If the stacks consist of nested | ||
194 | * exceptions | ||
195 | */ | ||
196 | tinfo = task_thread_info(task); | ||
197 | for (;;) { | ||
198 | char *id; | ||
199 | unsigned long *estack_end; | ||
200 | estack_end = in_exception_stack(cpu, (unsigned long)stack, | ||
201 | &used, &id); | ||
202 | |||
203 | if (estack_end) { | ||
204 | if (ops->stack(data, id) < 0) | ||
205 | break; | ||
206 | |||
207 | bp = print_context_stack(tinfo, stack, bp, ops, | ||
208 | data, estack_end); | ||
209 | ops->stack(data, "<EOE>"); | ||
210 | /* | ||
211 | * We link to the next stack via the | ||
212 | * second-to-last pointer (index -2 to end) in the | ||
213 | * exception stack: | ||
214 | */ | ||
215 | stack = (unsigned long *) estack_end[-2]; | ||
216 | continue; | ||
217 | } | ||
218 | if (irqstack_end) { | ||
219 | unsigned long *irqstack; | ||
220 | irqstack = irqstack_end - | ||
221 | (IRQSTACKSIZE - 64) / sizeof(*irqstack); | ||
222 | |||
223 | if (stack >= irqstack && stack < irqstack_end) { | ||
224 | if (ops->stack(data, "IRQ") < 0) | ||
225 | break; | ||
226 | bp = print_context_stack(tinfo, stack, bp, | ||
227 | ops, data, irqstack_end); | ||
228 | /* | ||
229 | * We link to the next stack (which would be | ||
230 | * the process stack normally) the last | ||
231 | * pointer (index -1 to end) in the IRQ stack: | ||
232 | */ | ||
233 | stack = (unsigned long *) (irqstack_end[-1]); | ||
234 | irqstack_end = NULL; | ||
235 | ops->stack(data, "EOI"); | ||
236 | continue; | ||
237 | } | ||
238 | } | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * This handles the process stack: | ||
244 | */ | ||
245 | bp = print_context_stack(tinfo, stack, bp, ops, data, NULL); | ||
246 | put_cpu(); | ||
247 | } | ||
248 | EXPORT_SYMBOL(dump_trace); | ||
249 | |||
250 | static void | ||
251 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
252 | { | ||
253 | printk(data); | ||
254 | print_symbol(msg, symbol); | ||
255 | printk("\n"); | ||
256 | } | ||
257 | |||
258 | static void print_trace_warning(void *data, char *msg) | ||
259 | { | ||
260 | printk("%s%s\n", (char *)data, msg); | ||
261 | } | ||
262 | |||
263 | static int print_trace_stack(void *data, char *name) | ||
264 | { | ||
265 | printk("%s <%s> ", (char *)data, name); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Print one address/symbol entries per line. | ||
271 | */ | ||
272 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
273 | { | ||
274 | touch_nmi_watchdog(); | ||
275 | printk(data); | ||
276 | printk_address(addr, reliable); | ||
277 | } | ||
278 | |||
279 | static const struct stacktrace_ops print_trace_ops = { | ||
280 | .warning = print_trace_warning, | ||
281 | .warning_symbol = print_trace_warning_symbol, | ||
282 | .stack = print_trace_stack, | ||
283 | .address = print_trace_address, | ||
284 | }; | ||
285 | |||
286 | static void | ||
287 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
288 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
289 | { | ||
290 | printk("%sCall Trace:\n", log_lvl); | ||
291 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | ||
292 | } | ||
293 | |||
294 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
295 | unsigned long *stack, unsigned long bp) | ||
296 | { | ||
297 | show_trace_log_lvl(task, regs, stack, bp, ""); | ||
298 | } | ||
299 | |||
300 | static void | ||
301 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
302 | unsigned long *sp, unsigned long bp, char *log_lvl) | ||
303 | { | ||
304 | unsigned long *stack; | ||
305 | int i; | ||
306 | const int cpu = smp_processor_id(); | ||
307 | unsigned long *irqstack_end = | ||
308 | (unsigned long *) (cpu_pda(cpu)->irqstackptr); | ||
309 | unsigned long *irqstack = | ||
310 | (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); | ||
311 | |||
312 | /* | ||
313 | * debugging aid: "show_stack(NULL, NULL);" prints the | ||
314 | * back trace for this cpu. | ||
315 | */ | ||
316 | |||
317 | if (sp == NULL) { | ||
318 | if (task) | ||
319 | sp = (unsigned long *)task->thread.sp; | ||
320 | else | ||
321 | sp = (unsigned long *)&sp; | ||
322 | } | ||
323 | |||
324 | stack = sp; | ||
325 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
326 | if (stack >= irqstack && stack <= irqstack_end) { | ||
327 | if (stack == irqstack_end) { | ||
328 | stack = (unsigned long *) (irqstack_end[-1]); | ||
329 | printk(" <EOI> "); | ||
330 | } | ||
331 | } else { | ||
332 | if (((long) stack & (THREAD_SIZE-1)) == 0) | ||
333 | break; | ||
334 | } | ||
335 | if (i && ((i % STACKSLOTS_PER_LINE) == 0)) | ||
336 | printk("\n%s", log_lvl); | ||
337 | printk(" %016lx", *stack++); | ||
338 | touch_nmi_watchdog(); | ||
339 | } | ||
340 | printk("\n"); | ||
341 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | ||
342 | } | ||
343 | |||
344 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
345 | { | ||
346 | show_stack_log_lvl(task, NULL, sp, 0, ""); | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * The architecture-independent dump_stack generator | ||
351 | */ | ||
352 | void dump_stack(void) | ||
353 | { | ||
354 | unsigned long bp = 0; | ||
355 | unsigned long stack; | ||
356 | |||
357 | #ifdef CONFIG_FRAME_POINTER | ||
358 | if (!bp) | ||
359 | get_bp(bp); | ||
360 | #endif | ||
361 | |||
362 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
363 | current->pid, current->comm, print_tainted(), | ||
364 | init_utsname()->release, | ||
365 | (int)strcspn(init_utsname()->version, " "), | ||
366 | init_utsname()->version); | ||
367 | show_trace(NULL, NULL, &stack, bp); | ||
368 | } | ||
369 | EXPORT_SYMBOL(dump_stack); | ||
370 | |||
371 | void show_registers(struct pt_regs *regs) | ||
372 | { | ||
373 | int i; | ||
374 | unsigned long sp; | ||
375 | const int cpu = smp_processor_id(); | ||
376 | struct task_struct *cur = cpu_pda(cpu)->pcurrent; | ||
377 | |||
378 | sp = regs->sp; | ||
379 | printk("CPU %d ", cpu); | ||
380 | __show_regs(regs, 1); | ||
381 | printk("Process %s (pid: %d, threadinfo %p, task %p)\n", | ||
382 | cur->comm, cur->pid, task_thread_info(cur), cur); | ||
383 | |||
384 | /* | ||
385 | * When in-kernel, we also print out the stack and code at the | ||
386 | * time of the fault.. | ||
387 | */ | ||
388 | if (!user_mode(regs)) { | ||
389 | unsigned int code_prologue = code_bytes * 43 / 64; | ||
390 | unsigned int code_len = code_bytes; | ||
391 | unsigned char c; | ||
392 | u8 *ip; | ||
393 | |||
394 | printk(KERN_EMERG "Stack:\n"); | ||
395 | show_stack_log_lvl(NULL, regs, (unsigned long *)sp, | ||
396 | regs->bp, KERN_EMERG); | ||
397 | |||
398 | printk(KERN_EMERG "Code: "); | ||
399 | |||
400 | ip = (u8 *)regs->ip - code_prologue; | ||
401 | if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { | ||
402 | /* try starting at IP */ | ||
403 | ip = (u8 *)regs->ip; | ||
404 | code_len = code_len - code_prologue + 1; | ||
405 | } | ||
406 | for (i = 0; i < code_len; i++, ip++) { | ||
407 | if (ip < (u8 *)PAGE_OFFSET || | ||
408 | probe_kernel_address(ip, c)) { | ||
409 | printk(" Bad RIP value."); | ||
410 | break; | ||
411 | } | ||
412 | if (ip == (u8 *)regs->ip) | ||
413 | printk("<%02x> ", c); | ||
414 | else | ||
415 | printk("%02x ", c); | ||
416 | } | ||
417 | } | ||
418 | printk("\n"); | ||
419 | } | ||
420 | |||
421 | int is_valid_bugaddr(unsigned long ip) | ||
422 | { | ||
423 | unsigned short ud2; | ||
424 | |||
425 | if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2))) | ||
426 | return 0; | ||
427 | |||
428 | return ud2 == 0x0b0f; | ||
429 | } | ||
430 | |||
431 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
432 | static int die_owner = -1; | ||
433 | static unsigned int die_nest_count; | ||
434 | |||
435 | unsigned __kprobes long oops_begin(void) | ||
436 | { | ||
437 | int cpu; | ||
438 | unsigned long flags; | ||
439 | |||
440 | oops_enter(); | ||
441 | |||
442 | /* racy, but better than risking deadlock. */ | ||
443 | raw_local_irq_save(flags); | ||
444 | cpu = smp_processor_id(); | ||
445 | if (!__raw_spin_trylock(&die_lock)) { | ||
446 | if (cpu == die_owner) | ||
447 | /* nested oops. should stop eventually */; | ||
448 | else | ||
449 | __raw_spin_lock(&die_lock); | ||
450 | } | ||
451 | die_nest_count++; | ||
452 | die_owner = cpu; | ||
453 | console_verbose(); | ||
454 | bust_spinlocks(1); | ||
455 | return flags; | ||
456 | } | ||
457 | |||
458 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
459 | { | ||
460 | die_owner = -1; | ||
461 | bust_spinlocks(0); | ||
462 | die_nest_count--; | ||
463 | if (!die_nest_count) | ||
464 | /* Nest count reaches zero, release the lock. */ | ||
465 | __raw_spin_unlock(&die_lock); | ||
466 | raw_local_irq_restore(flags); | ||
467 | if (!regs) { | ||
468 | oops_exit(); | ||
469 | return; | ||
470 | } | ||
471 | if (in_interrupt()) | ||
472 | panic("Fatal exception in interrupt"); | ||
473 | if (panic_on_oops) | ||
474 | panic("Fatal exception"); | ||
475 | oops_exit(); | ||
476 | do_exit(signr); | ||
477 | } | ||
478 | |||
479 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
480 | { | ||
481 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | ||
482 | #ifdef CONFIG_PREEMPT | ||
483 | printk("PREEMPT "); | ||
484 | #endif | ||
485 | #ifdef CONFIG_SMP | ||
486 | printk("SMP "); | ||
487 | #endif | ||
488 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
489 | printk("DEBUG_PAGEALLOC"); | ||
490 | #endif | ||
491 | printk("\n"); | ||
492 | if (notify_die(DIE_OOPS, str, regs, err, | ||
493 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
494 | return 1; | ||
495 | |||
496 | show_registers(regs); | ||
497 | add_taint(TAINT_DIE); | ||
498 | /* Executive summary in case the oops scrolled away */ | ||
499 | printk(KERN_ALERT "RIP "); | ||
500 | printk_address(regs->ip, 1); | ||
501 | printk(" RSP <%016lx>\n", regs->sp); | ||
502 | if (kexec_should_crash(current)) | ||
503 | crash_kexec(regs); | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | void die(const char *str, struct pt_regs *regs, long err) | ||
508 | { | ||
509 | unsigned long flags = oops_begin(); | ||
510 | |||
511 | if (!user_mode(regs)) | ||
512 | report_bug(regs->ip, regs); | ||
513 | |||
514 | if (__die(str, regs, err)) | ||
515 | regs = NULL; | ||
516 | oops_end(flags, regs, SIGSEGV); | ||
517 | } | ||
518 | |||
519 | notrace __kprobes void | ||
520 | die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
521 | { | ||
522 | unsigned long flags; | ||
523 | |||
524 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
525 | return; | ||
526 | |||
527 | flags = oops_begin(); | ||
528 | /* | ||
529 | * We are in trouble anyway, lets at least try | ||
530 | * to get a message out. | ||
531 | */ | ||
532 | printk(KERN_EMERG "%s", str); | ||
533 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
534 | smp_processor_id(), regs->ip); | ||
535 | show_registers(regs); | ||
536 | if (kexec_should_crash(current)) | ||
537 | crash_kexec(regs); | ||
538 | if (do_panic || panic_on_oops) | ||
539 | panic("Non maskable interrupt"); | ||
540 | oops_end(flags, NULL, SIGBUS); | ||
541 | nmi_exit(); | ||
542 | local_irq_enable(); | ||
543 | do_exit(SIGBUS); | ||
544 | } | ||
545 | |||
546 | static int __init oops_setup(char *s) | ||
547 | { | ||
548 | if (!s) | ||
549 | return -EINVAL; | ||
550 | if (!strcmp(s, "panic")) | ||
551 | panic_on_oops = 1; | ||
552 | return 0; | ||
553 | } | ||
554 | early_param("oops", oops_setup); | ||
555 | |||
556 | static int __init kstack_setup(char *s) | ||
557 | { | ||
558 | if (!s) | ||
559 | return -EINVAL; | ||
560 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
561 | return 0; | ||
562 | } | ||
563 | early_param("kstack", kstack_setup); | ||
564 | |||
565 | static int __init code_bytes_setup(char *s) | ||
566 | { | ||
567 | code_bytes = simple_strtoul(s, NULL, 0); | ||
568 | if (code_bytes > 8192) | ||
569 | code_bytes = 8192; | ||
570 | |||
571 | return 1; | ||
572 | } | ||
573 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 109792bc7cfa..b21fbfaffe39 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -730,6 +730,7 @@ error_code: | |||
730 | movl $(__USER_DS), %ecx | 730 | movl $(__USER_DS), %ecx |
731 | movl %ecx, %ds | 731 | movl %ecx, %ds |
732 | movl %ecx, %es | 732 | movl %ecx, %es |
733 | TRACE_IRQS_OFF | ||
733 | movl %esp,%eax # pt_regs pointer | 734 | movl %esp,%eax # pt_regs pointer |
734 | call *%edi | 735 | call *%edi |
735 | jmp ret_from_exception | 736 | jmp ret_from_exception |
@@ -760,20 +761,9 @@ ENTRY(device_not_available) | |||
760 | RING0_INT_FRAME | 761 | RING0_INT_FRAME |
761 | pushl $-1 # mark this as an int | 762 | pushl $-1 # mark this as an int |
762 | CFI_ADJUST_CFA_OFFSET 4 | 763 | CFI_ADJUST_CFA_OFFSET 4 |
763 | SAVE_ALL | 764 | pushl $do_device_not_available |
764 | GET_CR0_INTO_EAX | ||
765 | testl $0x4, %eax # EM (math emulation bit) | ||
766 | jne device_not_available_emulate | ||
767 | preempt_stop(CLBR_ANY) | ||
768 | call math_state_restore | ||
769 | jmp ret_from_exception | ||
770 | device_not_available_emulate: | ||
771 | pushl $0 # temporary storage for ORIG_EIP | ||
772 | CFI_ADJUST_CFA_OFFSET 4 | 765 | CFI_ADJUST_CFA_OFFSET 4 |
773 | call math_emulate | 766 | jmp error_code |
774 | addl $4, %esp | ||
775 | CFI_ADJUST_CFA_OFFSET -4 | ||
776 | jmp ret_from_exception | ||
777 | CFI_ENDPROC | 767 | CFI_ENDPROC |
778 | END(device_not_available) | 768 | END(device_not_available) |
779 | 769 | ||
@@ -814,6 +804,7 @@ debug_stack_correct: | |||
814 | pushl $-1 # mark this as an int | 804 | pushl $-1 # mark this as an int |
815 | CFI_ADJUST_CFA_OFFSET 4 | 805 | CFI_ADJUST_CFA_OFFSET 4 |
816 | SAVE_ALL | 806 | SAVE_ALL |
807 | TRACE_IRQS_OFF | ||
817 | xorl %edx,%edx # error code 0 | 808 | xorl %edx,%edx # error code 0 |
818 | movl %esp,%eax # pt_regs pointer | 809 | movl %esp,%eax # pt_regs pointer |
819 | call do_debug | 810 | call do_debug |
@@ -858,6 +849,7 @@ nmi_stack_correct: | |||
858 | pushl %eax | 849 | pushl %eax |
859 | CFI_ADJUST_CFA_OFFSET 4 | 850 | CFI_ADJUST_CFA_OFFSET 4 |
860 | SAVE_ALL | 851 | SAVE_ALL |
852 | TRACE_IRQS_OFF | ||
861 | xorl %edx,%edx # zero error code | 853 | xorl %edx,%edx # zero error code |
862 | movl %esp,%eax # pt_regs pointer | 854 | movl %esp,%eax # pt_regs pointer |
863 | call do_nmi | 855 | call do_nmi |
@@ -898,6 +890,7 @@ nmi_espfix_stack: | |||
898 | pushl %eax | 890 | pushl %eax |
899 | CFI_ADJUST_CFA_OFFSET 4 | 891 | CFI_ADJUST_CFA_OFFSET 4 |
900 | SAVE_ALL | 892 | SAVE_ALL |
893 | TRACE_IRQS_OFF | ||
901 | FIXUP_ESPFIX_STACK # %eax == %esp | 894 | FIXUP_ESPFIX_STACK # %eax == %esp |
902 | xorl %edx,%edx # zero error code | 895 | xorl %edx,%edx # zero error code |
903 | call do_nmi | 896 | call do_nmi |
@@ -928,6 +921,7 @@ KPROBE_ENTRY(int3) | |||
928 | pushl $-1 # mark this as an int | 921 | pushl $-1 # mark this as an int |
929 | CFI_ADJUST_CFA_OFFSET 4 | 922 | CFI_ADJUST_CFA_OFFSET 4 |
930 | SAVE_ALL | 923 | SAVE_ALL |
924 | TRACE_IRQS_OFF | ||
931 | xorl %edx,%edx # zero error code | 925 | xorl %edx,%edx # zero error code |
932 | movl %esp,%eax # pt_regs pointer | 926 | movl %esp,%eax # pt_regs pointer |
933 | call do_int3 | 927 | call do_int3 |
@@ -1030,7 +1024,7 @@ ENTRY(machine_check) | |||
1030 | RING0_INT_FRAME | 1024 | RING0_INT_FRAME |
1031 | pushl $0 | 1025 | pushl $0 |
1032 | CFI_ADJUST_CFA_OFFSET 4 | 1026 | CFI_ADJUST_CFA_OFFSET 4 |
1033 | pushl machine_check_vector | 1027 | pushl $do_machine_check |
1034 | CFI_ADJUST_CFA_OFFSET 4 | 1028 | CFI_ADJUST_CFA_OFFSET 4 |
1035 | jmp error_code | 1029 | jmp error_code |
1036 | CFI_ENDPROC | 1030 | CFI_ENDPROC |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index cf3a0b2d0059..1db6ce4314e1 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -667,6 +667,13 @@ END(stub_rt_sigreturn) | |||
667 | SAVE_ARGS | 667 | SAVE_ARGS |
668 | leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler | 668 | leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler |
669 | pushq %rbp | 669 | pushq %rbp |
670 | /* | ||
671 | * Save rbp twice: One is for marking the stack frame, as usual, and the | ||
672 | * other, to fill pt_regs properly. This is because bx comes right | ||
673 | * before the last saved register in that structure, and not bp. If the | ||
674 | * base pointer were in the place bx is today, this would not be needed. | ||
675 | */ | ||
676 | movq %rbp, -8(%rsp) | ||
670 | CFI_ADJUST_CFA_OFFSET 8 | 677 | CFI_ADJUST_CFA_OFFSET 8 |
671 | CFI_REL_OFFSET rbp, 0 | 678 | CFI_REL_OFFSET rbp, 0 |
672 | movq %rsp,%rbp | 679 | movq %rsp,%rbp |
@@ -932,6 +939,9 @@ END(spurious_interrupt) | |||
932 | .if \ist | 939 | .if \ist |
933 | movq %gs:pda_data_offset, %rbp | 940 | movq %gs:pda_data_offset, %rbp |
934 | .endif | 941 | .endif |
942 | .if \irqtrace | ||
943 | TRACE_IRQS_OFF | ||
944 | .endif | ||
935 | movq %rsp,%rdi | 945 | movq %rsp,%rdi |
936 | movq ORIG_RAX(%rsp),%rsi | 946 | movq ORIG_RAX(%rsp),%rsi |
937 | movq $-1,ORIG_RAX(%rsp) | 947 | movq $-1,ORIG_RAX(%rsp) |
@@ -1058,7 +1068,8 @@ KPROBE_ENTRY(error_entry) | |||
1058 | je error_kernelspace | 1068 | je error_kernelspace |
1059 | error_swapgs: | 1069 | error_swapgs: |
1060 | SWAPGS | 1070 | SWAPGS |
1061 | error_sti: | 1071 | error_sti: |
1072 | TRACE_IRQS_OFF | ||
1062 | movq %rdi,RDI(%rsp) | 1073 | movq %rdi,RDI(%rsp) |
1063 | CFI_REL_OFFSET rdi,RDI | 1074 | CFI_REL_OFFSET rdi,RDI |
1064 | movq %rsp,%rdi | 1075 | movq %rsp,%rdi |
@@ -1232,7 +1243,7 @@ ENTRY(simd_coprocessor_error) | |||
1232 | END(simd_coprocessor_error) | 1243 | END(simd_coprocessor_error) |
1233 | 1244 | ||
1234 | ENTRY(device_not_available) | 1245 | ENTRY(device_not_available) |
1235 | zeroentry math_state_restore | 1246 | zeroentry do_device_not_available |
1236 | END(device_not_available) | 1247 | END(device_not_available) |
1237 | 1248 | ||
1238 | /* runs on exception stack */ | 1249 | /* runs on exception stack */ |
diff --git a/arch/x86/kernel/es7000_32.c b/arch/x86/kernel/es7000_32.c index 849e5cd485b8..f454c78fcef6 100644 --- a/arch/x86/kernel/es7000_32.c +++ b/arch/x86/kernel/es7000_32.c | |||
@@ -109,6 +109,7 @@ struct oem_table { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | extern int find_unisys_acpi_oem_table(unsigned long *oem_addr); | 111 | extern int find_unisys_acpi_oem_table(unsigned long *oem_addr); |
112 | extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr); | ||
112 | #endif | 113 | #endif |
113 | 114 | ||
114 | struct mip_reg { | 115 | struct mip_reg { |
@@ -243,21 +244,38 @@ parse_unisys_oem (char *oemptr) | |||
243 | } | 244 | } |
244 | 245 | ||
245 | #ifdef CONFIG_ACPI | 246 | #ifdef CONFIG_ACPI |
246 | int __init | 247 | static unsigned long oem_addrX; |
247 | find_unisys_acpi_oem_table(unsigned long *oem_addr) | 248 | static unsigned long oem_size; |
249 | int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) | ||
248 | { | 250 | { |
249 | struct acpi_table_header *header = NULL; | 251 | struct acpi_table_header *header = NULL; |
250 | int i = 0; | 252 | int i = 0; |
251 | while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) { | 253 | acpi_size tbl_size; |
254 | |||
255 | while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) { | ||
252 | if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) { | 256 | if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) { |
253 | struct oem_table *t = (struct oem_table *)header; | 257 | struct oem_table *t = (struct oem_table *)header; |
254 | *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr, | 258 | |
255 | t->OEMTableSize); | 259 | oem_addrX = t->OEMTableAddr; |
260 | oem_size = t->OEMTableSize; | ||
261 | early_acpi_os_unmap_memory(header, tbl_size); | ||
262 | |||
263 | *oem_addr = (unsigned long)__acpi_map_table(oem_addrX, | ||
264 | oem_size); | ||
256 | return 0; | 265 | return 0; |
257 | } | 266 | } |
267 | early_acpi_os_unmap_memory(header, tbl_size); | ||
258 | } | 268 | } |
259 | return -1; | 269 | return -1; |
260 | } | 270 | } |
271 | |||
272 | void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr) | ||
273 | { | ||
274 | if (!oem_addr) | ||
275 | return; | ||
276 | |||
277 | __acpi_unmap_table((char *)oem_addr, oem_size); | ||
278 | } | ||
261 | #endif | 279 | #endif |
262 | 280 | ||
263 | static void | 281 | static void |
diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c index ae2ffc8a400c..33581d94a90e 100644 --- a/arch/x86/kernel/genx2apic_uv_x.c +++ b/arch/x86/kernel/genx2apic_uv_x.c | |||
@@ -114,7 +114,7 @@ static void uv_send_IPI_one(int cpu, int vector) | |||
114 | unsigned long val, apicid, lapicid; | 114 | unsigned long val, apicid, lapicid; |
115 | int pnode; | 115 | int pnode; |
116 | 116 | ||
117 | apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */ | 117 | apicid = per_cpu(x86_cpu_to_apicid, cpu); |
118 | lapicid = apicid & 0x3f; /* ZZZ macro needed */ | 118 | lapicid = apicid & 0x3f; /* ZZZ macro needed */ |
119 | pnode = uv_apicid_to_pnode(apicid); | 119 | pnode = uv_apicid_to_pnode(apicid); |
120 | val = | 120 | val = |
@@ -202,12 +202,10 @@ static unsigned int phys_pkg_id(int index_msb) | |||
202 | return uv_read_apic_id() >> index_msb; | 202 | return uv_read_apic_id() >> index_msb; |
203 | } | 203 | } |
204 | 204 | ||
205 | #ifdef ZZZ /* Needs x2apic patch */ | ||
206 | static void uv_send_IPI_self(int vector) | 205 | static void uv_send_IPI_self(int vector) |
207 | { | 206 | { |
208 | apic_write(APIC_SELF_IPI, vector); | 207 | apic_write(APIC_SELF_IPI, vector); |
209 | } | 208 | } |
210 | #endif | ||
211 | 209 | ||
212 | struct genapic apic_x2apic_uv_x = { | 210 | struct genapic apic_x2apic_uv_x = { |
213 | .name = "UV large system", | 211 | .name = "UV large system", |
@@ -215,15 +213,15 @@ struct genapic apic_x2apic_uv_x = { | |||
215 | .int_delivery_mode = dest_Fixed, | 213 | .int_delivery_mode = dest_Fixed, |
216 | .int_dest_mode = (APIC_DEST_PHYSICAL != 0), | 214 | .int_dest_mode = (APIC_DEST_PHYSICAL != 0), |
217 | .target_cpus = uv_target_cpus, | 215 | .target_cpus = uv_target_cpus, |
218 | .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */ | 216 | .vector_allocation_domain = uv_vector_allocation_domain, |
219 | .apic_id_registered = uv_apic_id_registered, | 217 | .apic_id_registered = uv_apic_id_registered, |
220 | .init_apic_ldr = uv_init_apic_ldr, | 218 | .init_apic_ldr = uv_init_apic_ldr, |
221 | .send_IPI_all = uv_send_IPI_all, | 219 | .send_IPI_all = uv_send_IPI_all, |
222 | .send_IPI_allbutself = uv_send_IPI_allbutself, | 220 | .send_IPI_allbutself = uv_send_IPI_allbutself, |
223 | .send_IPI_mask = uv_send_IPI_mask, | 221 | .send_IPI_mask = uv_send_IPI_mask, |
224 | /* ZZZ.send_IPI_self = uv_send_IPI_self, */ | 222 | .send_IPI_self = uv_send_IPI_self, |
225 | .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, | 223 | .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, |
226 | .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ | 224 | .phys_pkg_id = phys_pkg_id, |
227 | .get_apic_id = get_apic_id, | 225 | .get_apic_id = get_apic_id, |
228 | .set_apic_id = set_apic_id, | 226 | .set_apic_id = set_apic_id, |
229 | .apic_id_mask = (0xFFFFFFFFu), | 227 | .apic_id_mask = (0xFFFFFFFFu), |
@@ -286,12 +284,13 @@ static __init void map_low_mmrs(void) | |||
286 | 284 | ||
287 | enum map_type {map_wb, map_uc}; | 285 | enum map_type {map_wb, map_uc}; |
288 | 286 | ||
289 | static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type) | 287 | static __init void map_high(char *id, unsigned long base, int shift, |
288 | int max_pnode, enum map_type map_type) | ||
290 | { | 289 | { |
291 | unsigned long bytes, paddr; | 290 | unsigned long bytes, paddr; |
292 | 291 | ||
293 | paddr = base << shift; | 292 | paddr = base << shift; |
294 | bytes = (1UL << shift); | 293 | bytes = (1UL << shift) * (max_pnode + 1); |
295 | printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, | 294 | printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, |
296 | paddr + bytes); | 295 | paddr + bytes); |
297 | if (map_type == map_uc) | 296 | if (map_type == map_uc) |
@@ -307,7 +306,7 @@ static __init void map_gru_high(int max_pnode) | |||
307 | 306 | ||
308 | gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR); | 307 | gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR); |
309 | if (gru.s.enable) | 308 | if (gru.s.enable) |
310 | map_high("GRU", gru.s.base, shift, map_wb); | 309 | map_high("GRU", gru.s.base, shift, max_pnode, map_wb); |
311 | } | 310 | } |
312 | 311 | ||
313 | static __init void map_config_high(int max_pnode) | 312 | static __init void map_config_high(int max_pnode) |
@@ -317,7 +316,7 @@ static __init void map_config_high(int max_pnode) | |||
317 | 316 | ||
318 | cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR); | 317 | cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR); |
319 | if (cfg.s.enable) | 318 | if (cfg.s.enable) |
320 | map_high("CONFIG", cfg.s.base, shift, map_uc); | 319 | map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc); |
321 | } | 320 | } |
322 | 321 | ||
323 | static __init void map_mmr_high(int max_pnode) | 322 | static __init void map_mmr_high(int max_pnode) |
@@ -327,7 +326,7 @@ static __init void map_mmr_high(int max_pnode) | |||
327 | 326 | ||
328 | mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); | 327 | mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); |
329 | if (mmr.s.enable) | 328 | if (mmr.s.enable) |
330 | map_high("MMR", mmr.s.base, shift, map_uc); | 329 | map_high("MMR", mmr.s.base, shift, max_pnode, map_uc); |
331 | } | 330 | } |
332 | 331 | ||
333 | static __init void map_mmioh_high(int max_pnode) | 332 | static __init void map_mmioh_high(int max_pnode) |
@@ -337,7 +336,7 @@ static __init void map_mmioh_high(int max_pnode) | |||
337 | 336 | ||
338 | mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); | 337 | mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); |
339 | if (mmioh.s.enable) | 338 | if (mmioh.s.enable) |
340 | map_high("MMIOH", mmioh.s.base, shift, map_uc); | 339 | map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc); |
341 | } | 340 | } |
342 | 341 | ||
343 | static __init void uv_rtc_init(void) | 342 | static __init void uv_rtc_init(void) |
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c index 3e66bd364a9d..1dcb0f13897e 100644 --- a/arch/x86/kernel/head.c +++ b/arch/x86/kernel/head.c | |||
@@ -35,6 +35,7 @@ void __init reserve_ebda_region(void) | |||
35 | 35 | ||
36 | /* start of EBDA area */ | 36 | /* start of EBDA area */ |
37 | ebda_addr = get_bios_ebda(); | 37 | ebda_addr = get_bios_ebda(); |
38 | printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem); | ||
38 | 39 | ||
39 | /* Fixup: bios puts an EBDA in the top 64K segment */ | 40 | /* Fixup: bios puts an EBDA in the top 64K segment */ |
40 | /* of conventional memory, but does not adjust lowmem. */ | 41 | /* of conventional memory, but does not adjust lowmem. */ |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 73deaffadd03..acf62fc233da 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -115,13 +115,17 @@ static void hpet_reserve_platform_timers(unsigned long id) | |||
115 | hd.hd_phys_address = hpet_address; | 115 | hd.hd_phys_address = hpet_address; |
116 | hd.hd_address = hpet; | 116 | hd.hd_address = hpet; |
117 | hd.hd_nirqs = nrtimers; | 117 | hd.hd_nirqs = nrtimers; |
118 | hd.hd_flags = HPET_DATA_PLATFORM; | ||
119 | hpet_reserve_timer(&hd, 0); | 118 | hpet_reserve_timer(&hd, 0); |
120 | 119 | ||
121 | #ifdef CONFIG_HPET_EMULATE_RTC | 120 | #ifdef CONFIG_HPET_EMULATE_RTC |
122 | hpet_reserve_timer(&hd, 1); | 121 | hpet_reserve_timer(&hd, 1); |
123 | #endif | 122 | #endif |
124 | 123 | ||
124 | /* | ||
125 | * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254 | ||
126 | * is wrong for i8259!) not the output IRQ. Many BIOS writers | ||
127 | * don't bother configuring *any* comparator interrupts. | ||
128 | */ | ||
125 | hd.hd_irq[0] = HPET_LEGACY_8254; | 129 | hd.hd_irq[0] = HPET_LEGACY_8254; |
126 | hd.hd_irq[1] = HPET_LEGACY_RTC; | 130 | hd.hd_irq[1] = HPET_LEGACY_RTC; |
127 | 131 | ||
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c index 1f26fd9ec4f4..5b5be9d43c2a 100644 --- a/arch/x86/kernel/irqinit_64.c +++ b/arch/x86/kernel/irqinit_64.c | |||
@@ -135,7 +135,7 @@ DEFINE_PER_CPU(vector_irq_t, vector_irq) = { | |||
135 | [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1 | 135 | [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1 |
136 | }; | 136 | }; |
137 | 137 | ||
138 | static void __init init_ISA_irqs (void) | 138 | void __init init_ISA_irqs(void) |
139 | { | 139 | { |
140 | int i; | 140 | int i; |
141 | 141 | ||
@@ -164,22 +164,8 @@ static void __init init_ISA_irqs (void) | |||
164 | 164 | ||
165 | void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); | 165 | void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); |
166 | 166 | ||
167 | void __init native_init_IRQ(void) | 167 | static void __init smp_intr_init(void) |
168 | { | 168 | { |
169 | int i; | ||
170 | |||
171 | init_ISA_irqs(); | ||
172 | /* | ||
173 | * Cover the whole vector space, no vector can escape | ||
174 | * us. (some of these will be overridden and become | ||
175 | * 'special' SMP interrupts) | ||
176 | */ | ||
177 | for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { | ||
178 | int vector = FIRST_EXTERNAL_VECTOR + i; | ||
179 | if (vector != IA32_SYSCALL_VECTOR) | ||
180 | set_intr_gate(vector, interrupt[i]); | ||
181 | } | ||
182 | |||
183 | #ifdef CONFIG_SMP | 169 | #ifdef CONFIG_SMP |
184 | /* | 170 | /* |
185 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | 171 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper |
@@ -207,6 +193,12 @@ void __init native_init_IRQ(void) | |||
207 | /* Low priority IPI to cleanup after moving an irq */ | 193 | /* Low priority IPI to cleanup after moving an irq */ |
208 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | 194 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); |
209 | #endif | 195 | #endif |
196 | } | ||
197 | |||
198 | static void __init apic_intr_init(void) | ||
199 | { | ||
200 | smp_intr_init(); | ||
201 | |||
210 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); | 202 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
211 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); | 203 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); |
212 | 204 | ||
@@ -216,6 +208,25 @@ void __init native_init_IRQ(void) | |||
216 | /* IPI vectors for APIC spurious and error interrupts */ | 208 | /* IPI vectors for APIC spurious and error interrupts */ |
217 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | 209 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); |
218 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | 210 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); |
211 | } | ||
212 | |||
213 | void __init native_init_IRQ(void) | ||
214 | { | ||
215 | int i; | ||
216 | |||
217 | init_ISA_irqs(); | ||
218 | /* | ||
219 | * Cover the whole vector space, no vector can escape | ||
220 | * us. (some of these will be overridden and become | ||
221 | * 'special' SMP interrupts) | ||
222 | */ | ||
223 | for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { | ||
224 | int vector = FIRST_EXTERNAL_VECTOR + i; | ||
225 | if (vector != IA32_SYSCALL_VECTOR) | ||
226 | set_intr_gate(vector, interrupt[i]); | ||
227 | } | ||
228 | |||
229 | apic_intr_init(); | ||
219 | 230 | ||
220 | if (!acpi_ioapic) | 231 | if (!acpi_ioapic) |
221 | setup_irq(2, &irq2); | 232 | setup_irq(2, &irq2); |
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 922c14058f97..0a1302fe6d45 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -123,7 +123,7 @@ void cpu_idle(void) | |||
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
126 | void __show_registers(struct pt_regs *regs, int all) | 126 | void __show_regs(struct pt_regs *regs, int all) |
127 | { | 127 | { |
128 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; | 128 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; |
129 | unsigned long d0, d1, d2, d3, d6, d7; | 129 | unsigned long d0, d1, d2, d3, d6, d7; |
@@ -189,7 +189,7 @@ void __show_registers(struct pt_regs *regs, int all) | |||
189 | 189 | ||
190 | void show_regs(struct pt_regs *regs) | 190 | void show_regs(struct pt_regs *regs) |
191 | { | 191 | { |
192 | __show_registers(regs, 1); | 192 | __show_regs(regs, 1); |
193 | show_trace(NULL, regs, ®s->sp, regs->bp); | 193 | show_trace(NULL, regs, ®s->sp, regs->bp); |
194 | } | 194 | } |
195 | 195 | ||
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index ca80394ef5b8..cd8c0ed02b7e 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -136,7 +136,7 @@ void cpu_idle(void) | |||
136 | } | 136 | } |
137 | 137 | ||
138 | /* Prints also some state that isn't saved in the pt_regs */ | 138 | /* Prints also some state that isn't saved in the pt_regs */ |
139 | void __show_regs(struct pt_regs *regs) | 139 | void __show_regs(struct pt_regs *regs, int all) |
140 | { | 140 | { |
141 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs; | 141 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs; |
142 | unsigned long d0, d1, d2, d3, d6, d7; | 142 | unsigned long d0, d1, d2, d3, d6, d7; |
@@ -175,6 +175,9 @@ void __show_regs(struct pt_regs *regs) | |||
175 | rdmsrl(MSR_GS_BASE, gs); | 175 | rdmsrl(MSR_GS_BASE, gs); |
176 | rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); | 176 | rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); |
177 | 177 | ||
178 | if (!all) | ||
179 | return; | ||
180 | |||
178 | cr0 = read_cr0(); | 181 | cr0 = read_cr0(); |
179 | cr2 = read_cr2(); | 182 | cr2 = read_cr2(); |
180 | cr3 = read_cr3(); | 183 | cr3 = read_cr3(); |
@@ -200,7 +203,7 @@ void __show_regs(struct pt_regs *regs) | |||
200 | void show_regs(struct pt_regs *regs) | 203 | void show_regs(struct pt_regs *regs) |
201 | { | 204 | { |
202 | printk(KERN_INFO "CPU %d:", smp_processor_id()); | 205 | printk(KERN_INFO "CPU %d:", smp_processor_id()); |
203 | __show_regs(regs); | 206 | __show_regs(regs, 1); |
204 | show_trace(NULL, regs, (void *)(regs + 1), regs->bp); | 207 | show_trace(NULL, regs, (void *)(regs + 1), regs->bp); |
205 | } | 208 | } |
206 | 209 | ||
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index d13858818100..f6a11b9b1f98 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c | |||
@@ -354,9 +354,27 @@ static void ati_force_hpet_resume(void) | |||
354 | printk(KERN_DEBUG "Force enabled HPET at resume\n"); | 354 | printk(KERN_DEBUG "Force enabled HPET at resume\n"); |
355 | } | 355 | } |
356 | 356 | ||
357 | static u32 ati_ixp4x0_rev(struct pci_dev *dev) | ||
358 | { | ||
359 | u32 d; | ||
360 | u8 b; | ||
361 | |||
362 | pci_read_config_byte(dev, 0xac, &b); | ||
363 | b &= ~(1<<5); | ||
364 | pci_write_config_byte(dev, 0xac, b); | ||
365 | pci_read_config_dword(dev, 0x70, &d); | ||
366 | d |= 1<<8; | ||
367 | pci_write_config_dword(dev, 0x70, d); | ||
368 | pci_read_config_dword(dev, 0x8, &d); | ||
369 | d &= 0xff; | ||
370 | dev_printk(KERN_DEBUG, &dev->dev, "SB4X0 revision 0x%x\n", d); | ||
371 | return d; | ||
372 | } | ||
373 | |||
357 | static void ati_force_enable_hpet(struct pci_dev *dev) | 374 | static void ati_force_enable_hpet(struct pci_dev *dev) |
358 | { | 375 | { |
359 | u32 uninitialized_var(val); | 376 | u32 d, val; |
377 | u8 b; | ||
360 | 378 | ||
361 | if (hpet_address || force_hpet_address) | 379 | if (hpet_address || force_hpet_address) |
362 | return; | 380 | return; |
@@ -366,14 +384,33 @@ static void ati_force_enable_hpet(struct pci_dev *dev) | |||
366 | return; | 384 | return; |
367 | } | 385 | } |
368 | 386 | ||
387 | d = ati_ixp4x0_rev(dev); | ||
388 | if (d < 0x82) | ||
389 | return; | ||
390 | |||
391 | /* base address */ | ||
369 | pci_write_config_dword(dev, 0x14, 0xfed00000); | 392 | pci_write_config_dword(dev, 0x14, 0xfed00000); |
370 | pci_read_config_dword(dev, 0x14, &val); | 393 | pci_read_config_dword(dev, 0x14, &val); |
394 | |||
395 | /* enable interrupt */ | ||
396 | outb(0x72, 0xcd6); b = inb(0xcd7); | ||
397 | b |= 0x1; | ||
398 | outb(0x72, 0xcd6); outb(b, 0xcd7); | ||
399 | outb(0x72, 0xcd6); b = inb(0xcd7); | ||
400 | if (!(b & 0x1)) | ||
401 | return; | ||
402 | pci_read_config_dword(dev, 0x64, &d); | ||
403 | d |= (1<<10); | ||
404 | pci_write_config_dword(dev, 0x64, d); | ||
405 | pci_read_config_dword(dev, 0x64, &d); | ||
406 | if (!(d & (1<<10))) | ||
407 | return; | ||
408 | |||
371 | force_hpet_address = val; | 409 | force_hpet_address = val; |
372 | force_hpet_resume_type = ATI_FORCE_HPET_RESUME; | 410 | force_hpet_resume_type = ATI_FORCE_HPET_RESUME; |
373 | dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n", | 411 | dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n", |
374 | force_hpet_address); | 412 | force_hpet_address); |
375 | cached_dev = dev; | 413 | cached_dev = dev; |
376 | return; | ||
377 | } | 414 | } |
378 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS, | 415 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS, |
379 | ati_force_enable_hpet); | 416 | ati_force_enable_hpet); |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 21b8e0a59780..2255782e8d4b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -302,7 +302,7 @@ static void __init relocate_initrd(void) | |||
302 | if (clen > MAX_MAP_CHUNK-slop) | 302 | if (clen > MAX_MAP_CHUNK-slop) |
303 | clen = MAX_MAP_CHUNK-slop; | 303 | clen = MAX_MAP_CHUNK-slop; |
304 | mapaddr = ramdisk_image & PAGE_MASK; | 304 | mapaddr = ramdisk_image & PAGE_MASK; |
305 | p = early_ioremap(mapaddr, clen+slop); | 305 | p = early_memremap(mapaddr, clen+slop); |
306 | memcpy(q, p+slop, clen); | 306 | memcpy(q, p+slop, clen); |
307 | early_iounmap(p, clen+slop); | 307 | early_iounmap(p, clen+slop); |
308 | q += clen; | 308 | q += clen; |
@@ -379,7 +379,7 @@ static void __init parse_setup_data(void) | |||
379 | return; | 379 | return; |
380 | pa_data = boot_params.hdr.setup_data; | 380 | pa_data = boot_params.hdr.setup_data; |
381 | while (pa_data) { | 381 | while (pa_data) { |
382 | data = early_ioremap(pa_data, PAGE_SIZE); | 382 | data = early_memremap(pa_data, PAGE_SIZE); |
383 | switch (data->type) { | 383 | switch (data->type) { |
384 | case SETUP_E820_EXT: | 384 | case SETUP_E820_EXT: |
385 | parse_e820_ext(data, pa_data); | 385 | parse_e820_ext(data, pa_data); |
@@ -402,7 +402,7 @@ static void __init e820_reserve_setup_data(void) | |||
402 | return; | 402 | return; |
403 | pa_data = boot_params.hdr.setup_data; | 403 | pa_data = boot_params.hdr.setup_data; |
404 | while (pa_data) { | 404 | while (pa_data) { |
405 | data = early_ioremap(pa_data, sizeof(*data)); | 405 | data = early_memremap(pa_data, sizeof(*data)); |
406 | e820_update_range(pa_data, sizeof(*data)+data->len, | 406 | e820_update_range(pa_data, sizeof(*data)+data->len, |
407 | E820_RAM, E820_RESERVED_KERN); | 407 | E820_RAM, E820_RESERVED_KERN); |
408 | found = 1; | 408 | found = 1; |
@@ -428,7 +428,7 @@ static void __init reserve_early_setup_data(void) | |||
428 | return; | 428 | return; |
429 | pa_data = boot_params.hdr.setup_data; | 429 | pa_data = boot_params.hdr.setup_data; |
430 | while (pa_data) { | 430 | while (pa_data) { |
431 | data = early_ioremap(pa_data, sizeof(*data)); | 431 | data = early_memremap(pa_data, sizeof(*data)); |
432 | sprintf(buf, "setup data %x", data->type); | 432 | sprintf(buf, "setup data %x", data->type); |
433 | reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf); | 433 | reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf); |
434 | pa_data = data->next; | 434 | pa_data = data->next; |
@@ -998,6 +998,8 @@ void __init setup_arch(char **cmdline_p) | |||
998 | */ | 998 | */ |
999 | acpi_boot_table_init(); | 999 | acpi_boot_table_init(); |
1000 | 1000 | ||
1001 | early_acpi_boot_init(); | ||
1002 | |||
1001 | #ifdef CONFIG_ACPI_NUMA | 1003 | #ifdef CONFIG_ACPI_NUMA |
1002 | /* | 1004 | /* |
1003 | * Parse SRAT to discover nodes. | 1005 | * Parse SRAT to discover nodes. |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 76b6f50978f7..8c3aca7cb343 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -334,14 +334,17 @@ static void __cpuinit start_secondary(void *unused) | |||
334 | * does not change while we are assigning vectors to cpus. Holding | 334 | * does not change while we are assigning vectors to cpus. Holding |
335 | * this lock ensures we don't half assign or remove an irq from a cpu. | 335 | * this lock ensures we don't half assign or remove an irq from a cpu. |
336 | */ | 336 | */ |
337 | ipi_call_lock_irq(); | 337 | ipi_call_lock(); |
338 | lock_vector_lock(); | 338 | lock_vector_lock(); |
339 | __setup_vector_irq(smp_processor_id()); | 339 | __setup_vector_irq(smp_processor_id()); |
340 | cpu_set(smp_processor_id(), cpu_online_map); | 340 | cpu_set(smp_processor_id(), cpu_online_map); |
341 | unlock_vector_lock(); | 341 | unlock_vector_lock(); |
342 | ipi_call_unlock_irq(); | 342 | ipi_call_unlock(); |
343 | per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; | 343 | per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; |
344 | 344 | ||
345 | /* enable local interrupts */ | ||
346 | local_irq_enable(); | ||
347 | |||
345 | setup_secondary_clock(); | 348 | setup_secondary_clock(); |
346 | 349 | ||
347 | wmb(); | 350 | wmb(); |
@@ -596,10 +599,12 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) | |||
596 | * Give the other CPU some time to accept the IPI. | 599 | * Give the other CPU some time to accept the IPI. |
597 | */ | 600 | */ |
598 | udelay(200); | 601 | udelay(200); |
599 | maxlvt = lapic_get_maxlvt(); | 602 | if (APIC_INTEGRATED(apic_version[phys_apicid])) { |
600 | if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ | 603 | maxlvt = lapic_get_maxlvt(); |
601 | apic_write(APIC_ESR, 0); | 604 | if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ |
602 | accept_status = (apic_read(APIC_ESR) & 0xEF); | 605 | apic_write(APIC_ESR, 0); |
606 | accept_status = (apic_read(APIC_ESR) & 0xEF); | ||
607 | } | ||
603 | pr_debug("NMI sent.\n"); | 608 | pr_debug("NMI sent.\n"); |
604 | 609 | ||
605 | if (send_status) | 610 | if (send_status) |
@@ -1256,39 +1261,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus) | |||
1256 | check_nmi_watchdog(); | 1261 | check_nmi_watchdog(); |
1257 | } | 1262 | } |
1258 | 1263 | ||
1259 | #ifdef CONFIG_HOTPLUG_CPU | ||
1260 | |||
1261 | static void remove_siblinginfo(int cpu) | ||
1262 | { | ||
1263 | int sibling; | ||
1264 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
1265 | |||
1266 | for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) { | ||
1267 | cpu_clear(cpu, per_cpu(cpu_core_map, sibling)); | ||
1268 | /*/ | ||
1269 | * last thread sibling in this cpu core going down | ||
1270 | */ | ||
1271 | if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1) | ||
1272 | cpu_data(sibling).booted_cores--; | ||
1273 | } | ||
1274 | |||
1275 | for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu)) | ||
1276 | cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling)); | ||
1277 | cpus_clear(per_cpu(cpu_sibling_map, cpu)); | ||
1278 | cpus_clear(per_cpu(cpu_core_map, cpu)); | ||
1279 | c->phys_proc_id = 0; | ||
1280 | c->cpu_core_id = 0; | ||
1281 | cpu_clear(cpu, cpu_sibling_setup_map); | ||
1282 | } | ||
1283 | |||
1284 | static int additional_cpus __initdata = -1; | ||
1285 | |||
1286 | static __init int setup_additional_cpus(char *s) | ||
1287 | { | ||
1288 | return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL; | ||
1289 | } | ||
1290 | early_param("additional_cpus", setup_additional_cpus); | ||
1291 | |||
1292 | /* | 1264 | /* |
1293 | * cpu_possible_map should be static, it cannot change as cpu's | 1265 | * cpu_possible_map should be static, it cannot change as cpu's |
1294 | * are onlined, or offlined. The reason is per-cpu data-structures | 1266 | * are onlined, or offlined. The reason is per-cpu data-structures |
@@ -1308,21 +1280,13 @@ early_param("additional_cpus", setup_additional_cpus); | |||
1308 | */ | 1280 | */ |
1309 | __init void prefill_possible_map(void) | 1281 | __init void prefill_possible_map(void) |
1310 | { | 1282 | { |
1311 | int i; | 1283 | int i, possible; |
1312 | int possible; | ||
1313 | 1284 | ||
1314 | /* no processor from mptable or madt */ | 1285 | /* no processor from mptable or madt */ |
1315 | if (!num_processors) | 1286 | if (!num_processors) |
1316 | num_processors = 1; | 1287 | num_processors = 1; |
1317 | 1288 | ||
1318 | if (additional_cpus == -1) { | 1289 | possible = num_processors + disabled_cpus; |
1319 | if (disabled_cpus > 0) | ||
1320 | additional_cpus = disabled_cpus; | ||
1321 | else | ||
1322 | additional_cpus = 0; | ||
1323 | } | ||
1324 | |||
1325 | possible = num_processors + additional_cpus; | ||
1326 | if (possible > NR_CPUS) | 1290 | if (possible > NR_CPUS) |
1327 | possible = NR_CPUS; | 1291 | possible = NR_CPUS; |
1328 | 1292 | ||
@@ -1335,6 +1299,31 @@ __init void prefill_possible_map(void) | |||
1335 | nr_cpu_ids = possible; | 1299 | nr_cpu_ids = possible; |
1336 | } | 1300 | } |
1337 | 1301 | ||
1302 | #ifdef CONFIG_HOTPLUG_CPU | ||
1303 | |||
1304 | static void remove_siblinginfo(int cpu) | ||
1305 | { | ||
1306 | int sibling; | ||
1307 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
1308 | |||
1309 | for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) { | ||
1310 | cpu_clear(cpu, per_cpu(cpu_core_map, sibling)); | ||
1311 | /*/ | ||
1312 | * last thread sibling in this cpu core going down | ||
1313 | */ | ||
1314 | if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1) | ||
1315 | cpu_data(sibling).booted_cores--; | ||
1316 | } | ||
1317 | |||
1318 | for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu)) | ||
1319 | cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling)); | ||
1320 | cpus_clear(per_cpu(cpu_sibling_map, cpu)); | ||
1321 | cpus_clear(per_cpu(cpu_core_map, cpu)); | ||
1322 | c->phys_proc_id = 0; | ||
1323 | c->cpu_core_id = 0; | ||
1324 | cpu_clear(cpu, cpu_sibling_setup_map); | ||
1325 | } | ||
1326 | |||
1338 | static void __ref remove_cpu_from_maps(int cpu) | 1327 | static void __ref remove_cpu_from_maps(int cpu) |
1339 | { | 1328 | { |
1340 | cpu_clear(cpu, cpu_online_map); | 1329 | cpu_clear(cpu, cpu_online_map); |
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index bbecf8b6bf96..77b400f06ea2 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c | |||
@@ -47,10 +47,9 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
47 | unsigned long pc = instruction_pointer(regs); | 47 | unsigned long pc = instruction_pointer(regs); |
48 | 48 | ||
49 | #ifdef CONFIG_SMP | 49 | #ifdef CONFIG_SMP |
50 | if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) && | 50 | if (!user_mode_vm(regs) && in_lock_functions(pc)) { |
51 | in_lock_functions(pc)) { | ||
52 | #ifdef CONFIG_FRAME_POINTER | 51 | #ifdef CONFIG_FRAME_POINTER |
53 | return *(unsigned long *)(regs->bp + 4); | 52 | return *(unsigned long *)(regs->bp + sizeof(long)); |
54 | #else | 53 | #else |
55 | unsigned long *sp = (unsigned long *)®s->sp; | 54 | unsigned long *sp = (unsigned long *)®s->sp; |
56 | 55 | ||
@@ -95,6 +94,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
95 | 94 | ||
96 | do_timer_interrupt_hook(); | 95 | do_timer_interrupt_hook(); |
97 | 96 | ||
97 | #ifdef CONFIG_MCA | ||
98 | if (MCA_bus) { | 98 | if (MCA_bus) { |
99 | /* The PS/2 uses level-triggered interrupts. You can't | 99 | /* The PS/2 uses level-triggered interrupts. You can't |
100 | turn them off, nor would you want to (any attempt to | 100 | turn them off, nor would you want to (any attempt to |
@@ -108,6 +108,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
108 | u8 irq_v = inb_p( 0x61 ); /* read the current state */ | 108 | u8 irq_v = inb_p( 0x61 ); /* read the current state */ |
109 | outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */ | 109 | outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */ |
110 | } | 110 | } |
111 | #endif | ||
111 | 112 | ||
112 | return IRQ_HANDLED; | 113 | return IRQ_HANDLED; |
113 | } | 114 | } |
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index e3d49c553af2..cb19d650c216 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
19 | #include <linux/mca.h> | ||
19 | 20 | ||
20 | #include <asm/i8253.h> | 21 | #include <asm/i8253.h> |
21 | #include <asm/hpet.h> | 22 | #include <asm/hpet.h> |
@@ -33,23 +34,34 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
33 | /* Assume the lock function has either no stack frame or a copy | 34 | /* Assume the lock function has either no stack frame or a copy |
34 | of flags from PUSHF | 35 | of flags from PUSHF |
35 | Eflags always has bits 22 and up cleared unlike kernel addresses. */ | 36 | Eflags always has bits 22 and up cleared unlike kernel addresses. */ |
36 | if (!user_mode(regs) && in_lock_functions(pc)) { | 37 | if (!user_mode_vm(regs) && in_lock_functions(pc)) { |
38 | #ifdef CONFIG_FRAME_POINTER | ||
39 | return *(unsigned long *)(regs->bp + sizeof(long)); | ||
40 | #else | ||
37 | unsigned long *sp = (unsigned long *)regs->sp; | 41 | unsigned long *sp = (unsigned long *)regs->sp; |
38 | if (sp[0] >> 22) | 42 | if (sp[0] >> 22) |
39 | return sp[0]; | 43 | return sp[0]; |
40 | if (sp[1] >> 22) | 44 | if (sp[1] >> 22) |
41 | return sp[1]; | 45 | return sp[1]; |
46 | #endif | ||
42 | } | 47 | } |
43 | return pc; | 48 | return pc; |
44 | } | 49 | } |
45 | EXPORT_SYMBOL(profile_pc); | 50 | EXPORT_SYMBOL(profile_pc); |
46 | 51 | ||
47 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) | 52 | irqreturn_t timer_interrupt(int irq, void *dev_id) |
48 | { | 53 | { |
49 | add_pda(irq0_irqs, 1); | 54 | add_pda(irq0_irqs, 1); |
50 | 55 | ||
51 | global_clock_event->event_handler(global_clock_event); | 56 | global_clock_event->event_handler(global_clock_event); |
52 | 57 | ||
58 | #ifdef CONFIG_MCA | ||
59 | if (MCA_bus) { | ||
60 | u8 irq_v = inb_p(0x61); /* read the current state */ | ||
61 | outb_p(irq_v|0x80, 0x61); /* reset the IRQ */ | ||
62 | } | ||
63 | #endif | ||
64 | |||
53 | return IRQ_HANDLED; | 65 | return IRQ_HANDLED; |
54 | } | 66 | } |
55 | 67 | ||
@@ -100,7 +112,7 @@ unsigned long __init calibrate_cpu(void) | |||
100 | } | 112 | } |
101 | 113 | ||
102 | static struct irqaction irq0 = { | 114 | static struct irqaction irq0 = { |
103 | .handler = timer_event_interrupt, | 115 | .handler = timer_interrupt, |
104 | .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, | 116 | .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, |
105 | .mask = CPU_MASK_NONE, | 117 | .mask = CPU_MASK_NONE, |
106 | .name = "timer" | 118 | .name = "timer" |
@@ -111,16 +123,13 @@ void __init hpet_time_init(void) | |||
111 | if (!hpet_enable()) | 123 | if (!hpet_enable()) |
112 | setup_pit_timer(); | 124 | setup_pit_timer(); |
113 | 125 | ||
126 | irq0.mask = cpumask_of_cpu(0); | ||
114 | setup_irq(0, &irq0); | 127 | setup_irq(0, &irq0); |
115 | } | 128 | } |
116 | 129 | ||
117 | void __init time_init(void) | 130 | void __init time_init(void) |
118 | { | 131 | { |
119 | tsc_init(); | 132 | tsc_init(); |
120 | if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) | ||
121 | vgetcpu_mode = VGETCPU_RDTSCP; | ||
122 | else | ||
123 | vgetcpu_mode = VGETCPU_LSL; | ||
124 | 133 | ||
125 | late_time_init = choose_time_init(); | 134 | late_time_init = choose_time_init(); |
126 | } | 135 | } |
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps.c index 0429c5de5ea9..e062974cce34 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps.c | |||
@@ -7,13 +7,11 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * 'Traps.c' handles hardware traps and faults after we have saved some | 10 | * Handle hardware traps and faults. |
11 | * state in 'asm.s'. | ||
12 | */ | 11 | */ |
13 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
14 | #include <linux/kallsyms.h> | 13 | #include <linux/kallsyms.h> |
15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
16 | #include <linux/highmem.h> | ||
17 | #include <linux/kprobes.h> | 15 | #include <linux/kprobes.h> |
18 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
19 | #include <linux/utsname.h> | 17 | #include <linux/utsname.h> |
@@ -32,6 +30,8 @@ | |||
32 | #include <linux/bug.h> | 30 | #include <linux/bug.h> |
33 | #include <linux/nmi.h> | 31 | #include <linux/nmi.h> |
34 | #include <linux/mm.h> | 32 | #include <linux/mm.h> |
33 | #include <linux/smp.h> | ||
34 | #include <linux/io.h> | ||
35 | 35 | ||
36 | #ifdef CONFIG_EISA | 36 | #ifdef CONFIG_EISA |
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
@@ -46,21 +46,31 @@ | |||
46 | #include <linux/edac.h> | 46 | #include <linux/edac.h> |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #include <asm/arch_hooks.h> | ||
50 | #include <asm/stacktrace.h> | 49 | #include <asm/stacktrace.h> |
51 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
52 | #include <asm/debugreg.h> | 51 | #include <asm/debugreg.h> |
53 | #include <asm/atomic.h> | 52 | #include <asm/atomic.h> |
54 | #include <asm/system.h> | 53 | #include <asm/system.h> |
55 | #include <asm/unwind.h> | 54 | #include <asm/unwind.h> |
55 | #include <asm/traps.h> | ||
56 | #include <asm/desc.h> | 56 | #include <asm/desc.h> |
57 | #include <asm/i387.h> | 57 | #include <asm/i387.h> |
58 | |||
59 | #include <mach_traps.h> | ||
60 | |||
61 | #ifdef CONFIG_X86_64 | ||
62 | #include <asm/pgalloc.h> | ||
63 | #include <asm/proto.h> | ||
64 | #include <asm/pda.h> | ||
65 | #else | ||
66 | #include <asm/processor-flags.h> | ||
67 | #include <asm/arch_hooks.h> | ||
58 | #include <asm/nmi.h> | 68 | #include <asm/nmi.h> |
59 | #include <asm/smp.h> | 69 | #include <asm/smp.h> |
60 | #include <asm/io.h> | 70 | #include <asm/io.h> |
61 | #include <asm/traps.h> | 71 | #include <asm/traps.h> |
62 | 72 | ||
63 | #include "mach_traps.h" | 73 | #include "cpu/mcheck/mce.h" |
64 | 74 | ||
65 | DECLARE_BITMAP(used_vectors, NR_VECTORS); | 75 | DECLARE_BITMAP(used_vectors, NR_VECTORS); |
66 | EXPORT_SYMBOL_GPL(used_vectors); | 76 | EXPORT_SYMBOL_GPL(used_vectors); |
@@ -77,418 +87,104 @@ char ignore_fpu_irq; | |||
77 | */ | 87 | */ |
78 | gate_desc idt_table[256] | 88 | gate_desc idt_table[256] |
79 | __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; | 89 | __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; |
80 | |||
81 | int panic_on_unrecovered_nmi; | ||
82 | int kstack_depth_to_print = 24; | ||
83 | static unsigned int code_bytes = 64; | ||
84 | static int ignore_nmis; | ||
85 | static int die_counter; | ||
86 | |||
87 | void printk_address(unsigned long address, int reliable) | ||
88 | { | ||
89 | #ifdef CONFIG_KALLSYMS | ||
90 | unsigned long offset = 0; | ||
91 | unsigned long symsize; | ||
92 | const char *symname; | ||
93 | char *modname; | ||
94 | char *delim = ":"; | ||
95 | char namebuf[KSYM_NAME_LEN]; | ||
96 | char reliab[4] = ""; | ||
97 | |||
98 | symname = kallsyms_lookup(address, &symsize, &offset, | ||
99 | &modname, namebuf); | ||
100 | if (!symname) { | ||
101 | printk(" [<%08lx>]\n", address); | ||
102 | return; | ||
103 | } | ||
104 | if (!reliable) | ||
105 | strcpy(reliab, "? "); | ||
106 | |||
107 | if (!modname) | ||
108 | modname = delim = ""; | ||
109 | printk(" [<%08lx>] %s%s%s%s%s+0x%lx/0x%lx\n", | ||
110 | address, reliab, delim, modname, delim, symname, offset, symsize); | ||
111 | #else | ||
112 | printk(" [<%08lx>]\n", address); | ||
113 | #endif | 90 | #endif |
114 | } | ||
115 | |||
116 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
117 | void *p, unsigned int size) | ||
118 | { | ||
119 | void *t = tinfo; | ||
120 | return p > t && p <= t + THREAD_SIZE - size; | ||
121 | } | ||
122 | |||
123 | /* The form of the top of the frame on the stack */ | ||
124 | struct stack_frame { | ||
125 | struct stack_frame *next_frame; | ||
126 | unsigned long return_address; | ||
127 | }; | ||
128 | |||
129 | static inline unsigned long | ||
130 | print_context_stack(struct thread_info *tinfo, | ||
131 | unsigned long *stack, unsigned long bp, | ||
132 | const struct stacktrace_ops *ops, void *data) | ||
133 | { | ||
134 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
135 | |||
136 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { | ||
137 | unsigned long addr; | ||
138 | |||
139 | addr = *stack; | ||
140 | if (__kernel_text_address(addr)) { | ||
141 | if ((unsigned long) stack == bp + 4) { | ||
142 | ops->address(data, addr, 1); | ||
143 | frame = frame->next_frame; | ||
144 | bp = (unsigned long) frame; | ||
145 | } else { | ||
146 | ops->address(data, addr, bp == 0); | ||
147 | } | ||
148 | } | ||
149 | stack++; | ||
150 | } | ||
151 | return bp; | ||
152 | } | ||
153 | |||
154 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
155 | unsigned long *stack, unsigned long bp, | ||
156 | const struct stacktrace_ops *ops, void *data) | ||
157 | { | ||
158 | if (!task) | ||
159 | task = current; | ||
160 | |||
161 | if (!stack) { | ||
162 | unsigned long dummy; | ||
163 | stack = &dummy; | ||
164 | if (task != current) | ||
165 | stack = (unsigned long *)task->thread.sp; | ||
166 | } | ||
167 | |||
168 | #ifdef CONFIG_FRAME_POINTER | ||
169 | if (!bp) { | ||
170 | if (task == current) { | ||
171 | /* Grab bp right from our regs */ | ||
172 | asm("movl %%ebp, %0" : "=r" (bp) :); | ||
173 | } else { | ||
174 | /* bp is the last reg pushed by switch_to */ | ||
175 | bp = *(unsigned long *) task->thread.sp; | ||
176 | } | ||
177 | } | ||
178 | #endif | ||
179 | |||
180 | for (;;) { | ||
181 | struct thread_info *context; | ||
182 | |||
183 | context = (struct thread_info *) | ||
184 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | ||
185 | bp = print_context_stack(context, stack, bp, ops, data); | ||
186 | /* | ||
187 | * Should be after the line below, but somewhere | ||
188 | * in early boot context comes out corrupted and we | ||
189 | * can't reference it: | ||
190 | */ | ||
191 | if (ops->stack(data, "IRQ") < 0) | ||
192 | break; | ||
193 | stack = (unsigned long *)context->previous_esp; | ||
194 | if (!stack) | ||
195 | break; | ||
196 | touch_nmi_watchdog(); | ||
197 | } | ||
198 | } | ||
199 | EXPORT_SYMBOL(dump_trace); | ||
200 | |||
201 | static void | ||
202 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
203 | { | ||
204 | printk(data); | ||
205 | print_symbol(msg, symbol); | ||
206 | printk("\n"); | ||
207 | } | ||
208 | |||
209 | static void print_trace_warning(void *data, char *msg) | ||
210 | { | ||
211 | printk("%s%s\n", (char *)data, msg); | ||
212 | } | ||
213 | 91 | ||
214 | static int print_trace_stack(void *data, char *name) | 92 | static int ignore_nmis; |
215 | { | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Print one address/symbol entries per line. | ||
221 | */ | ||
222 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
223 | { | ||
224 | printk("%s [<%08lx>] ", (char *)data, addr); | ||
225 | if (!reliable) | ||
226 | printk("? "); | ||
227 | print_symbol("%s\n", addr); | ||
228 | touch_nmi_watchdog(); | ||
229 | } | ||
230 | |||
231 | static const struct stacktrace_ops print_trace_ops = { | ||
232 | .warning = print_trace_warning, | ||
233 | .warning_symbol = print_trace_warning_symbol, | ||
234 | .stack = print_trace_stack, | ||
235 | .address = print_trace_address, | ||
236 | }; | ||
237 | 93 | ||
238 | static void | 94 | static inline void conditional_sti(struct pt_regs *regs) |
239 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
240 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
241 | { | 95 | { |
242 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | 96 | if (regs->flags & X86_EFLAGS_IF) |
243 | printk("%s =======================\n", log_lvl); | 97 | local_irq_enable(); |
244 | } | 98 | } |
245 | 99 | ||
246 | void show_trace(struct task_struct *task, struct pt_regs *regs, | 100 | static inline void preempt_conditional_sti(struct pt_regs *regs) |
247 | unsigned long *stack, unsigned long bp) | ||
248 | { | 101 | { |
249 | show_trace_log_lvl(task, regs, stack, bp, ""); | 102 | inc_preempt_count(); |
103 | if (regs->flags & X86_EFLAGS_IF) | ||
104 | local_irq_enable(); | ||
250 | } | 105 | } |
251 | 106 | ||
252 | static void | 107 | static inline void preempt_conditional_cli(struct pt_regs *regs) |
253 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
254 | unsigned long *sp, unsigned long bp, char *log_lvl) | ||
255 | { | 108 | { |
256 | unsigned long *stack; | 109 | if (regs->flags & X86_EFLAGS_IF) |
257 | int i; | 110 | local_irq_disable(); |
258 | 111 | dec_preempt_count(); | |
259 | if (sp == NULL) { | ||
260 | if (task) | ||
261 | sp = (unsigned long *)task->thread.sp; | ||
262 | else | ||
263 | sp = (unsigned long *)&sp; | ||
264 | } | ||
265 | |||
266 | stack = sp; | ||
267 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
268 | if (kstack_end(stack)) | ||
269 | break; | ||
270 | if (i && ((i % 8) == 0)) | ||
271 | printk("\n%s ", log_lvl); | ||
272 | printk("%08lx ", *stack++); | ||
273 | } | ||
274 | printk("\n%sCall Trace:\n", log_lvl); | ||
275 | |||
276 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | ||
277 | } | 112 | } |
278 | 113 | ||
279 | void show_stack(struct task_struct *task, unsigned long *sp) | 114 | #ifdef CONFIG_X86_32 |
115 | static inline void | ||
116 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | ||
280 | { | 117 | { |
281 | printk(" "); | 118 | if (!user_mode_vm(regs)) |
282 | show_stack_log_lvl(task, NULL, sp, 0, ""); | 119 | die(str, regs, err); |
283 | } | 120 | } |
284 | 121 | ||
285 | /* | 122 | /* |
286 | * The architecture-independent dump_stack generator | 123 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an |
124 | * invalid offset set (the LAZY one) and the faulting thread has | ||
125 | * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS, | ||
126 | * we set the offset field correctly and return 1. | ||
287 | */ | 127 | */ |
288 | void dump_stack(void) | 128 | static int lazy_iobitmap_copy(void) |
289 | { | 129 | { |
290 | unsigned long bp = 0; | 130 | struct thread_struct *thread; |
291 | unsigned long stack; | 131 | struct tss_struct *tss; |
292 | 132 | int cpu; | |
293 | #ifdef CONFIG_FRAME_POINTER | ||
294 | if (!bp) | ||
295 | asm("movl %%ebp, %0" : "=r" (bp):); | ||
296 | #endif | ||
297 | |||
298 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
299 | current->pid, current->comm, print_tainted(), | ||
300 | init_utsname()->release, | ||
301 | (int)strcspn(init_utsname()->version, " "), | ||
302 | init_utsname()->version); | ||
303 | |||
304 | show_trace(current, NULL, &stack, bp); | ||
305 | } | ||
306 | |||
307 | EXPORT_SYMBOL(dump_stack); | ||
308 | |||
309 | void show_registers(struct pt_regs *regs) | ||
310 | { | ||
311 | int i; | ||
312 | 133 | ||
313 | print_modules(); | 134 | cpu = get_cpu(); |
314 | __show_registers(regs, 0); | 135 | tss = &per_cpu(init_tss, cpu); |
136 | thread = ¤t->thread; | ||
315 | 137 | ||
316 | printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", | 138 | if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && |
317 | TASK_COMM_LEN, current->comm, task_pid_nr(current), | 139 | thread->io_bitmap_ptr) { |
318 | current_thread_info(), current, task_thread_info(current)); | 140 | memcpy(tss->io_bitmap, thread->io_bitmap_ptr, |
319 | /* | 141 | thread->io_bitmap_max); |
320 | * When in-kernel, we also print out the stack and code at the | 142 | /* |
321 | * time of the fault.. | 143 | * If the previously set map was extending to higher ports |
322 | */ | 144 | * than the current one, pad extra space with 0xff (no access). |
323 | if (!user_mode_vm(regs)) { | 145 | */ |
324 | unsigned int code_prologue = code_bytes * 43 / 64; | 146 | if (thread->io_bitmap_max < tss->io_bitmap_max) { |
325 | unsigned int code_len = code_bytes; | 147 | memset((char *) tss->io_bitmap + |
326 | unsigned char c; | 148 | thread->io_bitmap_max, 0xff, |
327 | u8 *ip; | 149 | tss->io_bitmap_max - thread->io_bitmap_max); |
328 | |||
329 | printk("\n" KERN_EMERG "Stack: "); | ||
330 | show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG); | ||
331 | |||
332 | printk(KERN_EMERG "Code: "); | ||
333 | |||
334 | ip = (u8 *)regs->ip - code_prologue; | ||
335 | if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { | ||
336 | /* try starting at EIP */ | ||
337 | ip = (u8 *)regs->ip; | ||
338 | code_len = code_len - code_prologue + 1; | ||
339 | } | ||
340 | for (i = 0; i < code_len; i++, ip++) { | ||
341 | if (ip < (u8 *)PAGE_OFFSET || | ||
342 | probe_kernel_address(ip, c)) { | ||
343 | printk(" Bad EIP value."); | ||
344 | break; | ||
345 | } | ||
346 | if (ip == (u8 *)regs->ip) | ||
347 | printk("<%02x> ", c); | ||
348 | else | ||
349 | printk("%02x ", c); | ||
350 | } | 150 | } |
351 | } | 151 | tss->io_bitmap_max = thread->io_bitmap_max; |
352 | printk("\n"); | 152 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; |
353 | } | 153 | tss->io_bitmap_owner = thread; |
354 | 154 | put_cpu(); | |
355 | int is_valid_bugaddr(unsigned long ip) | ||
356 | { | ||
357 | unsigned short ud2; | ||
358 | |||
359 | if (ip < PAGE_OFFSET) | ||
360 | return 0; | ||
361 | if (probe_kernel_address((unsigned short *)ip, ud2)) | ||
362 | return 0; | ||
363 | |||
364 | return ud2 == 0x0b0f; | ||
365 | } | ||
366 | |||
367 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
368 | static int die_owner = -1; | ||
369 | static unsigned int die_nest_count; | ||
370 | |||
371 | unsigned __kprobes long oops_begin(void) | ||
372 | { | ||
373 | unsigned long flags; | ||
374 | |||
375 | oops_enter(); | ||
376 | |||
377 | if (die_owner != raw_smp_processor_id()) { | ||
378 | console_verbose(); | ||
379 | raw_local_irq_save(flags); | ||
380 | __raw_spin_lock(&die_lock); | ||
381 | die_owner = smp_processor_id(); | ||
382 | die_nest_count = 0; | ||
383 | bust_spinlocks(1); | ||
384 | } else { | ||
385 | raw_local_irq_save(flags); | ||
386 | } | ||
387 | die_nest_count++; | ||
388 | return flags; | ||
389 | } | ||
390 | |||
391 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
392 | { | ||
393 | bust_spinlocks(0); | ||
394 | die_owner = -1; | ||
395 | add_taint(TAINT_DIE); | ||
396 | __raw_spin_unlock(&die_lock); | ||
397 | raw_local_irq_restore(flags); | ||
398 | |||
399 | if (!regs) | ||
400 | return; | ||
401 | |||
402 | if (kexec_should_crash(current)) | ||
403 | crash_kexec(regs); | ||
404 | |||
405 | if (in_interrupt()) | ||
406 | panic("Fatal exception in interrupt"); | ||
407 | |||
408 | if (panic_on_oops) | ||
409 | panic("Fatal exception"); | ||
410 | |||
411 | oops_exit(); | ||
412 | do_exit(signr); | ||
413 | } | ||
414 | |||
415 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
416 | { | ||
417 | unsigned short ss; | ||
418 | unsigned long sp; | ||
419 | 155 | ||
420 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | ||
421 | #ifdef CONFIG_PREEMPT | ||
422 | printk("PREEMPT "); | ||
423 | #endif | ||
424 | #ifdef CONFIG_SMP | ||
425 | printk("SMP "); | ||
426 | #endif | ||
427 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
428 | printk("DEBUG_PAGEALLOC"); | ||
429 | #endif | ||
430 | printk("\n"); | ||
431 | if (notify_die(DIE_OOPS, str, regs, err, | ||
432 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
433 | return 1; | 156 | return 1; |
434 | |||
435 | show_registers(regs); | ||
436 | /* Executive summary in case the oops scrolled away */ | ||
437 | sp = (unsigned long) (®s->sp); | ||
438 | savesegment(ss, ss); | ||
439 | if (user_mode(regs)) { | ||
440 | sp = regs->sp; | ||
441 | ss = regs->ss & 0xffff; | ||
442 | } | 157 | } |
443 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | 158 | put_cpu(); |
444 | print_symbol("%s", regs->ip); | ||
445 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * This is gone through when something in the kernel has done something bad | ||
451 | * and is about to be terminated: | ||
452 | */ | ||
453 | void die(const char *str, struct pt_regs *regs, long err) | ||
454 | { | ||
455 | unsigned long flags = oops_begin(); | ||
456 | |||
457 | if (die_nest_count < 3) { | ||
458 | report_bug(regs->ip, regs); | ||
459 | |||
460 | if (__die(str, regs, err)) | ||
461 | regs = NULL; | ||
462 | } else { | ||
463 | printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); | ||
464 | } | ||
465 | |||
466 | oops_end(flags, regs, SIGSEGV); | ||
467 | } | ||
468 | 159 | ||
469 | static inline void | 160 | return 0; |
470 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | ||
471 | { | ||
472 | if (!user_mode_vm(regs)) | ||
473 | die(str, regs, err); | ||
474 | } | 161 | } |
162 | #endif | ||
475 | 163 | ||
476 | static void __kprobes | 164 | static void __kprobes |
477 | do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs *regs, | 165 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, |
478 | long error_code, siginfo_t *info) | 166 | long error_code, siginfo_t *info) |
479 | { | 167 | { |
480 | struct task_struct *tsk = current; | 168 | struct task_struct *tsk = current; |
481 | 169 | ||
170 | #ifdef CONFIG_X86_32 | ||
482 | if (regs->flags & X86_VM_MASK) { | 171 | if (regs->flags & X86_VM_MASK) { |
483 | if (vm86) | 172 | /* |
173 | * traps 0, 1, 3, 4, and 5 should be forwarded to vm86. | ||
174 | * On nmi (interrupt 2), do_trap should not be called. | ||
175 | */ | ||
176 | if (trapnr < 6) | ||
484 | goto vm86_trap; | 177 | goto vm86_trap; |
485 | goto trap_signal; | 178 | goto trap_signal; |
486 | } | 179 | } |
180 | #endif | ||
487 | 181 | ||
488 | if (!user_mode(regs)) | 182 | if (!user_mode(regs)) |
489 | goto kernel_trap; | 183 | goto kernel_trap; |
490 | 184 | ||
185 | #ifdef CONFIG_X86_32 | ||
491 | trap_signal: | 186 | trap_signal: |
187 | #endif | ||
492 | /* | 188 | /* |
493 | * We want error_code and trap_no set for userspace faults and | 189 | * We want error_code and trap_no set for userspace faults and |
494 | * kernelspace faults which result in die(), but not | 190 | * kernelspace faults which result in die(), but not |
@@ -501,6 +197,18 @@ trap_signal: | |||
501 | tsk->thread.error_code = error_code; | 197 | tsk->thread.error_code = error_code; |
502 | tsk->thread.trap_no = trapnr; | 198 | tsk->thread.trap_no = trapnr; |
503 | 199 | ||
200 | #ifdef CONFIG_X86_64 | ||
201 | if (show_unhandled_signals && unhandled_signal(tsk, signr) && | ||
202 | printk_ratelimit()) { | ||
203 | printk(KERN_INFO | ||
204 | "%s[%d] trap %s ip:%lx sp:%lx error:%lx", | ||
205 | tsk->comm, tsk->pid, str, | ||
206 | regs->ip, regs->sp, error_code); | ||
207 | print_vma_addr(" in ", regs->ip); | ||
208 | printk("\n"); | ||
209 | } | ||
210 | #endif | ||
211 | |||
504 | if (info) | 212 | if (info) |
505 | force_sig_info(signr, info, tsk); | 213 | force_sig_info(signr, info, tsk); |
506 | else | 214 | else |
@@ -515,29 +223,29 @@ kernel_trap: | |||
515 | } | 223 | } |
516 | return; | 224 | return; |
517 | 225 | ||
226 | #ifdef CONFIG_X86_32 | ||
518 | vm86_trap: | 227 | vm86_trap: |
519 | if (handle_vm86_trap((struct kernel_vm86_regs *) regs, | 228 | if (handle_vm86_trap((struct kernel_vm86_regs *) regs, |
520 | error_code, trapnr)) | 229 | error_code, trapnr)) |
521 | goto trap_signal; | 230 | goto trap_signal; |
522 | return; | 231 | return; |
232 | #endif | ||
523 | } | 233 | } |
524 | 234 | ||
525 | #define DO_ERROR(trapnr, signr, str, name) \ | 235 | #define DO_ERROR(trapnr, signr, str, name) \ |
526 | void do_##name(struct pt_regs *regs, long error_code) \ | 236 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ |
527 | { \ | 237 | { \ |
528 | trace_hardirqs_fixup(); \ | ||
529 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 238 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
530 | == NOTIFY_STOP) \ | 239 | == NOTIFY_STOP) \ |
531 | return; \ | 240 | return; \ |
532 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ | 241 | conditional_sti(regs); \ |
242 | do_trap(trapnr, signr, str, regs, error_code, NULL); \ | ||
533 | } | 243 | } |
534 | 244 | ||
535 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ | 245 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ |
536 | void do_##name(struct pt_regs *regs, long error_code) \ | 246 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ |
537 | { \ | 247 | { \ |
538 | siginfo_t info; \ | 248 | siginfo_t info; \ |
539 | if (irq) \ | ||
540 | local_irq_enable(); \ | ||
541 | info.si_signo = signr; \ | 249 | info.si_signo = signr; \ |
542 | info.si_errno = 0; \ | 250 | info.si_errno = 0; \ |
543 | info.si_code = sicode; \ | 251 | info.si_code = sicode; \ |
@@ -545,90 +253,68 @@ void do_##name(struct pt_regs *regs, long error_code) \ | |||
545 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 253 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
546 | == NOTIFY_STOP) \ | 254 | == NOTIFY_STOP) \ |
547 | return; \ | 255 | return; \ |
548 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ | 256 | conditional_sti(regs); \ |
257 | do_trap(trapnr, signr, str, regs, error_code, &info); \ | ||
549 | } | 258 | } |
550 | 259 | ||
551 | #define DO_VM86_ERROR(trapnr, signr, str, name) \ | 260 | DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) |
552 | void do_##name(struct pt_regs *regs, long error_code) \ | 261 | DO_ERROR(4, SIGSEGV, "overflow", overflow) |
553 | { \ | 262 | DO_ERROR(5, SIGSEGV, "bounds", bounds) |
554 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 263 | DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip) |
555 | == NOTIFY_STOP) \ | ||
556 | return; \ | ||
557 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ | ||
558 | } | ||
559 | |||
560 | #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | ||
561 | void do_##name(struct pt_regs *regs, long error_code) \ | ||
562 | { \ | ||
563 | siginfo_t info; \ | ||
564 | info.si_signo = signr; \ | ||
565 | info.si_errno = 0; \ | ||
566 | info.si_code = sicode; \ | ||
567 | info.si_addr = (void __user *)siaddr; \ | ||
568 | trace_hardirqs_fixup(); \ | ||
569 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
570 | == NOTIFY_STOP) \ | ||
571 | return; \ | ||
572 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ | ||
573 | } | ||
574 | |||
575 | DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) | ||
576 | #ifndef CONFIG_KPROBES | ||
577 | DO_VM86_ERROR(3, SIGTRAP, "int3", int3) | ||
578 | #endif | ||
579 | DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow) | ||
580 | DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds) | ||
581 | DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0) | ||
582 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | 264 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) |
583 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | 265 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) |
584 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | 266 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) |
267 | #ifdef CONFIG_X86_32 | ||
585 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | 268 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) |
586 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) | 269 | #endif |
587 | DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1) | 270 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) |
271 | |||
272 | #ifdef CONFIG_X86_64 | ||
273 | /* Runs on IST stack */ | ||
274 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | ||
275 | { | ||
276 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, | ||
277 | 12, SIGBUS) == NOTIFY_STOP) | ||
278 | return; | ||
279 | preempt_conditional_sti(regs); | ||
280 | do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL); | ||
281 | preempt_conditional_cli(regs); | ||
282 | } | ||
283 | |||
284 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | ||
285 | { | ||
286 | static const char str[] = "double fault"; | ||
287 | struct task_struct *tsk = current; | ||
288 | |||
289 | /* Return not checked because double check cannot be ignored */ | ||
290 | notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV); | ||
588 | 291 | ||
589 | void __kprobes | 292 | tsk->thread.error_code = error_code; |
293 | tsk->thread.trap_no = 8; | ||
294 | |||
295 | /* This is always a kernel trap and never fixable (and thus must | ||
296 | never return). */ | ||
297 | for (;;) | ||
298 | die(str, regs, error_code); | ||
299 | } | ||
300 | #endif | ||
301 | |||
302 | dotraplinkage void __kprobes | ||
590 | do_general_protection(struct pt_regs *regs, long error_code) | 303 | do_general_protection(struct pt_regs *regs, long error_code) |
591 | { | 304 | { |
592 | struct task_struct *tsk; | 305 | struct task_struct *tsk; |
593 | struct thread_struct *thread; | ||
594 | struct tss_struct *tss; | ||
595 | int cpu; | ||
596 | 306 | ||
597 | cpu = get_cpu(); | 307 | conditional_sti(regs); |
598 | tss = &per_cpu(init_tss, cpu); | ||
599 | thread = ¤t->thread; | ||
600 | |||
601 | /* | ||
602 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an | ||
603 | * invalid offset set (the LAZY one) and the faulting thread has | ||
604 | * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS | ||
605 | * and we set the offset field correctly. Then we let the CPU to | ||
606 | * restart the faulting instruction. | ||
607 | */ | ||
608 | if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && | ||
609 | thread->io_bitmap_ptr) { | ||
610 | memcpy(tss->io_bitmap, thread->io_bitmap_ptr, | ||
611 | thread->io_bitmap_max); | ||
612 | /* | ||
613 | * If the previously set map was extending to higher ports | ||
614 | * than the current one, pad extra space with 0xff (no access). | ||
615 | */ | ||
616 | if (thread->io_bitmap_max < tss->io_bitmap_max) { | ||
617 | memset((char *) tss->io_bitmap + | ||
618 | thread->io_bitmap_max, 0xff, | ||
619 | tss->io_bitmap_max - thread->io_bitmap_max); | ||
620 | } | ||
621 | tss->io_bitmap_max = thread->io_bitmap_max; | ||
622 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; | ||
623 | tss->io_bitmap_owner = thread; | ||
624 | put_cpu(); | ||
625 | 308 | ||
309 | #ifdef CONFIG_X86_32 | ||
310 | if (lazy_iobitmap_copy()) { | ||
311 | /* restart the faulting instruction */ | ||
626 | return; | 312 | return; |
627 | } | 313 | } |
628 | put_cpu(); | ||
629 | 314 | ||
630 | if (regs->flags & X86_VM_MASK) | 315 | if (regs->flags & X86_VM_MASK) |
631 | goto gp_in_vm86; | 316 | goto gp_in_vm86; |
317 | #endif | ||
632 | 318 | ||
633 | tsk = current; | 319 | tsk = current; |
634 | if (!user_mode(regs)) | 320 | if (!user_mode(regs)) |
@@ -650,10 +336,12 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
650 | force_sig(SIGSEGV, tsk); | 336 | force_sig(SIGSEGV, tsk); |
651 | return; | 337 | return; |
652 | 338 | ||
339 | #ifdef CONFIG_X86_32 | ||
653 | gp_in_vm86: | 340 | gp_in_vm86: |
654 | local_irq_enable(); | 341 | local_irq_enable(); |
655 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | 342 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); |
656 | return; | 343 | return; |
344 | #endif | ||
657 | 345 | ||
658 | gp_in_kernel: | 346 | gp_in_kernel: |
659 | if (fixup_exception(regs)) | 347 | if (fixup_exception(regs)) |
@@ -690,7 +378,8 @@ mem_parity_error(unsigned char reason, struct pt_regs *regs) | |||
690 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 378 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
691 | 379 | ||
692 | /* Clear and disable the memory parity error line. */ | 380 | /* Clear and disable the memory parity error line. */ |
693 | clear_mem_error(reason); | 381 | reason = (reason & 0xf) | 4; |
382 | outb(reason, 0x61); | ||
694 | } | 383 | } |
695 | 384 | ||
696 | static notrace __kprobes void | 385 | static notrace __kprobes void |
@@ -716,7 +405,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs) | |||
716 | static notrace __kprobes void | 405 | static notrace __kprobes void |
717 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | 406 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) |
718 | { | 407 | { |
719 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 408 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == |
409 | NOTIFY_STOP) | ||
720 | return; | 410 | return; |
721 | #ifdef CONFIG_MCA | 411 | #ifdef CONFIG_MCA |
722 | /* | 412 | /* |
@@ -739,41 +429,6 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
739 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 429 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
740 | } | 430 | } |
741 | 431 | ||
742 | static DEFINE_SPINLOCK(nmi_print_lock); | ||
743 | |||
744 | void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
745 | { | ||
746 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
747 | return; | ||
748 | |||
749 | spin_lock(&nmi_print_lock); | ||
750 | /* | ||
751 | * We are in trouble anyway, lets at least try | ||
752 | * to get a message out: | ||
753 | */ | ||
754 | bust_spinlocks(1); | ||
755 | printk(KERN_EMERG "%s", str); | ||
756 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
757 | smp_processor_id(), regs->ip); | ||
758 | show_registers(regs); | ||
759 | if (do_panic) | ||
760 | panic("Non maskable interrupt"); | ||
761 | console_silent(); | ||
762 | spin_unlock(&nmi_print_lock); | ||
763 | bust_spinlocks(0); | ||
764 | |||
765 | /* | ||
766 | * If we are in kernel we are probably nested up pretty bad | ||
767 | * and might aswell get out now while we still can: | ||
768 | */ | ||
769 | if (!user_mode_vm(regs)) { | ||
770 | current->thread.trap_no = 2; | ||
771 | crash_kexec(regs); | ||
772 | } | ||
773 | |||
774 | do_exit(SIGSEGV); | ||
775 | } | ||
776 | |||
777 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | 432 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) |
778 | { | 433 | { |
779 | unsigned char reason = 0; | 434 | unsigned char reason = 0; |
@@ -812,22 +467,25 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
812 | mem_parity_error(reason, regs); | 467 | mem_parity_error(reason, regs); |
813 | if (reason & 0x40) | 468 | if (reason & 0x40) |
814 | io_check_error(reason, regs); | 469 | io_check_error(reason, regs); |
470 | #ifdef CONFIG_X86_32 | ||
815 | /* | 471 | /* |
816 | * Reassert NMI in case it became active meanwhile | 472 | * Reassert NMI in case it became active meanwhile |
817 | * as it's edge-triggered: | 473 | * as it's edge-triggered: |
818 | */ | 474 | */ |
819 | reassert_nmi(); | 475 | reassert_nmi(); |
476 | #endif | ||
820 | } | 477 | } |
821 | 478 | ||
822 | notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code) | 479 | dotraplinkage notrace __kprobes void |
480 | do_nmi(struct pt_regs *regs, long error_code) | ||
823 | { | 481 | { |
824 | int cpu; | ||
825 | |||
826 | nmi_enter(); | 482 | nmi_enter(); |
827 | 483 | ||
828 | cpu = smp_processor_id(); | 484 | #ifdef CONFIG_X86_32 |
829 | 485 | { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } | |
830 | ++nmi_count(cpu); | 486 | #else |
487 | add_pda(__nmi_count, 1); | ||
488 | #endif | ||
831 | 489 | ||
832 | if (!ignore_nmis) | 490 | if (!ignore_nmis) |
833 | default_do_nmi(regs); | 491 | default_do_nmi(regs); |
@@ -847,21 +505,44 @@ void restart_nmi(void) | |||
847 | acpi_nmi_enable(); | 505 | acpi_nmi_enable(); |
848 | } | 506 | } |
849 | 507 | ||
850 | #ifdef CONFIG_KPROBES | 508 | /* May run on IST stack. */ |
851 | void __kprobes do_int3(struct pt_regs *regs, long error_code) | 509 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) |
852 | { | 510 | { |
853 | trace_hardirqs_fixup(); | 511 | #ifdef CONFIG_KPROBES |
854 | |||
855 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) | 512 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) |
856 | == NOTIFY_STOP) | 513 | == NOTIFY_STOP) |
857 | return; | 514 | return; |
858 | /* | 515 | #else |
859 | * This is an interrupt gate, because kprobes wants interrupts | 516 | if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP) |
860 | * disabled. Normal trap handlers don't. | 517 | == NOTIFY_STOP) |
861 | */ | 518 | return; |
862 | restore_interrupts(regs); | 519 | #endif |
520 | |||
521 | preempt_conditional_sti(regs); | ||
522 | do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); | ||
523 | preempt_conditional_cli(regs); | ||
524 | } | ||
863 | 525 | ||
864 | do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); | 526 | #ifdef CONFIG_X86_64 |
527 | /* Help handler running on IST stack to switch back to user stack | ||
528 | for scheduling or signal handling. The actual stack switch is done in | ||
529 | entry.S */ | ||
530 | asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | ||
531 | { | ||
532 | struct pt_regs *regs = eregs; | ||
533 | /* Did already sync */ | ||
534 | if (eregs == (struct pt_regs *)eregs->sp) | ||
535 | ; | ||
536 | /* Exception from user space */ | ||
537 | else if (user_mode(eregs)) | ||
538 | regs = task_pt_regs(current); | ||
539 | /* Exception from kernel and interrupts are enabled. Move to | ||
540 | kernel process stack. */ | ||
541 | else if (eregs->flags & X86_EFLAGS_IF) | ||
542 | regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); | ||
543 | if (eregs != regs) | ||
544 | *regs = *eregs; | ||
545 | return regs; | ||
865 | } | 546 | } |
866 | #endif | 547 | #endif |
867 | 548 | ||
@@ -886,15 +567,15 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code) | |||
886 | * about restoring all the debug state, and ptrace doesn't have to | 567 | * about restoring all the debug state, and ptrace doesn't have to |
887 | * find every occurrence of the TF bit that could be saved away even | 568 | * find every occurrence of the TF bit that could be saved away even |
888 | * by user code) | 569 | * by user code) |
570 | * | ||
571 | * May run on IST stack. | ||
889 | */ | 572 | */ |
890 | void __kprobes do_debug(struct pt_regs *regs, long error_code) | 573 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) |
891 | { | 574 | { |
892 | struct task_struct *tsk = current; | 575 | struct task_struct *tsk = current; |
893 | unsigned int condition; | 576 | unsigned long condition; |
894 | int si_code; | 577 | int si_code; |
895 | 578 | ||
896 | trace_hardirqs_fixup(); | ||
897 | |||
898 | get_debugreg(condition, 6); | 579 | get_debugreg(condition, 6); |
899 | 580 | ||
900 | /* | 581 | /* |
@@ -906,9 +587,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
906 | if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, | 587 | if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, |
907 | SIGTRAP) == NOTIFY_STOP) | 588 | SIGTRAP) == NOTIFY_STOP) |
908 | return; | 589 | return; |
590 | |||
909 | /* It's safe to allow irq's after DR6 has been saved */ | 591 | /* It's safe to allow irq's after DR6 has been saved */ |
910 | if (regs->flags & X86_EFLAGS_IF) | 592 | preempt_conditional_sti(regs); |
911 | local_irq_enable(); | ||
912 | 593 | ||
913 | /* Mask out spurious debug traps due to lazy DR7 setting */ | 594 | /* Mask out spurious debug traps due to lazy DR7 setting */ |
914 | if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { | 595 | if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { |
@@ -916,8 +597,10 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
916 | goto clear_dr7; | 597 | goto clear_dr7; |
917 | } | 598 | } |
918 | 599 | ||
600 | #ifdef CONFIG_X86_32 | ||
919 | if (regs->flags & X86_VM_MASK) | 601 | if (regs->flags & X86_VM_MASK) |
920 | goto debug_vm86; | 602 | goto debug_vm86; |
603 | #endif | ||
921 | 604 | ||
922 | /* Save debug status register where ptrace can see it */ | 605 | /* Save debug status register where ptrace can see it */ |
923 | tsk->thread.debugreg6 = condition; | 606 | tsk->thread.debugreg6 = condition; |
@@ -927,16 +610,11 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
927 | * kernel space (but re-enable TF when returning to user mode). | 610 | * kernel space (but re-enable TF when returning to user mode). |
928 | */ | 611 | */ |
929 | if (condition & DR_STEP) { | 612 | if (condition & DR_STEP) { |
930 | /* | ||
931 | * We already checked v86 mode above, so we can | ||
932 | * check for kernel mode by just checking the CPL | ||
933 | * of CS. | ||
934 | */ | ||
935 | if (!user_mode(regs)) | 613 | if (!user_mode(regs)) |
936 | goto clear_TF_reenable; | 614 | goto clear_TF_reenable; |
937 | } | 615 | } |
938 | 616 | ||
939 | si_code = get_si_code((unsigned long)condition); | 617 | si_code = get_si_code(condition); |
940 | /* Ok, finally something we can handle */ | 618 | /* Ok, finally something we can handle */ |
941 | send_sigtrap(tsk, regs, error_code, si_code); | 619 | send_sigtrap(tsk, regs, error_code, si_code); |
942 | 620 | ||
@@ -946,18 +624,37 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
946 | */ | 624 | */ |
947 | clear_dr7: | 625 | clear_dr7: |
948 | set_debugreg(0, 7); | 626 | set_debugreg(0, 7); |
627 | preempt_conditional_cli(regs); | ||
949 | return; | 628 | return; |
950 | 629 | ||
630 | #ifdef CONFIG_X86_32 | ||
951 | debug_vm86: | 631 | debug_vm86: |
952 | handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); | 632 | handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); |
633 | preempt_conditional_cli(regs); | ||
953 | return; | 634 | return; |
635 | #endif | ||
954 | 636 | ||
955 | clear_TF_reenable: | 637 | clear_TF_reenable: |
956 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); | 638 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); |
957 | regs->flags &= ~X86_EFLAGS_TF; | 639 | regs->flags &= ~X86_EFLAGS_TF; |
640 | preempt_conditional_cli(regs); | ||
958 | return; | 641 | return; |
959 | } | 642 | } |
960 | 643 | ||
644 | #ifdef CONFIG_X86_64 | ||
645 | static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) | ||
646 | { | ||
647 | if (fixup_exception(regs)) | ||
648 | return 1; | ||
649 | |||
650 | notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE); | ||
651 | /* Illegal floating point operation in the kernel */ | ||
652 | current->thread.trap_no = trapnr; | ||
653 | die(str, regs, 0); | ||
654 | return 0; | ||
655 | } | ||
656 | #endif | ||
657 | |||
961 | /* | 658 | /* |
962 | * Note that we play around with the 'TS' bit in an attempt to get | 659 | * Note that we play around with the 'TS' bit in an attempt to get |
963 | * the correct behaviour even in the presence of the asynchronous | 660 | * the correct behaviour even in the presence of the asynchronous |
@@ -994,7 +691,9 @@ void math_error(void __user *ip) | |||
994 | swd = get_fpu_swd(task); | 691 | swd = get_fpu_swd(task); |
995 | switch (swd & ~cwd & 0x3f) { | 692 | switch (swd & ~cwd & 0x3f) { |
996 | case 0x000: /* No unmasked exception */ | 693 | case 0x000: /* No unmasked exception */ |
694 | #ifdef CONFIG_X86_32 | ||
997 | return; | 695 | return; |
696 | #endif | ||
998 | default: /* Multiple exceptions */ | 697 | default: /* Multiple exceptions */ |
999 | break; | 698 | break; |
1000 | case 0x001: /* Invalid Op */ | 699 | case 0x001: /* Invalid Op */ |
@@ -1022,9 +721,18 @@ void math_error(void __user *ip) | |||
1022 | force_sig_info(SIGFPE, &info, task); | 721 | force_sig_info(SIGFPE, &info, task); |
1023 | } | 722 | } |
1024 | 723 | ||
1025 | void do_coprocessor_error(struct pt_regs *regs, long error_code) | 724 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) |
1026 | { | 725 | { |
726 | conditional_sti(regs); | ||
727 | |||
728 | #ifdef CONFIG_X86_32 | ||
1027 | ignore_fpu_irq = 1; | 729 | ignore_fpu_irq = 1; |
730 | #else | ||
731 | if (!user_mode(regs) && | ||
732 | kernel_math_error(regs, "kernel x87 math error", 16)) | ||
733 | return; | ||
734 | #endif | ||
735 | |||
1028 | math_error((void __user *)regs->ip); | 736 | math_error((void __user *)regs->ip); |
1029 | } | 737 | } |
1030 | 738 | ||
@@ -1076,8 +784,12 @@ static void simd_math_error(void __user *ip) | |||
1076 | force_sig_info(SIGFPE, &info, task); | 784 | force_sig_info(SIGFPE, &info, task); |
1077 | } | 785 | } |
1078 | 786 | ||
1079 | void do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | 787 | dotraplinkage void |
788 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | ||
1080 | { | 789 | { |
790 | conditional_sti(regs); | ||
791 | |||
792 | #ifdef CONFIG_X86_32 | ||
1081 | if (cpu_has_xmm) { | 793 | if (cpu_has_xmm) { |
1082 | /* Handle SIMD FPU exceptions on PIII+ processors. */ | 794 | /* Handle SIMD FPU exceptions on PIII+ processors. */ |
1083 | ignore_fpu_irq = 1; | 795 | ignore_fpu_irq = 1; |
@@ -1096,16 +808,25 @@ void do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | |||
1096 | current->thread.error_code = error_code; | 808 | current->thread.error_code = error_code; |
1097 | die_if_kernel("cache flush denied", regs, error_code); | 809 | die_if_kernel("cache flush denied", regs, error_code); |
1098 | force_sig(SIGSEGV, current); | 810 | force_sig(SIGSEGV, current); |
811 | #else | ||
812 | if (!user_mode(regs) && | ||
813 | kernel_math_error(regs, "kernel simd math error", 19)) | ||
814 | return; | ||
815 | simd_math_error((void __user *)regs->ip); | ||
816 | #endif | ||
1099 | } | 817 | } |
1100 | 818 | ||
1101 | void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) | 819 | dotraplinkage void |
820 | do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) | ||
1102 | { | 821 | { |
822 | conditional_sti(regs); | ||
1103 | #if 0 | 823 | #if 0 |
1104 | /* No need to warn about this any longer. */ | 824 | /* No need to warn about this any longer. */ |
1105 | printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); | 825 | printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); |
1106 | #endif | 826 | #endif |
1107 | } | 827 | } |
1108 | 828 | ||
829 | #ifdef CONFIG_X86_32 | ||
1109 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) | 830 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) |
1110 | { | 831 | { |
1111 | struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); | 832 | struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); |
@@ -1124,6 +845,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) | |||
1124 | 845 | ||
1125 | return new_kesp; | 846 | return new_kesp; |
1126 | } | 847 | } |
848 | #else | ||
849 | asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) | ||
850 | { | ||
851 | } | ||
852 | |||
853 | asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) | ||
854 | { | ||
855 | } | ||
856 | #endif | ||
1127 | 857 | ||
1128 | /* | 858 | /* |
1129 | * 'math_state_restore()' saves the current math information in the | 859 | * 'math_state_restore()' saves the current math information in the |
@@ -1156,14 +886,24 @@ asmlinkage void math_state_restore(void) | |||
1156 | } | 886 | } |
1157 | 887 | ||
1158 | clts(); /* Allow maths ops (or we recurse) */ | 888 | clts(); /* Allow maths ops (or we recurse) */ |
889 | #ifdef CONFIG_X86_32 | ||
1159 | restore_fpu(tsk); | 890 | restore_fpu(tsk); |
891 | #else | ||
892 | /* | ||
893 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
894 | */ | ||
895 | if (unlikely(restore_fpu_checking(tsk))) { | ||
896 | stts(); | ||
897 | force_sig(SIGSEGV, tsk); | ||
898 | return; | ||
899 | } | ||
900 | #endif | ||
1160 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ | 901 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ |
1161 | tsk->fpu_counter++; | 902 | tsk->fpu_counter++; |
1162 | } | 903 | } |
1163 | EXPORT_SYMBOL_GPL(math_state_restore); | 904 | EXPORT_SYMBOL_GPL(math_state_restore); |
1164 | 905 | ||
1165 | #ifndef CONFIG_MATH_EMULATION | 906 | #ifndef CONFIG_MATH_EMULATION |
1166 | |||
1167 | asmlinkage void math_emulate(long arg) | 907 | asmlinkage void math_emulate(long arg) |
1168 | { | 908 | { |
1169 | printk(KERN_EMERG | 909 | printk(KERN_EMERG |
@@ -1172,12 +912,54 @@ asmlinkage void math_emulate(long arg) | |||
1172 | force_sig(SIGFPE, current); | 912 | force_sig(SIGFPE, current); |
1173 | schedule(); | 913 | schedule(); |
1174 | } | 914 | } |
1175 | |||
1176 | #endif /* CONFIG_MATH_EMULATION */ | 915 | #endif /* CONFIG_MATH_EMULATION */ |
1177 | 916 | ||
917 | dotraplinkage void __kprobes | ||
918 | do_device_not_available(struct pt_regs *regs, long error) | ||
919 | { | ||
920 | #ifdef CONFIG_X86_32 | ||
921 | if (read_cr0() & X86_CR0_EM) { | ||
922 | conditional_sti(regs); | ||
923 | math_emulate(0); | ||
924 | } else { | ||
925 | math_state_restore(); /* interrupts still off */ | ||
926 | conditional_sti(regs); | ||
927 | } | ||
928 | #else | ||
929 | math_state_restore(); | ||
930 | #endif | ||
931 | } | ||
932 | |||
933 | #ifdef CONFIG_X86_32 | ||
934 | #ifdef CONFIG_X86_MCE | ||
935 | dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error) | ||
936 | { | ||
937 | conditional_sti(regs); | ||
938 | machine_check_vector(regs, error); | ||
939 | } | ||
940 | #endif | ||
941 | |||
942 | dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | ||
943 | { | ||
944 | siginfo_t info; | ||
945 | local_irq_enable(); | ||
946 | |||
947 | info.si_signo = SIGILL; | ||
948 | info.si_errno = 0; | ||
949 | info.si_code = ILL_BADSTK; | ||
950 | info.si_addr = 0; | ||
951 | if (notify_die(DIE_TRAP, "iret exception", | ||
952 | regs, error_code, 32, SIGILL) == NOTIFY_STOP) | ||
953 | return; | ||
954 | do_trap(32, SIGILL, "iret exception", regs, error_code, &info); | ||
955 | } | ||
956 | #endif | ||
957 | |||
1178 | void __init trap_init(void) | 958 | void __init trap_init(void) |
1179 | { | 959 | { |
960 | #ifdef CONFIG_X86_32 | ||
1180 | int i; | 961 | int i; |
962 | #endif | ||
1181 | 963 | ||
1182 | #ifdef CONFIG_EISA | 964 | #ifdef CONFIG_EISA |
1183 | void __iomem *p = early_ioremap(0x0FFFD9, 4); | 965 | void __iomem *p = early_ioremap(0x0FFFD9, 4); |
@@ -1187,29 +969,40 @@ void __init trap_init(void) | |||
1187 | early_iounmap(p, 4); | 969 | early_iounmap(p, 4); |
1188 | #endif | 970 | #endif |
1189 | 971 | ||
1190 | set_trap_gate(0, ÷_error); | 972 | set_intr_gate(0, ÷_error); |
1191 | set_intr_gate(1, &debug); | 973 | set_intr_gate_ist(1, &debug, DEBUG_STACK); |
1192 | set_intr_gate(2, &nmi); | 974 | set_intr_gate_ist(2, &nmi, NMI_STACK); |
1193 | set_system_intr_gate(3, &int3); /* int3 can be called from all */ | 975 | /* int3 can be called from all */ |
1194 | set_system_gate(4, &overflow); /* int4 can be called from all */ | 976 | set_system_intr_gate_ist(3, &int3, DEBUG_STACK); |
1195 | set_trap_gate(5, &bounds); | 977 | /* int4 can be called from all */ |
1196 | set_trap_gate(6, &invalid_op); | 978 | set_system_intr_gate(4, &overflow); |
1197 | set_trap_gate(7, &device_not_available); | 979 | set_intr_gate(5, &bounds); |
980 | set_intr_gate(6, &invalid_op); | ||
981 | set_intr_gate(7, &device_not_available); | ||
982 | #ifdef CONFIG_X86_32 | ||
1198 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); | 983 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); |
1199 | set_trap_gate(9, &coprocessor_segment_overrun); | 984 | #else |
1200 | set_trap_gate(10, &invalid_TSS); | 985 | set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK); |
1201 | set_trap_gate(11, &segment_not_present); | 986 | #endif |
1202 | set_trap_gate(12, &stack_segment); | 987 | set_intr_gate(9, &coprocessor_segment_overrun); |
1203 | set_trap_gate(13, &general_protection); | 988 | set_intr_gate(10, &invalid_TSS); |
989 | set_intr_gate(11, &segment_not_present); | ||
990 | set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK); | ||
991 | set_intr_gate(13, &general_protection); | ||
1204 | set_intr_gate(14, &page_fault); | 992 | set_intr_gate(14, &page_fault); |
1205 | set_trap_gate(15, &spurious_interrupt_bug); | 993 | set_intr_gate(15, &spurious_interrupt_bug); |
1206 | set_trap_gate(16, &coprocessor_error); | 994 | set_intr_gate(16, &coprocessor_error); |
1207 | set_trap_gate(17, &alignment_check); | 995 | set_intr_gate(17, &alignment_check); |
1208 | #ifdef CONFIG_X86_MCE | 996 | #ifdef CONFIG_X86_MCE |
1209 | set_trap_gate(18, &machine_check); | 997 | set_intr_gate_ist(18, &machine_check, MCE_STACK); |
1210 | #endif | 998 | #endif |
1211 | set_trap_gate(19, &simd_coprocessor_error); | 999 | set_intr_gate(19, &simd_coprocessor_error); |
1212 | 1000 | ||
1001 | #ifdef CONFIG_IA32_EMULATION | ||
1002 | set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); | ||
1003 | #endif | ||
1004 | |||
1005 | #ifdef CONFIG_X86_32 | ||
1213 | if (cpu_has_fxsr) { | 1006 | if (cpu_has_fxsr) { |
1214 | printk(KERN_INFO "Enabling fast FPU save and restore... "); | 1007 | printk(KERN_INFO "Enabling fast FPU save and restore... "); |
1215 | set_in_cr4(X86_CR4_OSFXSR); | 1008 | set_in_cr4(X86_CR4_OSFXSR); |
@@ -1222,36 +1015,20 @@ void __init trap_init(void) | |||
1222 | printk("done.\n"); | 1015 | printk("done.\n"); |
1223 | } | 1016 | } |
1224 | 1017 | ||
1225 | set_system_gate(SYSCALL_VECTOR, &system_call); | 1018 | set_system_trap_gate(SYSCALL_VECTOR, &system_call); |
1226 | 1019 | ||
1227 | /* Reserve all the builtin and the syscall vector: */ | 1020 | /* Reserve all the builtin and the syscall vector: */ |
1228 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) | 1021 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) |
1229 | set_bit(i, used_vectors); | 1022 | set_bit(i, used_vectors); |
1230 | 1023 | ||
1231 | set_bit(SYSCALL_VECTOR, used_vectors); | 1024 | set_bit(SYSCALL_VECTOR, used_vectors); |
1232 | 1025 | #endif | |
1233 | /* | 1026 | /* |
1234 | * Should be a barrier for any external CPU state: | 1027 | * Should be a barrier for any external CPU state: |
1235 | */ | 1028 | */ |
1236 | cpu_init(); | 1029 | cpu_init(); |
1237 | 1030 | ||
1031 | #ifdef CONFIG_X86_32 | ||
1238 | trap_init_hook(); | 1032 | trap_init_hook(); |
1033 | #endif | ||
1239 | } | 1034 | } |
1240 | |||
1241 | static int __init kstack_setup(char *s) | ||
1242 | { | ||
1243 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
1244 | |||
1245 | return 1; | ||
1246 | } | ||
1247 | __setup("kstack=", kstack_setup); | ||
1248 | |||
1249 | static int __init code_bytes_setup(char *s) | ||
1250 | { | ||
1251 | code_bytes = simple_strtoul(s, NULL, 0); | ||
1252 | if (code_bytes > 8192) | ||
1253 | code_bytes = 8192; | ||
1254 | |||
1255 | return 1; | ||
1256 | } | ||
1257 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c deleted file mode 100644 index 9c0ac0cab013..000000000000 --- a/arch/x86/kernel/traps_64.c +++ /dev/null | |||
@@ -1,1214 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
4 | * | ||
5 | * Pentium III FXSR, SSE support | ||
6 | * Gareth Hughes <gareth@valinux.com>, May 2000 | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * 'Traps.c' handles hardware traps and faults after we have saved some | ||
11 | * state in 'entry.S'. | ||
12 | */ | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/kallsyms.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/kprobes.h> | ||
18 | #include <linux/uaccess.h> | ||
19 | #include <linux/utsname.h> | ||
20 | #include <linux/kdebug.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/ptrace.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/unwind.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/kexec.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/timer.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/bug.h> | ||
33 | #include <linux/nmi.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/smp.h> | ||
36 | #include <linux/io.h> | ||
37 | |||
38 | #if defined(CONFIG_EDAC) | ||
39 | #include <linux/edac.h> | ||
40 | #endif | ||
41 | |||
42 | #include <asm/stacktrace.h> | ||
43 | #include <asm/processor.h> | ||
44 | #include <asm/debugreg.h> | ||
45 | #include <asm/atomic.h> | ||
46 | #include <asm/system.h> | ||
47 | #include <asm/unwind.h> | ||
48 | #include <asm/desc.h> | ||
49 | #include <asm/i387.h> | ||
50 | #include <asm/pgalloc.h> | ||
51 | #include <asm/proto.h> | ||
52 | #include <asm/pda.h> | ||
53 | #include <asm/traps.h> | ||
54 | |||
55 | #include <mach_traps.h> | ||
56 | |||
57 | int panic_on_unrecovered_nmi; | ||
58 | int kstack_depth_to_print = 12; | ||
59 | static unsigned int code_bytes = 64; | ||
60 | static int ignore_nmis; | ||
61 | static int die_counter; | ||
62 | |||
63 | static inline void conditional_sti(struct pt_regs *regs) | ||
64 | { | ||
65 | if (regs->flags & X86_EFLAGS_IF) | ||
66 | local_irq_enable(); | ||
67 | } | ||
68 | |||
69 | static inline void preempt_conditional_sti(struct pt_regs *regs) | ||
70 | { | ||
71 | inc_preempt_count(); | ||
72 | if (regs->flags & X86_EFLAGS_IF) | ||
73 | local_irq_enable(); | ||
74 | } | ||
75 | |||
76 | static inline void preempt_conditional_cli(struct pt_regs *regs) | ||
77 | { | ||
78 | if (regs->flags & X86_EFLAGS_IF) | ||
79 | local_irq_disable(); | ||
80 | /* Make sure to not schedule here because we could be running | ||
81 | on an exception stack. */ | ||
82 | dec_preempt_count(); | ||
83 | } | ||
84 | |||
85 | void printk_address(unsigned long address, int reliable) | ||
86 | { | ||
87 | printk(" [<%016lx>] %s%pS\n", | ||
88 | address, reliable ? "" : "? ", (void *) address); | ||
89 | } | ||
90 | |||
91 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | ||
92 | unsigned *usedp, char **idp) | ||
93 | { | ||
94 | static char ids[][8] = { | ||
95 | [DEBUG_STACK - 1] = "#DB", | ||
96 | [NMI_STACK - 1] = "NMI", | ||
97 | [DOUBLEFAULT_STACK - 1] = "#DF", | ||
98 | [STACKFAULT_STACK - 1] = "#SS", | ||
99 | [MCE_STACK - 1] = "#MC", | ||
100 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
101 | [N_EXCEPTION_STACKS ... | ||
102 | N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" | ||
103 | #endif | ||
104 | }; | ||
105 | unsigned k; | ||
106 | |||
107 | /* | ||
108 | * Iterate over all exception stacks, and figure out whether | ||
109 | * 'stack' is in one of them: | ||
110 | */ | ||
111 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { | ||
112 | unsigned long end = per_cpu(orig_ist, cpu).ist[k]; | ||
113 | /* | ||
114 | * Is 'stack' above this exception frame's end? | ||
115 | * If yes then skip to the next frame. | ||
116 | */ | ||
117 | if (stack >= end) | ||
118 | continue; | ||
119 | /* | ||
120 | * Is 'stack' above this exception frame's start address? | ||
121 | * If yes then we found the right frame. | ||
122 | */ | ||
123 | if (stack >= end - EXCEPTION_STKSZ) { | ||
124 | /* | ||
125 | * Make sure we only iterate through an exception | ||
126 | * stack once. If it comes up for the second time | ||
127 | * then there's something wrong going on - just | ||
128 | * break out and return NULL: | ||
129 | */ | ||
130 | if (*usedp & (1U << k)) | ||
131 | break; | ||
132 | *usedp |= 1U << k; | ||
133 | *idp = ids[k]; | ||
134 | return (unsigned long *)end; | ||
135 | } | ||
136 | /* | ||
137 | * If this is a debug stack, and if it has a larger size than | ||
138 | * the usual exception stacks, then 'stack' might still | ||
139 | * be within the lower portion of the debug stack: | ||
140 | */ | ||
141 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
142 | if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { | ||
143 | unsigned j = N_EXCEPTION_STACKS - 1; | ||
144 | |||
145 | /* | ||
146 | * Black magic. A large debug stack is composed of | ||
147 | * multiple exception stack entries, which we | ||
148 | * iterate through now. Dont look: | ||
149 | */ | ||
150 | do { | ||
151 | ++j; | ||
152 | end -= EXCEPTION_STKSZ; | ||
153 | ids[j][4] = '1' + (j - N_EXCEPTION_STACKS); | ||
154 | } while (stack < end - EXCEPTION_STKSZ); | ||
155 | if (*usedp & (1U << j)) | ||
156 | break; | ||
157 | *usedp |= 1U << j; | ||
158 | *idp = ids[j]; | ||
159 | return (unsigned long *)end; | ||
160 | } | ||
161 | #endif | ||
162 | } | ||
163 | return NULL; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * x86-64 can have up to three kernel stacks: | ||
168 | * process stack | ||
169 | * interrupt stack | ||
170 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | ||
171 | */ | ||
172 | |||
173 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
174 | void *p, unsigned int size, void *end) | ||
175 | { | ||
176 | void *t = tinfo; | ||
177 | if (end) { | ||
178 | if (p < end && p >= (end-THREAD_SIZE)) | ||
179 | return 1; | ||
180 | else | ||
181 | return 0; | ||
182 | } | ||
183 | return p > t && p < t + THREAD_SIZE - size; | ||
184 | } | ||
185 | |||
186 | /* The form of the top of the frame on the stack */ | ||
187 | struct stack_frame { | ||
188 | struct stack_frame *next_frame; | ||
189 | unsigned long return_address; | ||
190 | }; | ||
191 | |||
192 | static inline unsigned long | ||
193 | print_context_stack(struct thread_info *tinfo, | ||
194 | unsigned long *stack, unsigned long bp, | ||
195 | const struct stacktrace_ops *ops, void *data, | ||
196 | unsigned long *end) | ||
197 | { | ||
198 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
199 | |||
200 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { | ||
201 | unsigned long addr; | ||
202 | |||
203 | addr = *stack; | ||
204 | if (__kernel_text_address(addr)) { | ||
205 | if ((unsigned long) stack == bp + 8) { | ||
206 | ops->address(data, addr, 1); | ||
207 | frame = frame->next_frame; | ||
208 | bp = (unsigned long) frame; | ||
209 | } else { | ||
210 | ops->address(data, addr, bp == 0); | ||
211 | } | ||
212 | } | ||
213 | stack++; | ||
214 | } | ||
215 | return bp; | ||
216 | } | ||
217 | |||
218 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
219 | unsigned long *stack, unsigned long bp, | ||
220 | const struct stacktrace_ops *ops, void *data) | ||
221 | { | ||
222 | const unsigned cpu = get_cpu(); | ||
223 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | ||
224 | unsigned used = 0; | ||
225 | struct thread_info *tinfo; | ||
226 | |||
227 | if (!task) | ||
228 | task = current; | ||
229 | |||
230 | if (!stack) { | ||
231 | unsigned long dummy; | ||
232 | stack = &dummy; | ||
233 | if (task && task != current) | ||
234 | stack = (unsigned long *)task->thread.sp; | ||
235 | } | ||
236 | |||
237 | #ifdef CONFIG_FRAME_POINTER | ||
238 | if (!bp) { | ||
239 | if (task == current) { | ||
240 | /* Grab bp right from our regs */ | ||
241 | asm("movq %%rbp, %0" : "=r" (bp) : ); | ||
242 | } else { | ||
243 | /* bp is the last reg pushed by switch_to */ | ||
244 | bp = *(unsigned long *) task->thread.sp; | ||
245 | } | ||
246 | } | ||
247 | #endif | ||
248 | |||
249 | /* | ||
250 | * Print function call entries in all stacks, starting at the | ||
251 | * current stack address. If the stacks consist of nested | ||
252 | * exceptions | ||
253 | */ | ||
254 | tinfo = task_thread_info(task); | ||
255 | for (;;) { | ||
256 | char *id; | ||
257 | unsigned long *estack_end; | ||
258 | estack_end = in_exception_stack(cpu, (unsigned long)stack, | ||
259 | &used, &id); | ||
260 | |||
261 | if (estack_end) { | ||
262 | if (ops->stack(data, id) < 0) | ||
263 | break; | ||
264 | |||
265 | bp = print_context_stack(tinfo, stack, bp, ops, | ||
266 | data, estack_end); | ||
267 | ops->stack(data, "<EOE>"); | ||
268 | /* | ||
269 | * We link to the next stack via the | ||
270 | * second-to-last pointer (index -2 to end) in the | ||
271 | * exception stack: | ||
272 | */ | ||
273 | stack = (unsigned long *) estack_end[-2]; | ||
274 | continue; | ||
275 | } | ||
276 | if (irqstack_end) { | ||
277 | unsigned long *irqstack; | ||
278 | irqstack = irqstack_end - | ||
279 | (IRQSTACKSIZE - 64) / sizeof(*irqstack); | ||
280 | |||
281 | if (stack >= irqstack && stack < irqstack_end) { | ||
282 | if (ops->stack(data, "IRQ") < 0) | ||
283 | break; | ||
284 | bp = print_context_stack(tinfo, stack, bp, | ||
285 | ops, data, irqstack_end); | ||
286 | /* | ||
287 | * We link to the next stack (which would be | ||
288 | * the process stack normally) the last | ||
289 | * pointer (index -1 to end) in the IRQ stack: | ||
290 | */ | ||
291 | stack = (unsigned long *) (irqstack_end[-1]); | ||
292 | irqstack_end = NULL; | ||
293 | ops->stack(data, "EOI"); | ||
294 | continue; | ||
295 | } | ||
296 | } | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * This handles the process stack: | ||
302 | */ | ||
303 | bp = print_context_stack(tinfo, stack, bp, ops, data, NULL); | ||
304 | put_cpu(); | ||
305 | } | ||
306 | EXPORT_SYMBOL(dump_trace); | ||
307 | |||
308 | static void | ||
309 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
310 | { | ||
311 | print_symbol(msg, symbol); | ||
312 | printk("\n"); | ||
313 | } | ||
314 | |||
315 | static void print_trace_warning(void *data, char *msg) | ||
316 | { | ||
317 | printk("%s\n", msg); | ||
318 | } | ||
319 | |||
320 | static int print_trace_stack(void *data, char *name) | ||
321 | { | ||
322 | printk(" <%s> ", name); | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
327 | { | ||
328 | touch_nmi_watchdog(); | ||
329 | printk_address(addr, reliable); | ||
330 | } | ||
331 | |||
332 | static const struct stacktrace_ops print_trace_ops = { | ||
333 | .warning = print_trace_warning, | ||
334 | .warning_symbol = print_trace_warning_symbol, | ||
335 | .stack = print_trace_stack, | ||
336 | .address = print_trace_address, | ||
337 | }; | ||
338 | |||
339 | static void | ||
340 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
341 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
342 | { | ||
343 | printk("Call Trace:\n"); | ||
344 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | ||
345 | } | ||
346 | |||
347 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
348 | unsigned long *stack, unsigned long bp) | ||
349 | { | ||
350 | show_trace_log_lvl(task, regs, stack, bp, ""); | ||
351 | } | ||
352 | |||
353 | static void | ||
354 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
355 | unsigned long *sp, unsigned long bp, char *log_lvl) | ||
356 | { | ||
357 | unsigned long *stack; | ||
358 | int i; | ||
359 | const int cpu = smp_processor_id(); | ||
360 | unsigned long *irqstack_end = | ||
361 | (unsigned long *) (cpu_pda(cpu)->irqstackptr); | ||
362 | unsigned long *irqstack = | ||
363 | (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); | ||
364 | |||
365 | /* | ||
366 | * debugging aid: "show_stack(NULL, NULL);" prints the | ||
367 | * back trace for this cpu. | ||
368 | */ | ||
369 | |||
370 | if (sp == NULL) { | ||
371 | if (task) | ||
372 | sp = (unsigned long *)task->thread.sp; | ||
373 | else | ||
374 | sp = (unsigned long *)&sp; | ||
375 | } | ||
376 | |||
377 | stack = sp; | ||
378 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
379 | if (stack >= irqstack && stack <= irqstack_end) { | ||
380 | if (stack == irqstack_end) { | ||
381 | stack = (unsigned long *) (irqstack_end[-1]); | ||
382 | printk(" <EOI> "); | ||
383 | } | ||
384 | } else { | ||
385 | if (((long) stack & (THREAD_SIZE-1)) == 0) | ||
386 | break; | ||
387 | } | ||
388 | if (i && ((i % 4) == 0)) | ||
389 | printk("\n"); | ||
390 | printk(" %016lx", *stack++); | ||
391 | touch_nmi_watchdog(); | ||
392 | } | ||
393 | printk("\n"); | ||
394 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | ||
395 | } | ||
396 | |||
397 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
398 | { | ||
399 | show_stack_log_lvl(task, NULL, sp, 0, ""); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * The architecture-independent dump_stack generator | ||
404 | */ | ||
405 | void dump_stack(void) | ||
406 | { | ||
407 | unsigned long bp = 0; | ||
408 | unsigned long stack; | ||
409 | |||
410 | #ifdef CONFIG_FRAME_POINTER | ||
411 | if (!bp) | ||
412 | asm("movq %%rbp, %0" : "=r" (bp) : ); | ||
413 | #endif | ||
414 | |||
415 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
416 | current->pid, current->comm, print_tainted(), | ||
417 | init_utsname()->release, | ||
418 | (int)strcspn(init_utsname()->version, " "), | ||
419 | init_utsname()->version); | ||
420 | show_trace(NULL, NULL, &stack, bp); | ||
421 | } | ||
422 | EXPORT_SYMBOL(dump_stack); | ||
423 | |||
424 | void show_registers(struct pt_regs *regs) | ||
425 | { | ||
426 | int i; | ||
427 | unsigned long sp; | ||
428 | const int cpu = smp_processor_id(); | ||
429 | struct task_struct *cur = cpu_pda(cpu)->pcurrent; | ||
430 | |||
431 | sp = regs->sp; | ||
432 | printk("CPU %d ", cpu); | ||
433 | __show_regs(regs); | ||
434 | printk("Process %s (pid: %d, threadinfo %p, task %p)\n", | ||
435 | cur->comm, cur->pid, task_thread_info(cur), cur); | ||
436 | |||
437 | /* | ||
438 | * When in-kernel, we also print out the stack and code at the | ||
439 | * time of the fault.. | ||
440 | */ | ||
441 | if (!user_mode(regs)) { | ||
442 | unsigned int code_prologue = code_bytes * 43 / 64; | ||
443 | unsigned int code_len = code_bytes; | ||
444 | unsigned char c; | ||
445 | u8 *ip; | ||
446 | |||
447 | printk("Stack: "); | ||
448 | show_stack_log_lvl(NULL, regs, (unsigned long *)sp, | ||
449 | regs->bp, ""); | ||
450 | |||
451 | printk(KERN_EMERG "Code: "); | ||
452 | |||
453 | ip = (u8 *)regs->ip - code_prologue; | ||
454 | if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { | ||
455 | /* try starting at RIP */ | ||
456 | ip = (u8 *)regs->ip; | ||
457 | code_len = code_len - code_prologue + 1; | ||
458 | } | ||
459 | for (i = 0; i < code_len; i++, ip++) { | ||
460 | if (ip < (u8 *)PAGE_OFFSET || | ||
461 | probe_kernel_address(ip, c)) { | ||
462 | printk(" Bad RIP value."); | ||
463 | break; | ||
464 | } | ||
465 | if (ip == (u8 *)regs->ip) | ||
466 | printk("<%02x> ", c); | ||
467 | else | ||
468 | printk("%02x ", c); | ||
469 | } | ||
470 | } | ||
471 | printk("\n"); | ||
472 | } | ||
473 | |||
474 | int is_valid_bugaddr(unsigned long ip) | ||
475 | { | ||
476 | unsigned short ud2; | ||
477 | |||
478 | if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2))) | ||
479 | return 0; | ||
480 | |||
481 | return ud2 == 0x0b0f; | ||
482 | } | ||
483 | |||
484 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
485 | static int die_owner = -1; | ||
486 | static unsigned int die_nest_count; | ||
487 | |||
488 | unsigned __kprobes long oops_begin(void) | ||
489 | { | ||
490 | int cpu; | ||
491 | unsigned long flags; | ||
492 | |||
493 | oops_enter(); | ||
494 | |||
495 | /* racy, but better than risking deadlock. */ | ||
496 | raw_local_irq_save(flags); | ||
497 | cpu = smp_processor_id(); | ||
498 | if (!__raw_spin_trylock(&die_lock)) { | ||
499 | if (cpu == die_owner) | ||
500 | /* nested oops. should stop eventually */; | ||
501 | else | ||
502 | __raw_spin_lock(&die_lock); | ||
503 | } | ||
504 | die_nest_count++; | ||
505 | die_owner = cpu; | ||
506 | console_verbose(); | ||
507 | bust_spinlocks(1); | ||
508 | return flags; | ||
509 | } | ||
510 | |||
511 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
512 | { | ||
513 | die_owner = -1; | ||
514 | bust_spinlocks(0); | ||
515 | die_nest_count--; | ||
516 | if (!die_nest_count) | ||
517 | /* Nest count reaches zero, release the lock. */ | ||
518 | __raw_spin_unlock(&die_lock); | ||
519 | raw_local_irq_restore(flags); | ||
520 | if (!regs) { | ||
521 | oops_exit(); | ||
522 | return; | ||
523 | } | ||
524 | if (panic_on_oops) | ||
525 | panic("Fatal exception"); | ||
526 | oops_exit(); | ||
527 | do_exit(signr); | ||
528 | } | ||
529 | |||
530 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
531 | { | ||
532 | printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff, ++die_counter); | ||
533 | #ifdef CONFIG_PREEMPT | ||
534 | printk("PREEMPT "); | ||
535 | #endif | ||
536 | #ifdef CONFIG_SMP | ||
537 | printk("SMP "); | ||
538 | #endif | ||
539 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
540 | printk("DEBUG_PAGEALLOC"); | ||
541 | #endif | ||
542 | printk("\n"); | ||
543 | if (notify_die(DIE_OOPS, str, regs, err, | ||
544 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
545 | return 1; | ||
546 | |||
547 | show_registers(regs); | ||
548 | add_taint(TAINT_DIE); | ||
549 | /* Executive summary in case the oops scrolled away */ | ||
550 | printk(KERN_ALERT "RIP "); | ||
551 | printk_address(regs->ip, 1); | ||
552 | printk(" RSP <%016lx>\n", regs->sp); | ||
553 | if (kexec_should_crash(current)) | ||
554 | crash_kexec(regs); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | void die(const char *str, struct pt_regs *regs, long err) | ||
559 | { | ||
560 | unsigned long flags = oops_begin(); | ||
561 | |||
562 | if (!user_mode(regs)) | ||
563 | report_bug(regs->ip, regs); | ||
564 | |||
565 | if (__die(str, regs, err)) | ||
566 | regs = NULL; | ||
567 | oops_end(flags, regs, SIGSEGV); | ||
568 | } | ||
569 | |||
570 | notrace __kprobes void | ||
571 | die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
572 | { | ||
573 | unsigned long flags; | ||
574 | |||
575 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
576 | return; | ||
577 | |||
578 | flags = oops_begin(); | ||
579 | /* | ||
580 | * We are in trouble anyway, lets at least try | ||
581 | * to get a message out. | ||
582 | */ | ||
583 | printk(KERN_EMERG "%s", str); | ||
584 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
585 | smp_processor_id(), regs->ip); | ||
586 | show_registers(regs); | ||
587 | if (kexec_should_crash(current)) | ||
588 | crash_kexec(regs); | ||
589 | if (do_panic || panic_on_oops) | ||
590 | panic("Non maskable interrupt"); | ||
591 | oops_end(flags, NULL, SIGBUS); | ||
592 | nmi_exit(); | ||
593 | local_irq_enable(); | ||
594 | do_exit(SIGBUS); | ||
595 | } | ||
596 | |||
597 | static void __kprobes | ||
598 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | ||
599 | long error_code, siginfo_t *info) | ||
600 | { | ||
601 | struct task_struct *tsk = current; | ||
602 | |||
603 | if (!user_mode(regs)) | ||
604 | goto kernel_trap; | ||
605 | |||
606 | /* | ||
607 | * We want error_code and trap_no set for userspace faults and | ||
608 | * kernelspace faults which result in die(), but not | ||
609 | * kernelspace faults which are fixed up. die() gives the | ||
610 | * process no chance to handle the signal and notice the | ||
611 | * kernel fault information, so that won't result in polluting | ||
612 | * the information about previously queued, but not yet | ||
613 | * delivered, faults. See also do_general_protection below. | ||
614 | */ | ||
615 | tsk->thread.error_code = error_code; | ||
616 | tsk->thread.trap_no = trapnr; | ||
617 | |||
618 | if (show_unhandled_signals && unhandled_signal(tsk, signr) && | ||
619 | printk_ratelimit()) { | ||
620 | printk(KERN_INFO | ||
621 | "%s[%d] trap %s ip:%lx sp:%lx error:%lx", | ||
622 | tsk->comm, tsk->pid, str, | ||
623 | regs->ip, regs->sp, error_code); | ||
624 | print_vma_addr(" in ", regs->ip); | ||
625 | printk("\n"); | ||
626 | } | ||
627 | |||
628 | if (info) | ||
629 | force_sig_info(signr, info, tsk); | ||
630 | else | ||
631 | force_sig(signr, tsk); | ||
632 | return; | ||
633 | |||
634 | kernel_trap: | ||
635 | if (!fixup_exception(regs)) { | ||
636 | tsk->thread.error_code = error_code; | ||
637 | tsk->thread.trap_no = trapnr; | ||
638 | die(str, regs, error_code); | ||
639 | } | ||
640 | return; | ||
641 | } | ||
642 | |||
643 | #define DO_ERROR(trapnr, signr, str, name) \ | ||
644 | asmlinkage void do_##name(struct pt_regs *regs, long error_code) \ | ||
645 | { \ | ||
646 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
647 | == NOTIFY_STOP) \ | ||
648 | return; \ | ||
649 | conditional_sti(regs); \ | ||
650 | do_trap(trapnr, signr, str, regs, error_code, NULL); \ | ||
651 | } | ||
652 | |||
653 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | ||
654 | asmlinkage void do_##name(struct pt_regs *regs, long error_code) \ | ||
655 | { \ | ||
656 | siginfo_t info; \ | ||
657 | info.si_signo = signr; \ | ||
658 | info.si_errno = 0; \ | ||
659 | info.si_code = sicode; \ | ||
660 | info.si_addr = (void __user *)siaddr; \ | ||
661 | trace_hardirqs_fixup(); \ | ||
662 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
663 | == NOTIFY_STOP) \ | ||
664 | return; \ | ||
665 | conditional_sti(regs); \ | ||
666 | do_trap(trapnr, signr, str, regs, error_code, &info); \ | ||
667 | } | ||
668 | |||
669 | DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) | ||
670 | DO_ERROR(4, SIGSEGV, "overflow", overflow) | ||
671 | DO_ERROR(5, SIGSEGV, "bounds", bounds) | ||
672 | DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip) | ||
673 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | ||
674 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | ||
675 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | ||
676 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) | ||
677 | |||
678 | /* Runs on IST stack */ | ||
679 | asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code) | ||
680 | { | ||
681 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, | ||
682 | 12, SIGBUS) == NOTIFY_STOP) | ||
683 | return; | ||
684 | preempt_conditional_sti(regs); | ||
685 | do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL); | ||
686 | preempt_conditional_cli(regs); | ||
687 | } | ||
688 | |||
689 | asmlinkage void do_double_fault(struct pt_regs *regs, long error_code) | ||
690 | { | ||
691 | static const char str[] = "double fault"; | ||
692 | struct task_struct *tsk = current; | ||
693 | |||
694 | /* Return not checked because double check cannot be ignored */ | ||
695 | notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV); | ||
696 | |||
697 | tsk->thread.error_code = error_code; | ||
698 | tsk->thread.trap_no = 8; | ||
699 | |||
700 | /* This is always a kernel trap and never fixable (and thus must | ||
701 | never return). */ | ||
702 | for (;;) | ||
703 | die(str, regs, error_code); | ||
704 | } | ||
705 | |||
706 | asmlinkage void __kprobes | ||
707 | do_general_protection(struct pt_regs *regs, long error_code) | ||
708 | { | ||
709 | struct task_struct *tsk; | ||
710 | |||
711 | conditional_sti(regs); | ||
712 | |||
713 | tsk = current; | ||
714 | if (!user_mode(regs)) | ||
715 | goto gp_in_kernel; | ||
716 | |||
717 | tsk->thread.error_code = error_code; | ||
718 | tsk->thread.trap_no = 13; | ||
719 | |||
720 | if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && | ||
721 | printk_ratelimit()) { | ||
722 | printk(KERN_INFO | ||
723 | "%s[%d] general protection ip:%lx sp:%lx error:%lx", | ||
724 | tsk->comm, tsk->pid, | ||
725 | regs->ip, regs->sp, error_code); | ||
726 | print_vma_addr(" in ", regs->ip); | ||
727 | printk("\n"); | ||
728 | } | ||
729 | |||
730 | force_sig(SIGSEGV, tsk); | ||
731 | return; | ||
732 | |||
733 | gp_in_kernel: | ||
734 | if (fixup_exception(regs)) | ||
735 | return; | ||
736 | |||
737 | tsk->thread.error_code = error_code; | ||
738 | tsk->thread.trap_no = 13; | ||
739 | if (notify_die(DIE_GPF, "general protection fault", regs, | ||
740 | error_code, 13, SIGSEGV) == NOTIFY_STOP) | ||
741 | return; | ||
742 | die("general protection fault", regs, error_code); | ||
743 | } | ||
744 | |||
745 | static notrace __kprobes void | ||
746 | mem_parity_error(unsigned char reason, struct pt_regs *regs) | ||
747 | { | ||
748 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", | ||
749 | reason); | ||
750 | printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); | ||
751 | |||
752 | #if defined(CONFIG_EDAC) | ||
753 | if (edac_handler_set()) { | ||
754 | edac_atomic_assert_error(); | ||
755 | return; | ||
756 | } | ||
757 | #endif | ||
758 | |||
759 | if (panic_on_unrecovered_nmi) | ||
760 | panic("NMI: Not continuing"); | ||
761 | |||
762 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | ||
763 | |||
764 | /* Clear and disable the memory parity error line. */ | ||
765 | reason = (reason & 0xf) | 4; | ||
766 | outb(reason, 0x61); | ||
767 | } | ||
768 | |||
769 | static notrace __kprobes void | ||
770 | io_check_error(unsigned char reason, struct pt_regs *regs) | ||
771 | { | ||
772 | printk("NMI: IOCK error (debug interrupt?)\n"); | ||
773 | show_registers(regs); | ||
774 | |||
775 | /* Re-enable the IOCK line, wait for a few seconds */ | ||
776 | reason = (reason & 0xf) | 8; | ||
777 | outb(reason, 0x61); | ||
778 | mdelay(2000); | ||
779 | reason &= ~8; | ||
780 | outb(reason, 0x61); | ||
781 | } | ||
782 | |||
783 | static notrace __kprobes void | ||
784 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | ||
785 | { | ||
786 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == | ||
787 | NOTIFY_STOP) | ||
788 | return; | ||
789 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", | ||
790 | reason); | ||
791 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | ||
792 | |||
793 | if (panic_on_unrecovered_nmi) | ||
794 | panic("NMI: Not continuing"); | ||
795 | |||
796 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | ||
797 | } | ||
798 | |||
799 | /* Runs on IST stack. This code must keep interrupts off all the time. | ||
800 | Nested NMIs are prevented by the CPU. */ | ||
801 | asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs) | ||
802 | { | ||
803 | unsigned char reason = 0; | ||
804 | int cpu; | ||
805 | |||
806 | cpu = smp_processor_id(); | ||
807 | |||
808 | /* Only the BSP gets external NMIs from the system. */ | ||
809 | if (!cpu) | ||
810 | reason = get_nmi_reason(); | ||
811 | |||
812 | if (!(reason & 0xc0)) { | ||
813 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | ||
814 | == NOTIFY_STOP) | ||
815 | return; | ||
816 | /* | ||
817 | * Ok, so this is none of the documented NMI sources, | ||
818 | * so it must be the NMI watchdog. | ||
819 | */ | ||
820 | if (nmi_watchdog_tick(regs, reason)) | ||
821 | return; | ||
822 | if (!do_nmi_callback(regs, cpu)) | ||
823 | unknown_nmi_error(reason, regs); | ||
824 | |||
825 | return; | ||
826 | } | ||
827 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | ||
828 | return; | ||
829 | |||
830 | /* AK: following checks seem to be broken on modern chipsets. FIXME */ | ||
831 | if (reason & 0x80) | ||
832 | mem_parity_error(reason, regs); | ||
833 | if (reason & 0x40) | ||
834 | io_check_error(reason, regs); | ||
835 | } | ||
836 | |||
837 | asmlinkage notrace __kprobes void | ||
838 | do_nmi(struct pt_regs *regs, long error_code) | ||
839 | { | ||
840 | nmi_enter(); | ||
841 | |||
842 | add_pda(__nmi_count, 1); | ||
843 | |||
844 | if (!ignore_nmis) | ||
845 | default_do_nmi(regs); | ||
846 | |||
847 | nmi_exit(); | ||
848 | } | ||
849 | |||
850 | void stop_nmi(void) | ||
851 | { | ||
852 | acpi_nmi_disable(); | ||
853 | ignore_nmis++; | ||
854 | } | ||
855 | |||
856 | void restart_nmi(void) | ||
857 | { | ||
858 | ignore_nmis--; | ||
859 | acpi_nmi_enable(); | ||
860 | } | ||
861 | |||
862 | /* runs on IST stack. */ | ||
863 | asmlinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) | ||
864 | { | ||
865 | trace_hardirqs_fixup(); | ||
866 | |||
867 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) | ||
868 | == NOTIFY_STOP) | ||
869 | return; | ||
870 | |||
871 | preempt_conditional_sti(regs); | ||
872 | do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); | ||
873 | preempt_conditional_cli(regs); | ||
874 | } | ||
875 | |||
876 | /* Help handler running on IST stack to switch back to user stack | ||
877 | for scheduling or signal handling. The actual stack switch is done in | ||
878 | entry.S */ | ||
879 | asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | ||
880 | { | ||
881 | struct pt_regs *regs = eregs; | ||
882 | /* Did already sync */ | ||
883 | if (eregs == (struct pt_regs *)eregs->sp) | ||
884 | ; | ||
885 | /* Exception from user space */ | ||
886 | else if (user_mode(eregs)) | ||
887 | regs = task_pt_regs(current); | ||
888 | /* Exception from kernel and interrupts are enabled. Move to | ||
889 | kernel process stack. */ | ||
890 | else if (eregs->flags & X86_EFLAGS_IF) | ||
891 | regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); | ||
892 | if (eregs != regs) | ||
893 | *regs = *eregs; | ||
894 | return regs; | ||
895 | } | ||
896 | |||
897 | /* runs on IST stack. */ | ||
898 | asmlinkage void __kprobes do_debug(struct pt_regs *regs, | ||
899 | unsigned long error_code) | ||
900 | { | ||
901 | struct task_struct *tsk = current; | ||
902 | unsigned long condition; | ||
903 | siginfo_t info; | ||
904 | |||
905 | trace_hardirqs_fixup(); | ||
906 | |||
907 | get_debugreg(condition, 6); | ||
908 | |||
909 | /* | ||
910 | * The processor cleared BTF, so don't mark that we need it set. | ||
911 | */ | ||
912 | clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR); | ||
913 | tsk->thread.debugctlmsr = 0; | ||
914 | |||
915 | if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, | ||
916 | SIGTRAP) == NOTIFY_STOP) | ||
917 | return; | ||
918 | |||
919 | preempt_conditional_sti(regs); | ||
920 | |||
921 | /* Mask out spurious debug traps due to lazy DR7 setting */ | ||
922 | if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { | ||
923 | if (!tsk->thread.debugreg7) | ||
924 | goto clear_dr7; | ||
925 | } | ||
926 | |||
927 | tsk->thread.debugreg6 = condition; | ||
928 | |||
929 | /* | ||
930 | * Single-stepping through TF: make sure we ignore any events in | ||
931 | * kernel space (but re-enable TF when returning to user mode). | ||
932 | */ | ||
933 | if (condition & DR_STEP) { | ||
934 | if (!user_mode(regs)) | ||
935 | goto clear_TF_reenable; | ||
936 | } | ||
937 | |||
938 | /* Ok, finally something we can handle */ | ||
939 | tsk->thread.trap_no = 1; | ||
940 | tsk->thread.error_code = error_code; | ||
941 | info.si_signo = SIGTRAP; | ||
942 | info.si_errno = 0; | ||
943 | info.si_code = get_si_code(condition); | ||
944 | info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; | ||
945 | force_sig_info(SIGTRAP, &info, tsk); | ||
946 | |||
947 | clear_dr7: | ||
948 | set_debugreg(0, 7); | ||
949 | preempt_conditional_cli(regs); | ||
950 | return; | ||
951 | |||
952 | clear_TF_reenable: | ||
953 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); | ||
954 | regs->flags &= ~X86_EFLAGS_TF; | ||
955 | preempt_conditional_cli(regs); | ||
956 | return; | ||
957 | } | ||
958 | |||
959 | static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) | ||
960 | { | ||
961 | if (fixup_exception(regs)) | ||
962 | return 1; | ||
963 | |||
964 | notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE); | ||
965 | /* Illegal floating point operation in the kernel */ | ||
966 | current->thread.trap_no = trapnr; | ||
967 | die(str, regs, 0); | ||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | /* | ||
972 | * Note that we play around with the 'TS' bit in an attempt to get | ||
973 | * the correct behaviour even in the presence of the asynchronous | ||
974 | * IRQ13 behaviour | ||
975 | */ | ||
976 | asmlinkage void do_coprocessor_error(struct pt_regs *regs) | ||
977 | { | ||
978 | void __user *ip = (void __user *)(regs->ip); | ||
979 | struct task_struct *task; | ||
980 | siginfo_t info; | ||
981 | unsigned short cwd, swd; | ||
982 | |||
983 | conditional_sti(regs); | ||
984 | if (!user_mode(regs) && | ||
985 | kernel_math_error(regs, "kernel x87 math error", 16)) | ||
986 | return; | ||
987 | |||
988 | /* | ||
989 | * Save the info for the exception handler and clear the error. | ||
990 | */ | ||
991 | task = current; | ||
992 | save_init_fpu(task); | ||
993 | task->thread.trap_no = 16; | ||
994 | task->thread.error_code = 0; | ||
995 | info.si_signo = SIGFPE; | ||
996 | info.si_errno = 0; | ||
997 | info.si_code = __SI_FAULT; | ||
998 | info.si_addr = ip; | ||
999 | /* | ||
1000 | * (~cwd & swd) will mask out exceptions that are not set to unmasked | ||
1001 | * status. 0x3f is the exception bits in these regs, 0x200 is the | ||
1002 | * C1 reg you need in case of a stack fault, 0x040 is the stack | ||
1003 | * fault bit. We should only be taking one exception at a time, | ||
1004 | * so if this combination doesn't produce any single exception, | ||
1005 | * then we have a bad program that isn't synchronizing its FPU usage | ||
1006 | * and it will suffer the consequences since we won't be able to | ||
1007 | * fully reproduce the context of the exception | ||
1008 | */ | ||
1009 | cwd = get_fpu_cwd(task); | ||
1010 | swd = get_fpu_swd(task); | ||
1011 | switch (swd & ~cwd & 0x3f) { | ||
1012 | case 0x000: /* No unmasked exception */ | ||
1013 | default: /* Multiple exceptions */ | ||
1014 | break; | ||
1015 | case 0x001: /* Invalid Op */ | ||
1016 | /* | ||
1017 | * swd & 0x240 == 0x040: Stack Underflow | ||
1018 | * swd & 0x240 == 0x240: Stack Overflow | ||
1019 | * User must clear the SF bit (0x40) if set | ||
1020 | */ | ||
1021 | info.si_code = FPE_FLTINV; | ||
1022 | break; | ||
1023 | case 0x002: /* Denormalize */ | ||
1024 | case 0x010: /* Underflow */ | ||
1025 | info.si_code = FPE_FLTUND; | ||
1026 | break; | ||
1027 | case 0x004: /* Zero Divide */ | ||
1028 | info.si_code = FPE_FLTDIV; | ||
1029 | break; | ||
1030 | case 0x008: /* Overflow */ | ||
1031 | info.si_code = FPE_FLTOVF; | ||
1032 | break; | ||
1033 | case 0x020: /* Precision */ | ||
1034 | info.si_code = FPE_FLTRES; | ||
1035 | break; | ||
1036 | } | ||
1037 | force_sig_info(SIGFPE, &info, task); | ||
1038 | } | ||
1039 | |||
1040 | asmlinkage void bad_intr(void) | ||
1041 | { | ||
1042 | printk("bad interrupt"); | ||
1043 | } | ||
1044 | |||
1045 | asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) | ||
1046 | { | ||
1047 | void __user *ip = (void __user *)(regs->ip); | ||
1048 | struct task_struct *task; | ||
1049 | siginfo_t info; | ||
1050 | unsigned short mxcsr; | ||
1051 | |||
1052 | conditional_sti(regs); | ||
1053 | if (!user_mode(regs) && | ||
1054 | kernel_math_error(regs, "kernel simd math error", 19)) | ||
1055 | return; | ||
1056 | |||
1057 | /* | ||
1058 | * Save the info for the exception handler and clear the error. | ||
1059 | */ | ||
1060 | task = current; | ||
1061 | save_init_fpu(task); | ||
1062 | task->thread.trap_no = 19; | ||
1063 | task->thread.error_code = 0; | ||
1064 | info.si_signo = SIGFPE; | ||
1065 | info.si_errno = 0; | ||
1066 | info.si_code = __SI_FAULT; | ||
1067 | info.si_addr = ip; | ||
1068 | /* | ||
1069 | * The SIMD FPU exceptions are handled a little differently, as there | ||
1070 | * is only a single status/control register. Thus, to determine which | ||
1071 | * unmasked exception was caught we must mask the exception mask bits | ||
1072 | * at 0x1f80, and then use these to mask the exception bits at 0x3f. | ||
1073 | */ | ||
1074 | mxcsr = get_fpu_mxcsr(task); | ||
1075 | switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { | ||
1076 | case 0x000: | ||
1077 | default: | ||
1078 | break; | ||
1079 | case 0x001: /* Invalid Op */ | ||
1080 | info.si_code = FPE_FLTINV; | ||
1081 | break; | ||
1082 | case 0x002: /* Denormalize */ | ||
1083 | case 0x010: /* Underflow */ | ||
1084 | info.si_code = FPE_FLTUND; | ||
1085 | break; | ||
1086 | case 0x004: /* Zero Divide */ | ||
1087 | info.si_code = FPE_FLTDIV; | ||
1088 | break; | ||
1089 | case 0x008: /* Overflow */ | ||
1090 | info.si_code = FPE_FLTOVF; | ||
1091 | break; | ||
1092 | case 0x020: /* Precision */ | ||
1093 | info.si_code = FPE_FLTRES; | ||
1094 | break; | ||
1095 | } | ||
1096 | force_sig_info(SIGFPE, &info, task); | ||
1097 | } | ||
1098 | |||
1099 | asmlinkage void do_spurious_interrupt_bug(struct pt_regs *regs) | ||
1100 | { | ||
1101 | } | ||
1102 | |||
1103 | asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) | ||
1104 | { | ||
1105 | } | ||
1106 | |||
1107 | asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) | ||
1108 | { | ||
1109 | } | ||
1110 | |||
1111 | /* | ||
1112 | * 'math_state_restore()' saves the current math information in the | ||
1113 | * old math state array, and gets the new ones from the current task | ||
1114 | * | ||
1115 | * Careful.. There are problems with IBM-designed IRQ13 behaviour. | ||
1116 | * Don't touch unless you *really* know how it works. | ||
1117 | */ | ||
1118 | asmlinkage void math_state_restore(void) | ||
1119 | { | ||
1120 | struct task_struct *me = current; | ||
1121 | |||
1122 | if (!used_math()) { | ||
1123 | local_irq_enable(); | ||
1124 | /* | ||
1125 | * does a slab alloc which can sleep | ||
1126 | */ | ||
1127 | if (init_fpu(me)) { | ||
1128 | /* | ||
1129 | * ran out of memory! | ||
1130 | */ | ||
1131 | do_group_exit(SIGKILL); | ||
1132 | return; | ||
1133 | } | ||
1134 | local_irq_disable(); | ||
1135 | } | ||
1136 | |||
1137 | clts(); /* Allow maths ops (or we recurse) */ | ||
1138 | /* | ||
1139 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
1140 | */ | ||
1141 | if (unlikely(restore_fpu_checking(me))) { | ||
1142 | stts(); | ||
1143 | force_sig(SIGSEGV, me); | ||
1144 | return; | ||
1145 | } | ||
1146 | task_thread_info(me)->status |= TS_USEDFPU; | ||
1147 | me->fpu_counter++; | ||
1148 | } | ||
1149 | EXPORT_SYMBOL_GPL(math_state_restore); | ||
1150 | |||
1151 | void __init trap_init(void) | ||
1152 | { | ||
1153 | set_intr_gate(0, ÷_error); | ||
1154 | set_intr_gate_ist(1, &debug, DEBUG_STACK); | ||
1155 | set_intr_gate_ist(2, &nmi, NMI_STACK); | ||
1156 | /* int3 can be called from all */ | ||
1157 | set_system_gate_ist(3, &int3, DEBUG_STACK); | ||
1158 | /* int4 can be called from all */ | ||
1159 | set_system_gate(4, &overflow); | ||
1160 | set_intr_gate(5, &bounds); | ||
1161 | set_intr_gate(6, &invalid_op); | ||
1162 | set_intr_gate(7, &device_not_available); | ||
1163 | set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK); | ||
1164 | set_intr_gate(9, &coprocessor_segment_overrun); | ||
1165 | set_intr_gate(10, &invalid_TSS); | ||
1166 | set_intr_gate(11, &segment_not_present); | ||
1167 | set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK); | ||
1168 | set_intr_gate(13, &general_protection); | ||
1169 | set_intr_gate(14, &page_fault); | ||
1170 | set_intr_gate(15, &spurious_interrupt_bug); | ||
1171 | set_intr_gate(16, &coprocessor_error); | ||
1172 | set_intr_gate(17, &alignment_check); | ||
1173 | #ifdef CONFIG_X86_MCE | ||
1174 | set_intr_gate_ist(18, &machine_check, MCE_STACK); | ||
1175 | #endif | ||
1176 | set_intr_gate(19, &simd_coprocessor_error); | ||
1177 | |||
1178 | #ifdef CONFIG_IA32_EMULATION | ||
1179 | set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall); | ||
1180 | #endif | ||
1181 | /* | ||
1182 | * Should be a barrier for any external CPU state: | ||
1183 | */ | ||
1184 | cpu_init(); | ||
1185 | } | ||
1186 | |||
1187 | static int __init oops_setup(char *s) | ||
1188 | { | ||
1189 | if (!s) | ||
1190 | return -EINVAL; | ||
1191 | if (!strcmp(s, "panic")) | ||
1192 | panic_on_oops = 1; | ||
1193 | return 0; | ||
1194 | } | ||
1195 | early_param("oops", oops_setup); | ||
1196 | |||
1197 | static int __init kstack_setup(char *s) | ||
1198 | { | ||
1199 | if (!s) | ||
1200 | return -EINVAL; | ||
1201 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
1202 | return 0; | ||
1203 | } | ||
1204 | early_param("kstack", kstack_setup); | ||
1205 | |||
1206 | static int __init code_bytes_setup(char *s) | ||
1207 | { | ||
1208 | code_bytes = simple_strtoul(s, NULL, 0); | ||
1209 | if (code_bytes > 8192) | ||
1210 | code_bytes = 8192; | ||
1211 | |||
1212 | return 1; | ||
1213 | } | ||
1214 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c index 520cca0ee04e..6513d41ea21e 100644 --- a/arch/x86/mach-generic/es7000.c +++ b/arch/x86/mach-generic/es7000.c | |||
@@ -47,16 +47,26 @@ static __init int mps_oem_check(struct mp_config_table *mpc, char *oem, | |||
47 | /* Hook from generic ACPI tables.c */ | 47 | /* Hook from generic ACPI tables.c */ |
48 | static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) | 48 | static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) |
49 | { | 49 | { |
50 | unsigned long oem_addr; | 50 | unsigned long oem_addr = 0; |
51 | int check_dsdt; | ||
52 | int ret = 0; | ||
53 | |||
54 | /* check dsdt at first to avoid clear fix_map for oem_addr */ | ||
55 | check_dsdt = es7000_check_dsdt(); | ||
56 | |||
51 | if (!find_unisys_acpi_oem_table(&oem_addr)) { | 57 | if (!find_unisys_acpi_oem_table(&oem_addr)) { |
52 | if (es7000_check_dsdt()) | 58 | if (check_dsdt) |
53 | return parse_unisys_oem((char *)oem_addr); | 59 | ret = parse_unisys_oem((char *)oem_addr); |
54 | else { | 60 | else { |
55 | setup_unisys(); | 61 | setup_unisys(); |
56 | return 1; | 62 | ret = 1; |
57 | } | 63 | } |
64 | /* | ||
65 | * we need to unmap it | ||
66 | */ | ||
67 | unmap_unisys_acpi_oem_table(oem_addr); | ||
58 | } | 68 | } |
59 | return 0; | 69 | return ret; |
60 | } | 70 | } |
61 | #else | 71 | #else |
62 | static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) | 72 | static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) |
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index dfb932dcf136..59f89b434b45 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
@@ -13,12 +13,8 @@ obj-$(CONFIG_MMIOTRACE) += mmiotrace.o | |||
13 | mmiotrace-y := pf_in.o mmio-mod.o | 13 | mmiotrace-y := pf_in.o mmio-mod.o |
14 | obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o | 14 | obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o |
15 | 15 | ||
16 | ifeq ($(CONFIG_X86_32),y) | 16 | obj-$(CONFIG_NUMA) += numa_$(BITS).o |
17 | obj-$(CONFIG_NUMA) += discontig_32.o | ||
18 | else | ||
19 | obj-$(CONFIG_NUMA) += numa_64.o | ||
20 | obj-$(CONFIG_K8_NUMA) += k8topology_64.o | 17 | obj-$(CONFIG_K8_NUMA) += k8topology_64.o |
21 | endif | ||
22 | obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o | 18 | obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o |
23 | 19 | ||
24 | obj-$(CONFIG_MEMTEST) += memtest.o | 20 | obj-$(CONFIG_MEMTEST) += memtest.o |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index a742d753d5b0..3f2b8962cbd0 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -592,11 +592,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
592 | unsigned long flags; | 592 | unsigned long flags; |
593 | #endif | 593 | #endif |
594 | 594 | ||
595 | /* | ||
596 | * We can fault from pretty much anywhere, with unknown IRQ state. | ||
597 | */ | ||
598 | trace_hardirqs_fixup(); | ||
599 | |||
600 | tsk = current; | 595 | tsk = current; |
601 | mm = tsk->mm; | 596 | mm = tsk->mm; |
602 | prefetchw(&mm->mmap_sem); | 597 | prefetchw(&mm->mmap_sem); |
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 007bb06c7504..4ba373c5b8c8 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c | |||
@@ -82,7 +82,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, | |||
82 | pte_t pte = gup_get_pte(ptep); | 82 | pte_t pte = gup_get_pte(ptep); |
83 | struct page *page; | 83 | struct page *page; |
84 | 84 | ||
85 | if ((pte_val(pte) & (mask | _PAGE_SPECIAL)) != mask) { | 85 | if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) { |
86 | pte_unmap(ptep); | 86 | pte_unmap(ptep); |
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
@@ -116,10 +116,10 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr, | |||
116 | mask = _PAGE_PRESENT|_PAGE_USER; | 116 | mask = _PAGE_PRESENT|_PAGE_USER; |
117 | if (write) | 117 | if (write) |
118 | mask |= _PAGE_RW; | 118 | mask |= _PAGE_RW; |
119 | if ((pte_val(pte) & mask) != mask) | 119 | if ((pte_flags(pte) & mask) != mask) |
120 | return 0; | 120 | return 0; |
121 | /* hugepages are never "special" */ | 121 | /* hugepages are never "special" */ |
122 | VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL); | 122 | VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL); |
123 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | 123 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); |
124 | 124 | ||
125 | refs = 0; | 125 | refs = 0; |
@@ -173,10 +173,10 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr, | |||
173 | mask = _PAGE_PRESENT|_PAGE_USER; | 173 | mask = _PAGE_PRESENT|_PAGE_USER; |
174 | if (write) | 174 | if (write) |
175 | mask |= _PAGE_RW; | 175 | mask |= _PAGE_RW; |
176 | if ((pte_val(pte) & mask) != mask) | 176 | if ((pte_flags(pte) & mask) != mask) |
177 | return 0; | 177 | return 0; |
178 | /* hugepages are never "special" */ | 178 | /* hugepages are never "special" */ |
179 | VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL); | 179 | VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL); |
180 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | 180 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); |
181 | 181 | ||
182 | refs = 0; | 182 | refs = 0; |
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index bbe044dbe014..8396868e82c5 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -558,7 +558,7 @@ void zap_low_mappings(void) | |||
558 | 558 | ||
559 | int nx_enabled; | 559 | int nx_enabled; |
560 | 560 | ||
561 | pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL); | 561 | pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP); |
562 | EXPORT_SYMBOL_GPL(__supported_pte_mask); | 562 | EXPORT_SYMBOL_GPL(__supported_pte_mask); |
563 | 563 | ||
564 | #ifdef CONFIG_X86_PAE | 564 | #ifdef CONFIG_X86_PAE |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 3e10054c5731..b8e461d49412 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -89,7 +89,7 @@ early_param("gbpages", parse_direct_gbpages_on); | |||
89 | 89 | ||
90 | int after_bootmem; | 90 | int after_bootmem; |
91 | 91 | ||
92 | unsigned long __supported_pte_mask __read_mostly = ~0UL; | 92 | pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP; |
93 | EXPORT_SYMBOL_GPL(__supported_pte_mask); | 93 | EXPORT_SYMBOL_GPL(__supported_pte_mask); |
94 | 94 | ||
95 | static int do_not_nx __cpuinitdata; | 95 | static int do_not_nx __cpuinitdata; |
@@ -196,9 +196,6 @@ set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte) | |||
196 | } | 196 | } |
197 | 197 | ||
198 | pte = pte_offset_kernel(pmd, vaddr); | 198 | pte = pte_offset_kernel(pmd, vaddr); |
199 | if (!pte_none(*pte) && pte_val(new_pte) && | ||
200 | pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask)) | ||
201 | pte_ERROR(*pte); | ||
202 | set_pte(pte, new_pte); | 199 | set_pte(pte, new_pte); |
203 | 200 | ||
204 | /* | 201 | /* |
@@ -313,7 +310,7 @@ static __ref void *alloc_low_page(unsigned long *phys) | |||
313 | if (pfn >= table_top) | 310 | if (pfn >= table_top) |
314 | panic("alloc_low_page: ran out of memory"); | 311 | panic("alloc_low_page: ran out of memory"); |
315 | 312 | ||
316 | adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE); | 313 | adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE); |
317 | memset(adr, 0, PAGE_SIZE); | 314 | memset(adr, 0, PAGE_SIZE); |
318 | *phys = pfn * PAGE_SIZE; | 315 | *phys = pfn * PAGE_SIZE; |
319 | return adr; | 316 | return adr; |
@@ -749,7 +746,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
749 | old_start = mr[i].start; | 746 | old_start = mr[i].start; |
750 | memmove(&mr[i], &mr[i+1], | 747 | memmove(&mr[i], &mr[i+1], |
751 | (nr_range - 1 - i) * sizeof (struct map_range)); | 748 | (nr_range - 1 - i) * sizeof (struct map_range)); |
752 | mr[i].start = old_start; | 749 | mr[i--].start = old_start; |
753 | nr_range--; | 750 | nr_range--; |
754 | } | 751 | } |
755 | 752 | ||
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 8cbeda15cd29..e4c43ec71b29 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -45,6 +45,27 @@ unsigned long __phys_addr(unsigned long x) | |||
45 | } | 45 | } |
46 | EXPORT_SYMBOL(__phys_addr); | 46 | EXPORT_SYMBOL(__phys_addr); |
47 | 47 | ||
48 | bool __virt_addr_valid(unsigned long x) | ||
49 | { | ||
50 | if (x >= __START_KERNEL_map) { | ||
51 | x -= __START_KERNEL_map; | ||
52 | if (x >= KERNEL_IMAGE_SIZE) | ||
53 | return false; | ||
54 | x += phys_base; | ||
55 | } else { | ||
56 | if (x < PAGE_OFFSET) | ||
57 | return false; | ||
58 | x -= PAGE_OFFSET; | ||
59 | if (system_state == SYSTEM_BOOTING ? | ||
60 | x > MAXMEM : !phys_addr_valid(x)) { | ||
61 | return false; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return pfn_valid(x >> PAGE_SHIFT); | ||
66 | } | ||
67 | EXPORT_SYMBOL(__virt_addr_valid); | ||
68 | |||
48 | #else | 69 | #else |
49 | 70 | ||
50 | static inline int phys_addr_valid(unsigned long addr) | 71 | static inline int phys_addr_valid(unsigned long addr) |
@@ -56,13 +77,24 @@ static inline int phys_addr_valid(unsigned long addr) | |||
56 | unsigned long __phys_addr(unsigned long x) | 77 | unsigned long __phys_addr(unsigned long x) |
57 | { | 78 | { |
58 | /* VMALLOC_* aren't constants; not available at the boot time */ | 79 | /* VMALLOC_* aren't constants; not available at the boot time */ |
59 | VIRTUAL_BUG_ON(x < PAGE_OFFSET || (system_state != SYSTEM_BOOTING && | 80 | VIRTUAL_BUG_ON(x < PAGE_OFFSET); |
60 | is_vmalloc_addr((void *)x))); | 81 | VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING && |
82 | is_vmalloc_addr((void *) x)); | ||
61 | return x - PAGE_OFFSET; | 83 | return x - PAGE_OFFSET; |
62 | } | 84 | } |
63 | EXPORT_SYMBOL(__phys_addr); | 85 | EXPORT_SYMBOL(__phys_addr); |
64 | #endif | 86 | #endif |
65 | 87 | ||
88 | bool __virt_addr_valid(unsigned long x) | ||
89 | { | ||
90 | if (x < PAGE_OFFSET) | ||
91 | return false; | ||
92 | if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x)) | ||
93 | return false; | ||
94 | return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT); | ||
95 | } | ||
96 | EXPORT_SYMBOL(__virt_addr_valid); | ||
97 | |||
66 | #endif | 98 | #endif |
67 | 99 | ||
68 | int page_is_ram(unsigned long pagenr) | 100 | int page_is_ram(unsigned long pagenr) |
@@ -242,16 +274,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
242 | switch (prot_val) { | 274 | switch (prot_val) { |
243 | case _PAGE_CACHE_UC: | 275 | case _PAGE_CACHE_UC: |
244 | default: | 276 | default: |
245 | prot = PAGE_KERNEL_NOCACHE; | 277 | prot = PAGE_KERNEL_IO_NOCACHE; |
246 | break; | 278 | break; |
247 | case _PAGE_CACHE_UC_MINUS: | 279 | case _PAGE_CACHE_UC_MINUS: |
248 | prot = PAGE_KERNEL_UC_MINUS; | 280 | prot = PAGE_KERNEL_IO_UC_MINUS; |
249 | break; | 281 | break; |
250 | case _PAGE_CACHE_WC: | 282 | case _PAGE_CACHE_WC: |
251 | prot = PAGE_KERNEL_WC; | 283 | prot = PAGE_KERNEL_IO_WC; |
252 | break; | 284 | break; |
253 | case _PAGE_CACHE_WB: | 285 | case _PAGE_CACHE_WB: |
254 | prot = PAGE_KERNEL; | 286 | prot = PAGE_KERNEL_IO; |
255 | break; | 287 | break; |
256 | } | 288 | } |
257 | 289 | ||
@@ -568,12 +600,12 @@ static void __init __early_set_fixmap(enum fixed_addresses idx, | |||
568 | } | 600 | } |
569 | 601 | ||
570 | static inline void __init early_set_fixmap(enum fixed_addresses idx, | 602 | static inline void __init early_set_fixmap(enum fixed_addresses idx, |
571 | unsigned long phys) | 603 | unsigned long phys, pgprot_t prot) |
572 | { | 604 | { |
573 | if (after_paging_init) | 605 | if (after_paging_init) |
574 | set_fixmap(idx, phys); | 606 | __set_fixmap(idx, phys, prot); |
575 | else | 607 | else |
576 | __early_set_fixmap(idx, phys, PAGE_KERNEL); | 608 | __early_set_fixmap(idx, phys, prot); |
577 | } | 609 | } |
578 | 610 | ||
579 | static inline void __init early_clear_fixmap(enum fixed_addresses idx) | 611 | static inline void __init early_clear_fixmap(enum fixed_addresses idx) |
@@ -584,16 +616,22 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx) | |||
584 | __early_set_fixmap(idx, 0, __pgprot(0)); | 616 | __early_set_fixmap(idx, 0, __pgprot(0)); |
585 | } | 617 | } |
586 | 618 | ||
587 | 619 | static void *prev_map[FIX_BTMAPS_SLOTS] __initdata; | |
588 | static int __initdata early_ioremap_nested; | 620 | static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata; |
589 | |||
590 | static int __init check_early_ioremap_leak(void) | 621 | static int __init check_early_ioremap_leak(void) |
591 | { | 622 | { |
592 | if (!early_ioremap_nested) | 623 | int count = 0; |
624 | int i; | ||
625 | |||
626 | for (i = 0; i < FIX_BTMAPS_SLOTS; i++) | ||
627 | if (prev_map[i]) | ||
628 | count++; | ||
629 | |||
630 | if (!count) | ||
593 | return 0; | 631 | return 0; |
594 | WARN(1, KERN_WARNING | 632 | WARN(1, KERN_WARNING |
595 | "Debug warning: early ioremap leak of %d areas detected.\n", | 633 | "Debug warning: early ioremap leak of %d areas detected.\n", |
596 | early_ioremap_nested); | 634 | count); |
597 | printk(KERN_WARNING | 635 | printk(KERN_WARNING |
598 | "please boot with early_ioremap_debug and report the dmesg.\n"); | 636 | "please boot with early_ioremap_debug and report the dmesg.\n"); |
599 | 637 | ||
@@ -601,18 +639,33 @@ static int __init check_early_ioremap_leak(void) | |||
601 | } | 639 | } |
602 | late_initcall(check_early_ioremap_leak); | 640 | late_initcall(check_early_ioremap_leak); |
603 | 641 | ||
604 | void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | 642 | static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot) |
605 | { | 643 | { |
606 | unsigned long offset, last_addr; | 644 | unsigned long offset, last_addr; |
607 | unsigned int nrpages, nesting; | 645 | unsigned int nrpages; |
608 | enum fixed_addresses idx0, idx; | 646 | enum fixed_addresses idx0, idx; |
647 | int i, slot; | ||
609 | 648 | ||
610 | WARN_ON(system_state != SYSTEM_BOOTING); | 649 | WARN_ON(system_state != SYSTEM_BOOTING); |
611 | 650 | ||
612 | nesting = early_ioremap_nested; | 651 | slot = -1; |
652 | for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { | ||
653 | if (!prev_map[i]) { | ||
654 | slot = i; | ||
655 | break; | ||
656 | } | ||
657 | } | ||
658 | |||
659 | if (slot < 0) { | ||
660 | printk(KERN_INFO "early_iomap(%08lx, %08lx) not found slot\n", | ||
661 | phys_addr, size); | ||
662 | WARN_ON(1); | ||
663 | return NULL; | ||
664 | } | ||
665 | |||
613 | if (early_ioremap_debug) { | 666 | if (early_ioremap_debug) { |
614 | printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ", | 667 | printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ", |
615 | phys_addr, size, nesting); | 668 | phys_addr, size, slot); |
616 | dump_stack(); | 669 | dump_stack(); |
617 | } | 670 | } |
618 | 671 | ||
@@ -623,11 +676,7 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
623 | return NULL; | 676 | return NULL; |
624 | } | 677 | } |
625 | 678 | ||
626 | if (nesting >= FIX_BTMAPS_NESTING) { | 679 | prev_size[slot] = size; |
627 | WARN_ON(1); | ||
628 | return NULL; | ||
629 | } | ||
630 | early_ioremap_nested++; | ||
631 | /* | 680 | /* |
632 | * Mappings have to be page-aligned | 681 | * Mappings have to be page-aligned |
633 | */ | 682 | */ |
@@ -647,10 +696,10 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
647 | /* | 696 | /* |
648 | * Ok, go for it.. | 697 | * Ok, go for it.. |
649 | */ | 698 | */ |
650 | idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting; | 699 | idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; |
651 | idx = idx0; | 700 | idx = idx0; |
652 | while (nrpages > 0) { | 701 | while (nrpages > 0) { |
653 | early_set_fixmap(idx, phys_addr); | 702 | early_set_fixmap(idx, phys_addr, prot); |
654 | phys_addr += PAGE_SIZE; | 703 | phys_addr += PAGE_SIZE; |
655 | --idx; | 704 | --idx; |
656 | --nrpages; | 705 | --nrpages; |
@@ -658,7 +707,20 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
658 | if (early_ioremap_debug) | 707 | if (early_ioremap_debug) |
659 | printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0)); | 708 | printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0)); |
660 | 709 | ||
661 | return (void *) (offset + fix_to_virt(idx0)); | 710 | prev_map[slot] = (void *) (offset + fix_to_virt(idx0)); |
711 | return prev_map[slot]; | ||
712 | } | ||
713 | |||
714 | /* Remap an IO device */ | ||
715 | void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | ||
716 | { | ||
717 | return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO); | ||
718 | } | ||
719 | |||
720 | /* Remap memory */ | ||
721 | void __init *early_memremap(unsigned long phys_addr, unsigned long size) | ||
722 | { | ||
723 | return __early_ioremap(phys_addr, size, PAGE_KERNEL); | ||
662 | } | 724 | } |
663 | 725 | ||
664 | void __init early_iounmap(void *addr, unsigned long size) | 726 | void __init early_iounmap(void *addr, unsigned long size) |
@@ -667,15 +729,33 @@ void __init early_iounmap(void *addr, unsigned long size) | |||
667 | unsigned long offset; | 729 | unsigned long offset; |
668 | unsigned int nrpages; | 730 | unsigned int nrpages; |
669 | enum fixed_addresses idx; | 731 | enum fixed_addresses idx; |
670 | int nesting; | 732 | int i, slot; |
733 | |||
734 | slot = -1; | ||
735 | for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { | ||
736 | if (prev_map[i] == addr) { | ||
737 | slot = i; | ||
738 | break; | ||
739 | } | ||
740 | } | ||
671 | 741 | ||
672 | nesting = --early_ioremap_nested; | 742 | if (slot < 0) { |
673 | if (WARN_ON(nesting < 0)) | 743 | printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n", |
744 | addr, size); | ||
745 | WARN_ON(1); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | if (prev_size[slot] != size) { | ||
750 | printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n", | ||
751 | addr, size, slot, prev_size[slot]); | ||
752 | WARN_ON(1); | ||
674 | return; | 753 | return; |
754 | } | ||
675 | 755 | ||
676 | if (early_ioremap_debug) { | 756 | if (early_ioremap_debug) { |
677 | printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr, | 757 | printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr, |
678 | size, nesting); | 758 | size, slot); |
679 | dump_stack(); | 759 | dump_stack(); |
680 | } | 760 | } |
681 | 761 | ||
@@ -687,12 +767,13 @@ void __init early_iounmap(void *addr, unsigned long size) | |||
687 | offset = virt_addr & ~PAGE_MASK; | 767 | offset = virt_addr & ~PAGE_MASK; |
688 | nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; | 768 | nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; |
689 | 769 | ||
690 | idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting; | 770 | idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; |
691 | while (nrpages > 0) { | 771 | while (nrpages > 0) { |
692 | early_clear_fixmap(idx); | 772 | early_clear_fixmap(idx); |
693 | --idx; | 773 | --idx; |
694 | --nrpages; | 774 | --nrpages; |
695 | } | 775 | } |
776 | prev_map[slot] = 0; | ||
696 | } | 777 | } |
697 | 778 | ||
698 | void __this_fixmap_does_not_exist(void) | 779 | void __this_fixmap_does_not_exist(void) |
diff --git a/arch/x86/mm/discontig_32.c b/arch/x86/mm/numa_32.c index 847c164725f4..847c164725f4 100644 --- a/arch/x86/mm/discontig_32.c +++ b/arch/x86/mm/numa_32.c | |||
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c index 1b4763e26ea9..51c0a2fc14fe 100644 --- a/arch/x86/mm/srat_64.c +++ b/arch/x86/mm/srat_64.c | |||
@@ -138,7 +138,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) | |||
138 | return; | 138 | return; |
139 | } | 139 | } |
140 | 140 | ||
141 | if (is_uv_system()) | 141 | if (get_uv_system_type() >= UV_X2APIC) |
142 | apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; | 142 | apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; |
143 | else | 143 | else |
144 | apic_id = pa->apic_id; | 144 | apic_id = pa->apic_id; |
diff --git a/arch/x86/oprofile/Makefile b/arch/x86/oprofile/Makefile index 30f3eb366667..446902b2a6b6 100644 --- a/arch/x86/oprofile/Makefile +++ b/arch/x86/oprofile/Makefile | |||
@@ -7,6 +7,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ | |||
7 | timer_int.o ) | 7 | timer_int.o ) |
8 | 8 | ||
9 | oprofile-y := $(DRIVER_OBJS) init.o backtrace.o | 9 | oprofile-y := $(DRIVER_OBJS) init.o backtrace.o |
10 | oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \ | 10 | oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_amd.o \ |
11 | op_model_ppro.o op_model_p4.o | 11 | op_model_ppro.o op_model_p4.o |
12 | oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o | 12 | oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o |
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 8a5f1614a3d5..57f6c9088081 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -1,10 +1,11 @@ | |||
1 | /** | 1 | /** |
2 | * @file nmi_int.c | 2 | * @file nmi_int.c |
3 | * | 3 | * |
4 | * @remark Copyright 2002 OProfile authors | 4 | * @remark Copyright 2002-2008 OProfile authors |
5 | * @remark Read the file COPYING | 5 | * @remark Read the file COPYING |
6 | * | 6 | * |
7 | * @author John Levon <levon@movementarian.org> | 7 | * @author John Levon <levon@movementarian.org> |
8 | * @author Robert Richter <robert.richter@amd.com> | ||
8 | */ | 9 | */ |
9 | 10 | ||
10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
@@ -439,6 +440,7 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
439 | __u8 vendor = boot_cpu_data.x86_vendor; | 440 | __u8 vendor = boot_cpu_data.x86_vendor; |
440 | __u8 family = boot_cpu_data.x86; | 441 | __u8 family = boot_cpu_data.x86; |
441 | char *cpu_type; | 442 | char *cpu_type; |
443 | int ret = 0; | ||
442 | 444 | ||
443 | if (!cpu_has_apic) | 445 | if (!cpu_has_apic) |
444 | return -ENODEV; | 446 | return -ENODEV; |
@@ -451,19 +453,23 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
451 | default: | 453 | default: |
452 | return -ENODEV; | 454 | return -ENODEV; |
453 | case 6: | 455 | case 6: |
454 | model = &op_athlon_spec; | 456 | model = &op_amd_spec; |
455 | cpu_type = "i386/athlon"; | 457 | cpu_type = "i386/athlon"; |
456 | break; | 458 | break; |
457 | case 0xf: | 459 | case 0xf: |
458 | model = &op_athlon_spec; | 460 | model = &op_amd_spec; |
459 | /* Actually it could be i386/hammer too, but give | 461 | /* Actually it could be i386/hammer too, but give |
460 | user space an consistent name. */ | 462 | user space an consistent name. */ |
461 | cpu_type = "x86-64/hammer"; | 463 | cpu_type = "x86-64/hammer"; |
462 | break; | 464 | break; |
463 | case 0x10: | 465 | case 0x10: |
464 | model = &op_athlon_spec; | 466 | model = &op_amd_spec; |
465 | cpu_type = "x86-64/family10"; | 467 | cpu_type = "x86-64/family10"; |
466 | break; | 468 | break; |
469 | case 0x11: | ||
470 | model = &op_amd_spec; | ||
471 | cpu_type = "x86-64/family11h"; | ||
472 | break; | ||
467 | } | 473 | } |
468 | break; | 474 | break; |
469 | 475 | ||
@@ -490,17 +496,24 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
490 | return -ENODEV; | 496 | return -ENODEV; |
491 | } | 497 | } |
492 | 498 | ||
493 | init_sysfs(); | ||
494 | #ifdef CONFIG_SMP | 499 | #ifdef CONFIG_SMP |
495 | register_cpu_notifier(&oprofile_cpu_nb); | 500 | register_cpu_notifier(&oprofile_cpu_nb); |
496 | #endif | 501 | #endif |
497 | using_nmi = 1; | 502 | /* default values, can be overwritten by model */ |
498 | ops->create_files = nmi_create_files; | 503 | ops->create_files = nmi_create_files; |
499 | ops->setup = nmi_setup; | 504 | ops->setup = nmi_setup; |
500 | ops->shutdown = nmi_shutdown; | 505 | ops->shutdown = nmi_shutdown; |
501 | ops->start = nmi_start; | 506 | ops->start = nmi_start; |
502 | ops->stop = nmi_stop; | 507 | ops->stop = nmi_stop; |
503 | ops->cpu_type = cpu_type; | 508 | ops->cpu_type = cpu_type; |
509 | |||
510 | if (model->init) | ||
511 | ret = model->init(ops); | ||
512 | if (ret) | ||
513 | return ret; | ||
514 | |||
515 | init_sysfs(); | ||
516 | using_nmi = 1; | ||
504 | printk(KERN_INFO "oprofile: using NMI interrupt.\n"); | 517 | printk(KERN_INFO "oprofile: using NMI interrupt.\n"); |
505 | return 0; | 518 | return 0; |
506 | } | 519 | } |
@@ -513,4 +526,6 @@ void op_nmi_exit(void) | |||
513 | unregister_cpu_notifier(&oprofile_cpu_nb); | 526 | unregister_cpu_notifier(&oprofile_cpu_nb); |
514 | #endif | 527 | #endif |
515 | } | 528 | } |
529 | if (model->exit) | ||
530 | model->exit(); | ||
516 | } | 531 | } |
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c new file mode 100644 index 000000000000..d9faf607b3a6 --- /dev/null +++ b/arch/x86/oprofile/op_model_amd.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* | ||
2 | * @file op_model_amd.c | ||
3 | * athlon / K7 / K8 / Family 10h model-specific MSR operations | ||
4 | * | ||
5 | * @remark Copyright 2002-2008 OProfile authors | ||
6 | * @remark Read the file COPYING | ||
7 | * | ||
8 | * @author John Levon | ||
9 | * @author Philippe Elie | ||
10 | * @author Graydon Hoare | ||
11 | * @author Robert Richter <robert.richter@amd.com> | ||
12 | * @author Barry Kasindorf | ||
13 | */ | ||
14 | |||
15 | #include <linux/oprofile.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/pci.h> | ||
18 | |||
19 | #include <asm/ptrace.h> | ||
20 | #include <asm/msr.h> | ||
21 | #include <asm/nmi.h> | ||
22 | |||
23 | #include "op_x86_model.h" | ||
24 | #include "op_counter.h" | ||
25 | |||
26 | #define NUM_COUNTERS 4 | ||
27 | #define NUM_CONTROLS 4 | ||
28 | |||
29 | #define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) | ||
30 | #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0) | ||
31 | #define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0) | ||
32 | #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) | ||
33 | |||
34 | #define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) | ||
35 | #define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) | ||
36 | #define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) | ||
37 | #define CTRL_SET_ACTIVE(n) (n |= (1<<22)) | ||
38 | #define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) | ||
39 | #define CTRL_CLEAR_LO(x) (x &= (1<<21)) | ||
40 | #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) | ||
41 | #define CTRL_SET_ENABLE(val) (val |= 1<<20) | ||
42 | #define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) | ||
43 | #define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) | ||
44 | #define CTRL_SET_UM(val, m) (val |= (m << 8)) | ||
45 | #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) | ||
46 | #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) | ||
47 | #define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9)) | ||
48 | #define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8)) | ||
49 | |||
50 | static unsigned long reset_value[NUM_COUNTERS]; | ||
51 | |||
52 | #ifdef CONFIG_OPROFILE_IBS | ||
53 | |||
54 | /* IbsFetchCtl bits/masks */ | ||
55 | #define IBS_FETCH_HIGH_VALID_BIT (1UL << 17) /* bit 49 */ | ||
56 | #define IBS_FETCH_HIGH_ENABLE (1UL << 16) /* bit 48 */ | ||
57 | #define IBS_FETCH_LOW_MAX_CNT_MASK 0x0000FFFFUL /* MaxCnt mask */ | ||
58 | |||
59 | /*IbsOpCtl bits */ | ||
60 | #define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ | ||
61 | #define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ | ||
62 | |||
63 | /* Codes used in cpu_buffer.c */ | ||
64 | /* This produces duplicate code, need to be fixed */ | ||
65 | #define IBS_FETCH_BEGIN 3 | ||
66 | #define IBS_OP_BEGIN 4 | ||
67 | |||
68 | /* The function interface needs to be fixed, something like add | ||
69 | data. Should then be added to linux/oprofile.h. */ | ||
70 | extern void oprofile_add_ibs_sample(struct pt_regs *const regs, | ||
71 | unsigned int * const ibs_sample, u8 code); | ||
72 | |||
73 | struct ibs_fetch_sample { | ||
74 | /* MSRC001_1031 IBS Fetch Linear Address Register */ | ||
75 | unsigned int ibs_fetch_lin_addr_low; | ||
76 | unsigned int ibs_fetch_lin_addr_high; | ||
77 | /* MSRC001_1030 IBS Fetch Control Register */ | ||
78 | unsigned int ibs_fetch_ctl_low; | ||
79 | unsigned int ibs_fetch_ctl_high; | ||
80 | /* MSRC001_1032 IBS Fetch Physical Address Register */ | ||
81 | unsigned int ibs_fetch_phys_addr_low; | ||
82 | unsigned int ibs_fetch_phys_addr_high; | ||
83 | }; | ||
84 | |||
85 | struct ibs_op_sample { | ||
86 | /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */ | ||
87 | unsigned int ibs_op_rip_low; | ||
88 | unsigned int ibs_op_rip_high; | ||
89 | /* MSRC001_1035 IBS Op Data Register */ | ||
90 | unsigned int ibs_op_data1_low; | ||
91 | unsigned int ibs_op_data1_high; | ||
92 | /* MSRC001_1036 IBS Op Data 2 Register */ | ||
93 | unsigned int ibs_op_data2_low; | ||
94 | unsigned int ibs_op_data2_high; | ||
95 | /* MSRC001_1037 IBS Op Data 3 Register */ | ||
96 | unsigned int ibs_op_data3_low; | ||
97 | unsigned int ibs_op_data3_high; | ||
98 | /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */ | ||
99 | unsigned int ibs_dc_linear_low; | ||
100 | unsigned int ibs_dc_linear_high; | ||
101 | /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */ | ||
102 | unsigned int ibs_dc_phys_low; | ||
103 | unsigned int ibs_dc_phys_high; | ||
104 | }; | ||
105 | |||
106 | /* | ||
107 | * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+ | ||
108 | */ | ||
109 | static void clear_ibs_nmi(void); | ||
110 | |||
111 | static int ibs_allowed; /* AMD Family10h and later */ | ||
112 | |||
113 | struct op_ibs_config { | ||
114 | unsigned long op_enabled; | ||
115 | unsigned long fetch_enabled; | ||
116 | unsigned long max_cnt_fetch; | ||
117 | unsigned long max_cnt_op; | ||
118 | unsigned long rand_en; | ||
119 | unsigned long dispatched_ops; | ||
120 | }; | ||
121 | |||
122 | static struct op_ibs_config ibs_config; | ||
123 | |||
124 | #endif | ||
125 | |||
126 | /* functions for op_amd_spec */ | ||
127 | |||
128 | static void op_amd_fill_in_addresses(struct op_msrs * const msrs) | ||
129 | { | ||
130 | int i; | ||
131 | |||
132 | for (i = 0; i < NUM_COUNTERS; i++) { | ||
133 | if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) | ||
134 | msrs->counters[i].addr = MSR_K7_PERFCTR0 + i; | ||
135 | else | ||
136 | msrs->counters[i].addr = 0; | ||
137 | } | ||
138 | |||
139 | for (i = 0; i < NUM_CONTROLS; i++) { | ||
140 | if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i)) | ||
141 | msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i; | ||
142 | else | ||
143 | msrs->controls[i].addr = 0; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | |||
148 | static void op_amd_setup_ctrs(struct op_msrs const * const msrs) | ||
149 | { | ||
150 | unsigned int low, high; | ||
151 | int i; | ||
152 | |||
153 | /* clear all counters */ | ||
154 | for (i = 0 ; i < NUM_CONTROLS; ++i) { | ||
155 | if (unlikely(!CTRL_IS_RESERVED(msrs, i))) | ||
156 | continue; | ||
157 | CTRL_READ(low, high, msrs, i); | ||
158 | CTRL_CLEAR_LO(low); | ||
159 | CTRL_CLEAR_HI(high); | ||
160 | CTRL_WRITE(low, high, msrs, i); | ||
161 | } | ||
162 | |||
163 | /* avoid a false detection of ctr overflows in NMI handler */ | ||
164 | for (i = 0; i < NUM_COUNTERS; ++i) { | ||
165 | if (unlikely(!CTR_IS_RESERVED(msrs, i))) | ||
166 | continue; | ||
167 | CTR_WRITE(1, msrs, i); | ||
168 | } | ||
169 | |||
170 | /* enable active counters */ | ||
171 | for (i = 0; i < NUM_COUNTERS; ++i) { | ||
172 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { | ||
173 | reset_value[i] = counter_config[i].count; | ||
174 | |||
175 | CTR_WRITE(counter_config[i].count, msrs, i); | ||
176 | |||
177 | CTRL_READ(low, high, msrs, i); | ||
178 | CTRL_CLEAR_LO(low); | ||
179 | CTRL_CLEAR_HI(high); | ||
180 | CTRL_SET_ENABLE(low); | ||
181 | CTRL_SET_USR(low, counter_config[i].user); | ||
182 | CTRL_SET_KERN(low, counter_config[i].kernel); | ||
183 | CTRL_SET_UM(low, counter_config[i].unit_mask); | ||
184 | CTRL_SET_EVENT_LOW(low, counter_config[i].event); | ||
185 | CTRL_SET_EVENT_HIGH(high, counter_config[i].event); | ||
186 | CTRL_SET_HOST_ONLY(high, 0); | ||
187 | CTRL_SET_GUEST_ONLY(high, 0); | ||
188 | |||
189 | CTRL_WRITE(low, high, msrs, i); | ||
190 | } else { | ||
191 | reset_value[i] = 0; | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | #ifdef CONFIG_OPROFILE_IBS | ||
197 | |||
198 | static inline int | ||
199 | op_amd_handle_ibs(struct pt_regs * const regs, | ||
200 | struct op_msrs const * const msrs) | ||
201 | { | ||
202 | unsigned int low, high; | ||
203 | struct ibs_fetch_sample ibs_fetch; | ||
204 | struct ibs_op_sample ibs_op; | ||
205 | |||
206 | if (!ibs_allowed) | ||
207 | return 1; | ||
208 | |||
209 | if (ibs_config.fetch_enabled) { | ||
210 | rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); | ||
211 | if (high & IBS_FETCH_HIGH_VALID_BIT) { | ||
212 | ibs_fetch.ibs_fetch_ctl_high = high; | ||
213 | ibs_fetch.ibs_fetch_ctl_low = low; | ||
214 | rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high); | ||
215 | ibs_fetch.ibs_fetch_lin_addr_high = high; | ||
216 | ibs_fetch.ibs_fetch_lin_addr_low = low; | ||
217 | rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high); | ||
218 | ibs_fetch.ibs_fetch_phys_addr_high = high; | ||
219 | ibs_fetch.ibs_fetch_phys_addr_low = low; | ||
220 | |||
221 | oprofile_add_ibs_sample(regs, | ||
222 | (unsigned int *)&ibs_fetch, | ||
223 | IBS_FETCH_BEGIN); | ||
224 | |||
225 | /*reenable the IRQ */ | ||
226 | rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); | ||
227 | high &= ~IBS_FETCH_HIGH_VALID_BIT; | ||
228 | high |= IBS_FETCH_HIGH_ENABLE; | ||
229 | low &= IBS_FETCH_LOW_MAX_CNT_MASK; | ||
230 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | if (ibs_config.op_enabled) { | ||
235 | rdmsr(MSR_AMD64_IBSOPCTL, low, high); | ||
236 | if (low & IBS_OP_LOW_VALID_BIT) { | ||
237 | rdmsr(MSR_AMD64_IBSOPRIP, low, high); | ||
238 | ibs_op.ibs_op_rip_low = low; | ||
239 | ibs_op.ibs_op_rip_high = high; | ||
240 | rdmsr(MSR_AMD64_IBSOPDATA, low, high); | ||
241 | ibs_op.ibs_op_data1_low = low; | ||
242 | ibs_op.ibs_op_data1_high = high; | ||
243 | rdmsr(MSR_AMD64_IBSOPDATA2, low, high); | ||
244 | ibs_op.ibs_op_data2_low = low; | ||
245 | ibs_op.ibs_op_data2_high = high; | ||
246 | rdmsr(MSR_AMD64_IBSOPDATA3, low, high); | ||
247 | ibs_op.ibs_op_data3_low = low; | ||
248 | ibs_op.ibs_op_data3_high = high; | ||
249 | rdmsr(MSR_AMD64_IBSDCLINAD, low, high); | ||
250 | ibs_op.ibs_dc_linear_low = low; | ||
251 | ibs_op.ibs_dc_linear_high = high; | ||
252 | rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high); | ||
253 | ibs_op.ibs_dc_phys_low = low; | ||
254 | ibs_op.ibs_dc_phys_high = high; | ||
255 | |||
256 | /* reenable the IRQ */ | ||
257 | oprofile_add_ibs_sample(regs, | ||
258 | (unsigned int *)&ibs_op, | ||
259 | IBS_OP_BEGIN); | ||
260 | rdmsr(MSR_AMD64_IBSOPCTL, low, high); | ||
261 | high = 0; | ||
262 | low &= ~IBS_OP_LOW_VALID_BIT; | ||
263 | low |= IBS_OP_LOW_ENABLE; | ||
264 | wrmsr(MSR_AMD64_IBSOPCTL, low, high); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | return 1; | ||
269 | } | ||
270 | |||
271 | #endif | ||
272 | |||
273 | static int op_amd_check_ctrs(struct pt_regs * const regs, | ||
274 | struct op_msrs const * const msrs) | ||
275 | { | ||
276 | unsigned int low, high; | ||
277 | int i; | ||
278 | |||
279 | for (i = 0 ; i < NUM_COUNTERS; ++i) { | ||
280 | if (!reset_value[i]) | ||
281 | continue; | ||
282 | CTR_READ(low, high, msrs, i); | ||
283 | if (CTR_OVERFLOWED(low)) { | ||
284 | oprofile_add_sample(regs, i); | ||
285 | CTR_WRITE(reset_value[i], msrs, i); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | #ifdef CONFIG_OPROFILE_IBS | ||
290 | op_amd_handle_ibs(regs, msrs); | ||
291 | #endif | ||
292 | |||
293 | /* See op_model_ppro.c */ | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | static void op_amd_start(struct op_msrs const * const msrs) | ||
298 | { | ||
299 | unsigned int low, high; | ||
300 | int i; | ||
301 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
302 | if (reset_value[i]) { | ||
303 | CTRL_READ(low, high, msrs, i); | ||
304 | CTRL_SET_ACTIVE(low); | ||
305 | CTRL_WRITE(low, high, msrs, i); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | #ifdef CONFIG_OPROFILE_IBS | ||
310 | if (ibs_allowed && ibs_config.fetch_enabled) { | ||
311 | low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; | ||
312 | high = IBS_FETCH_HIGH_ENABLE; | ||
313 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); | ||
314 | } | ||
315 | |||
316 | if (ibs_allowed && ibs_config.op_enabled) { | ||
317 | low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + IBS_OP_LOW_ENABLE; | ||
318 | high = 0; | ||
319 | wrmsr(MSR_AMD64_IBSOPCTL, low, high); | ||
320 | } | ||
321 | #endif | ||
322 | } | ||
323 | |||
324 | |||
325 | static void op_amd_stop(struct op_msrs const * const msrs) | ||
326 | { | ||
327 | unsigned int low, high; | ||
328 | int i; | ||
329 | |||
330 | /* Subtle: stop on all counters to avoid race with | ||
331 | * setting our pm callback */ | ||
332 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
333 | if (!reset_value[i]) | ||
334 | continue; | ||
335 | CTRL_READ(low, high, msrs, i); | ||
336 | CTRL_SET_INACTIVE(low); | ||
337 | CTRL_WRITE(low, high, msrs, i); | ||
338 | } | ||
339 | |||
340 | #ifdef CONFIG_OPROFILE_IBS | ||
341 | if (ibs_allowed && ibs_config.fetch_enabled) { | ||
342 | low = 0; /* clear max count and enable */ | ||
343 | high = 0; | ||
344 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); | ||
345 | } | ||
346 | |||
347 | if (ibs_allowed && ibs_config.op_enabled) { | ||
348 | low = 0; /* clear max count and enable */ | ||
349 | high = 0; | ||
350 | wrmsr(MSR_AMD64_IBSOPCTL, low, high); | ||
351 | } | ||
352 | #endif | ||
353 | } | ||
354 | |||
355 | static void op_amd_shutdown(struct op_msrs const * const msrs) | ||
356 | { | ||
357 | int i; | ||
358 | |||
359 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
360 | if (CTR_IS_RESERVED(msrs, i)) | ||
361 | release_perfctr_nmi(MSR_K7_PERFCTR0 + i); | ||
362 | } | ||
363 | for (i = 0 ; i < NUM_CONTROLS ; ++i) { | ||
364 | if (CTRL_IS_RESERVED(msrs, i)) | ||
365 | release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | #ifndef CONFIG_OPROFILE_IBS | ||
370 | |||
371 | /* no IBS support */ | ||
372 | |||
373 | static int op_amd_init(struct oprofile_operations *ops) | ||
374 | { | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static void op_amd_exit(void) {} | ||
379 | |||
380 | #else | ||
381 | |||
382 | static u8 ibs_eilvt_off; | ||
383 | |||
384 | static inline void apic_init_ibs_nmi_per_cpu(void *arg) | ||
385 | { | ||
386 | ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); | ||
387 | } | ||
388 | |||
389 | static inline void apic_clear_ibs_nmi_per_cpu(void *arg) | ||
390 | { | ||
391 | setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); | ||
392 | } | ||
393 | |||
394 | static int pfm_amd64_setup_eilvt(void) | ||
395 | { | ||
396 | #define IBSCTL_LVTOFFSETVAL (1 << 8) | ||
397 | #define IBSCTL 0x1cc | ||
398 | struct pci_dev *cpu_cfg; | ||
399 | int nodes; | ||
400 | u32 value = 0; | ||
401 | |||
402 | /* per CPU setup */ | ||
403 | on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1); | ||
404 | |||
405 | nodes = 0; | ||
406 | cpu_cfg = NULL; | ||
407 | do { | ||
408 | cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD, | ||
409 | PCI_DEVICE_ID_AMD_10H_NB_MISC, | ||
410 | cpu_cfg); | ||
411 | if (!cpu_cfg) | ||
412 | break; | ||
413 | ++nodes; | ||
414 | pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off | ||
415 | | IBSCTL_LVTOFFSETVAL); | ||
416 | pci_read_config_dword(cpu_cfg, IBSCTL, &value); | ||
417 | if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { | ||
418 | printk(KERN_DEBUG "Failed to setup IBS LVT offset, " | ||
419 | "IBSCTL = 0x%08x", value); | ||
420 | return 1; | ||
421 | } | ||
422 | } while (1); | ||
423 | |||
424 | if (!nodes) { | ||
425 | printk(KERN_DEBUG "No CPU node configured for IBS"); | ||
426 | return 1; | ||
427 | } | ||
428 | |||
429 | #ifdef CONFIG_NUMA | ||
430 | /* Sanity check */ | ||
431 | /* Works only for 64bit with proper numa implementation. */ | ||
432 | if (nodes != num_possible_nodes()) { | ||
433 | printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, " | ||
434 | "found: %d, expected %d", | ||
435 | nodes, num_possible_nodes()); | ||
436 | return 1; | ||
437 | } | ||
438 | #endif | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * initialize the APIC for the IBS interrupts | ||
444 | * if available (AMD Family10h rev B0 and later) | ||
445 | */ | ||
446 | static void setup_ibs(void) | ||
447 | { | ||
448 | ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); | ||
449 | |||
450 | if (!ibs_allowed) | ||
451 | return; | ||
452 | |||
453 | if (pfm_amd64_setup_eilvt()) { | ||
454 | ibs_allowed = 0; | ||
455 | return; | ||
456 | } | ||
457 | |||
458 | printk(KERN_INFO "oprofile: AMD IBS detected\n"); | ||
459 | } | ||
460 | |||
461 | |||
462 | /* | ||
463 | * unitialize the APIC for the IBS interrupts if needed on AMD Family10h | ||
464 | * rev B0 and later */ | ||
465 | static void clear_ibs_nmi(void) | ||
466 | { | ||
467 | if (ibs_allowed) | ||
468 | on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); | ||
469 | } | ||
470 | |||
471 | static int (*create_arch_files)(struct super_block * sb, struct dentry * root); | ||
472 | |||
473 | static int setup_ibs_files(struct super_block * sb, struct dentry * root) | ||
474 | { | ||
475 | char buf[12]; | ||
476 | struct dentry *dir; | ||
477 | int ret = 0; | ||
478 | |||
479 | /* architecture specific files */ | ||
480 | if (create_arch_files) | ||
481 | ret = create_arch_files(sb, root); | ||
482 | |||
483 | if (ret) | ||
484 | return ret; | ||
485 | |||
486 | if (!ibs_allowed) | ||
487 | return ret; | ||
488 | |||
489 | /* model specific files */ | ||
490 | |||
491 | /* setup some reasonable defaults */ | ||
492 | ibs_config.max_cnt_fetch = 250000; | ||
493 | ibs_config.fetch_enabled = 0; | ||
494 | ibs_config.max_cnt_op = 250000; | ||
495 | ibs_config.op_enabled = 0; | ||
496 | ibs_config.dispatched_ops = 1; | ||
497 | snprintf(buf, sizeof(buf), "ibs_fetch"); | ||
498 | dir = oprofilefs_mkdir(sb, root, buf); | ||
499 | oprofilefs_create_ulong(sb, dir, "rand_enable", | ||
500 | &ibs_config.rand_en); | ||
501 | oprofilefs_create_ulong(sb, dir, "enable", | ||
502 | &ibs_config.fetch_enabled); | ||
503 | oprofilefs_create_ulong(sb, dir, "max_count", | ||
504 | &ibs_config.max_cnt_fetch); | ||
505 | snprintf(buf, sizeof(buf), "ibs_uops"); | ||
506 | dir = oprofilefs_mkdir(sb, root, buf); | ||
507 | oprofilefs_create_ulong(sb, dir, "enable", | ||
508 | &ibs_config.op_enabled); | ||
509 | oprofilefs_create_ulong(sb, dir, "max_count", | ||
510 | &ibs_config.max_cnt_op); | ||
511 | oprofilefs_create_ulong(sb, dir, "dispatched_ops", | ||
512 | &ibs_config.dispatched_ops); | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int op_amd_init(struct oprofile_operations *ops) | ||
518 | { | ||
519 | setup_ibs(); | ||
520 | create_arch_files = ops->create_files; | ||
521 | ops->create_files = setup_ibs_files; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static void op_amd_exit(void) | ||
526 | { | ||
527 | clear_ibs_nmi(); | ||
528 | } | ||
529 | |||
530 | #endif | ||
531 | |||
532 | struct op_x86_model_spec const op_amd_spec = { | ||
533 | .init = op_amd_init, | ||
534 | .exit = op_amd_exit, | ||
535 | .num_counters = NUM_COUNTERS, | ||
536 | .num_controls = NUM_CONTROLS, | ||
537 | .fill_in_addresses = &op_amd_fill_in_addresses, | ||
538 | .setup_ctrs = &op_amd_setup_ctrs, | ||
539 | .check_ctrs = &op_amd_check_ctrs, | ||
540 | .start = &op_amd_start, | ||
541 | .stop = &op_amd_stop, | ||
542 | .shutdown = &op_amd_shutdown | ||
543 | }; | ||
diff --git a/arch/x86/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c deleted file mode 100644 index 3d534879a9dc..000000000000 --- a/arch/x86/oprofile/op_model_athlon.c +++ /dev/null | |||
@@ -1,190 +0,0 @@ | |||
1 | /* | ||
2 | * @file op_model_athlon.h | ||
3 | * athlon / K7 / K8 / Family 10h model-specific MSR operations | ||
4 | * | ||
5 | * @remark Copyright 2002 OProfile authors | ||
6 | * @remark Read the file COPYING | ||
7 | * | ||
8 | * @author John Levon | ||
9 | * @author Philippe Elie | ||
10 | * @author Graydon Hoare | ||
11 | */ | ||
12 | |||
13 | #include <linux/oprofile.h> | ||
14 | #include <asm/ptrace.h> | ||
15 | #include <asm/msr.h> | ||
16 | #include <asm/nmi.h> | ||
17 | |||
18 | #include "op_x86_model.h" | ||
19 | #include "op_counter.h" | ||
20 | |||
21 | #define NUM_COUNTERS 4 | ||
22 | #define NUM_CONTROLS 4 | ||
23 | |||
24 | #define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) | ||
25 | #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0) | ||
26 | #define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0) | ||
27 | #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) | ||
28 | |||
29 | #define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) | ||
30 | #define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) | ||
31 | #define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) | ||
32 | #define CTRL_SET_ACTIVE(n) (n |= (1<<22)) | ||
33 | #define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) | ||
34 | #define CTRL_CLEAR_LO(x) (x &= (1<<21)) | ||
35 | #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) | ||
36 | #define CTRL_SET_ENABLE(val) (val |= 1<<20) | ||
37 | #define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) | ||
38 | #define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) | ||
39 | #define CTRL_SET_UM(val, m) (val |= (m << 8)) | ||
40 | #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) | ||
41 | #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) | ||
42 | #define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9)) | ||
43 | #define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8)) | ||
44 | |||
45 | static unsigned long reset_value[NUM_COUNTERS]; | ||
46 | |||
47 | static void athlon_fill_in_addresses(struct op_msrs * const msrs) | ||
48 | { | ||
49 | int i; | ||
50 | |||
51 | for (i = 0; i < NUM_COUNTERS; i++) { | ||
52 | if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) | ||
53 | msrs->counters[i].addr = MSR_K7_PERFCTR0 + i; | ||
54 | else | ||
55 | msrs->counters[i].addr = 0; | ||
56 | } | ||
57 | |||
58 | for (i = 0; i < NUM_CONTROLS; i++) { | ||
59 | if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i)) | ||
60 | msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i; | ||
61 | else | ||
62 | msrs->controls[i].addr = 0; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | |||
67 | static void athlon_setup_ctrs(struct op_msrs const * const msrs) | ||
68 | { | ||
69 | unsigned int low, high; | ||
70 | int i; | ||
71 | |||
72 | /* clear all counters */ | ||
73 | for (i = 0 ; i < NUM_CONTROLS; ++i) { | ||
74 | if (unlikely(!CTRL_IS_RESERVED(msrs, i))) | ||
75 | continue; | ||
76 | CTRL_READ(low, high, msrs, i); | ||
77 | CTRL_CLEAR_LO(low); | ||
78 | CTRL_CLEAR_HI(high); | ||
79 | CTRL_WRITE(low, high, msrs, i); | ||
80 | } | ||
81 | |||
82 | /* avoid a false detection of ctr overflows in NMI handler */ | ||
83 | for (i = 0; i < NUM_COUNTERS; ++i) { | ||
84 | if (unlikely(!CTR_IS_RESERVED(msrs, i))) | ||
85 | continue; | ||
86 | CTR_WRITE(1, msrs, i); | ||
87 | } | ||
88 | |||
89 | /* enable active counters */ | ||
90 | for (i = 0; i < NUM_COUNTERS; ++i) { | ||
91 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { | ||
92 | reset_value[i] = counter_config[i].count; | ||
93 | |||
94 | CTR_WRITE(counter_config[i].count, msrs, i); | ||
95 | |||
96 | CTRL_READ(low, high, msrs, i); | ||
97 | CTRL_CLEAR_LO(low); | ||
98 | CTRL_CLEAR_HI(high); | ||
99 | CTRL_SET_ENABLE(low); | ||
100 | CTRL_SET_USR(low, counter_config[i].user); | ||
101 | CTRL_SET_KERN(low, counter_config[i].kernel); | ||
102 | CTRL_SET_UM(low, counter_config[i].unit_mask); | ||
103 | CTRL_SET_EVENT_LOW(low, counter_config[i].event); | ||
104 | CTRL_SET_EVENT_HIGH(high, counter_config[i].event); | ||
105 | CTRL_SET_HOST_ONLY(high, 0); | ||
106 | CTRL_SET_GUEST_ONLY(high, 0); | ||
107 | |||
108 | CTRL_WRITE(low, high, msrs, i); | ||
109 | } else { | ||
110 | reset_value[i] = 0; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | |||
116 | static int athlon_check_ctrs(struct pt_regs * const regs, | ||
117 | struct op_msrs const * const msrs) | ||
118 | { | ||
119 | unsigned int low, high; | ||
120 | int i; | ||
121 | |||
122 | for (i = 0 ; i < NUM_COUNTERS; ++i) { | ||
123 | if (!reset_value[i]) | ||
124 | continue; | ||
125 | CTR_READ(low, high, msrs, i); | ||
126 | if (CTR_OVERFLOWED(low)) { | ||
127 | oprofile_add_sample(regs, i); | ||
128 | CTR_WRITE(reset_value[i], msrs, i); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* See op_model_ppro.c */ | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | |||
137 | static void athlon_start(struct op_msrs const * const msrs) | ||
138 | { | ||
139 | unsigned int low, high; | ||
140 | int i; | ||
141 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
142 | if (reset_value[i]) { | ||
143 | CTRL_READ(low, high, msrs, i); | ||
144 | CTRL_SET_ACTIVE(low); | ||
145 | CTRL_WRITE(low, high, msrs, i); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | |||
151 | static void athlon_stop(struct op_msrs const * const msrs) | ||
152 | { | ||
153 | unsigned int low, high; | ||
154 | int i; | ||
155 | |||
156 | /* Subtle: stop on all counters to avoid race with | ||
157 | * setting our pm callback */ | ||
158 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
159 | if (!reset_value[i]) | ||
160 | continue; | ||
161 | CTRL_READ(low, high, msrs, i); | ||
162 | CTRL_SET_INACTIVE(low); | ||
163 | CTRL_WRITE(low, high, msrs, i); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static void athlon_shutdown(struct op_msrs const * const msrs) | ||
168 | { | ||
169 | int i; | ||
170 | |||
171 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
172 | if (CTR_IS_RESERVED(msrs, i)) | ||
173 | release_perfctr_nmi(MSR_K7_PERFCTR0 + i); | ||
174 | } | ||
175 | for (i = 0 ; i < NUM_CONTROLS ; ++i) { | ||
176 | if (CTRL_IS_RESERVED(msrs, i)) | ||
177 | release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | struct op_x86_model_spec const op_athlon_spec = { | ||
182 | .num_counters = NUM_COUNTERS, | ||
183 | .num_controls = NUM_CONTROLS, | ||
184 | .fill_in_addresses = &athlon_fill_in_addresses, | ||
185 | .setup_ctrs = &athlon_setup_ctrs, | ||
186 | .check_ctrs = &athlon_check_ctrs, | ||
187 | .start = &athlon_start, | ||
188 | .stop = &athlon_stop, | ||
189 | .shutdown = &athlon_shutdown | ||
190 | }; | ||
diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 45b605fa71d0..05a0261ba0c3 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h | |||
@@ -32,6 +32,8 @@ struct pt_regs; | |||
32 | * various x86 CPU models' perfctr support. | 32 | * various x86 CPU models' perfctr support. |
33 | */ | 33 | */ |
34 | struct op_x86_model_spec { | 34 | struct op_x86_model_spec { |
35 | int (*init)(struct oprofile_operations *ops); | ||
36 | void (*exit)(void); | ||
35 | unsigned int const num_counters; | 37 | unsigned int const num_counters; |
36 | unsigned int const num_controls; | 38 | unsigned int const num_controls; |
37 | void (*fill_in_addresses)(struct op_msrs * const msrs); | 39 | void (*fill_in_addresses)(struct op_msrs * const msrs); |
@@ -46,6 +48,6 @@ struct op_x86_model_spec { | |||
46 | extern struct op_x86_model_spec const op_ppro_spec; | 48 | extern struct op_x86_model_spec const op_ppro_spec; |
47 | extern struct op_x86_model_spec const op_p4_spec; | 49 | extern struct op_x86_model_spec const op_p4_spec; |
48 | extern struct op_x86_model_spec const op_p4_ht2_spec; | 50 | extern struct op_x86_model_spec const op_p4_ht2_spec; |
49 | extern struct op_x86_model_spec const op_athlon_spec; | 51 | extern struct op_x86_model_spec const op_amd_spec; |
50 | 52 | ||
51 | #endif /* OP_X86_MODEL_H */ | 53 | #endif /* OP_X86_MODEL_H */ |
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 4bdaa590375d..3c27a809393b 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c | |||
@@ -511,3 +511,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size); | |||
511 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size); | 511 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size); |
512 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size); | 512 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size); |
513 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size); | 513 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size); |
514 | |||
515 | /* | ||
516 | * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from | ||
517 | * confusing the PCI engine: | ||
518 | */ | ||
519 | static void sb600_disable_hpet_bar(struct pci_dev *dev) | ||
520 | { | ||
521 | u8 val; | ||
522 | |||
523 | /* | ||
524 | * The SB600 and SB700 both share the same device | ||
525 | * ID, but the PM register 0x55 does something different | ||
526 | * for the SB700, so make sure we are dealing with the | ||
527 | * SB600 before touching the bit: | ||
528 | */ | ||
529 | |||
530 | pci_read_config_byte(dev, 0x08, &val); | ||
531 | |||
532 | if (val < 0x2F) { | ||
533 | outb(0x55, 0xCD6); | ||
534 | val = inb(0xCD7); | ||
535 | |||
536 | /* Set bit 7 in PM register 0x55 */ | ||
537 | outb(0x55, 0xCD6); | ||
538 | outb(val | 0x80, 0xCD7); | ||
539 | } | ||
540 | } | ||
541 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar); | ||
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 8dfcf77cb717..4426bb552bd9 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, | |||
484 | return -EUNATCH; | 484 | return -EUNATCH; |
485 | 485 | ||
486 | default: | 486 | default: |
487 | err = n_tty_ioctl(tty, file, cmd, arg); | 487 | err = n_tty_ioctl_helper(tty, file, cmd, arg); |
488 | break; | 488 | break; |
489 | }; | 489 | }; |
490 | 490 | ||
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index caff85149b9d..700ff9679457 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -350,7 +350,7 @@ config STALDRV | |||
350 | 350 | ||
351 | config STALLION | 351 | config STALLION |
352 | tristate "Stallion EasyIO or EC8/32 support" | 352 | tristate "Stallion EasyIO or EC8/32 support" |
353 | depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) | 353 | depends on STALDRV && (ISA || EISA || PCI) |
354 | help | 354 | help |
355 | If you have an EasyIO or EasyConnection 8/32 multiport Stallion | 355 | If you have an EasyIO or EasyConnection 8/32 multiport Stallion |
356 | card, then this is for you; say Y. Make sure to read | 356 | card, then this is for you; say Y. Make sure to read |
@@ -361,7 +361,7 @@ config STALLION | |||
361 | 361 | ||
362 | config ISTALLION | 362 | config ISTALLION |
363 | tristate "Stallion EC8/64, ONboard, Brumby support" | 363 | tristate "Stallion EC8/64, ONboard, Brumby support" |
364 | depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) | 364 | depends on STALDRV && (ISA || EISA || PCI) |
365 | help | 365 | help |
366 | If you have an EasyConnection 8/64, ONboard, Brumby or Stallion | 366 | If you have an EasyConnection 8/64, ONboard, Brumby or Stallion |
367 | serial multiport card, say Y here. Make sure to read | 367 | serial multiport card, say Y here. Make sure to read |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 6850f6da7576..1a4247dccac4 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -7,7 +7,7 @@ | |||
7 | # | 7 | # |
8 | FONTMAPFILE = cp437.uni | 8 | FONTMAPFILE = cp437.uni |
9 | 9 | ||
10 | obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o | 10 | obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o |
11 | 11 | ||
12 | obj-$(CONFIG_LEGACY_PTYS) += pty.o | 12 | obj-$(CONFIG_LEGACY_PTYS) += pty.o |
13 | obj-$(CONFIG_UNIX98_PTYS) += pty.o | 13 | obj-$(CONFIG_UNIX98_PTYS) += pty.o |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 6e763e3f5a81..98821f97583c 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
@@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) | |||
837 | struct async_struct *info; | 837 | struct async_struct *info; |
838 | unsigned long flags; | 838 | unsigned long flags; |
839 | 839 | ||
840 | if (!tty) | ||
841 | return 0; | ||
842 | |||
843 | info = tty->driver_data; | 840 | info = tty->driver_data; |
844 | 841 | ||
845 | if (serial_paranoia_check(info, tty->name, "rs_put_char")) | 842 | if (serial_paranoia_check(info, tty->name, "rs_put_char")) |
@@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count | |||
892 | struct async_struct *info; | 889 | struct async_struct *info; |
893 | unsigned long flags; | 890 | unsigned long flags; |
894 | 891 | ||
895 | if (!tty) | ||
896 | return 0; | ||
897 | |||
898 | info = tty->driver_data; | 892 | info = tty->driver_data; |
899 | 893 | ||
900 | if (serial_paranoia_check(info, tty->name, "rs_write")) | 894 | if (serial_paranoia_check(info, tty->name, "rs_write")) |
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 31d08b641f5b..b899d9182c7d 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c | |||
@@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un | |||
712 | 712 | ||
713 | IndexCard = adgl->num_card-1; | 713 | IndexCard = adgl->num_card-1; |
714 | 714 | ||
715 | if(cmd != 0 && cmd != 6 && | 715 | if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { |
716 | ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { | ||
717 | static int warncount = 10; | 716 | static int warncount = 10; |
718 | if (warncount) { | 717 | if (warncount) { |
719 | printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); | 718 | printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); |
@@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un | |||
832 | } | 831 | } |
833 | break; | 832 | break; |
834 | default: | 833 | default: |
835 | printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ; | 834 | ret = -ENOTTY; |
836 | ret = -EINVAL; | ||
837 | break; | 835 | break; |
838 | } | 836 | } |
839 | Dummy = readb(apbs[IndexCard].RamIO + VERS); | 837 | Dummy = readb(apbs[IndexCard].RamIO + VERS); |
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index fe6d774fe2e4..5e5b1dc1a0a7 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -4993,12 +4993,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, | |||
4993 | device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { | 4993 | device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { |
4994 | card_name = "Cyclom-Y"; | 4994 | card_name = "Cyclom-Y"; |
4995 | 4995 | ||
4996 | addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); | 4996 | addr0 = ioremap_nocache(pci_resource_start(pdev, 0), |
4997 | CyPCI_Yctl); | ||
4997 | if (addr0 == NULL) { | 4998 | if (addr0 == NULL) { |
4998 | dev_err(&pdev->dev, "can't remap ctl region\n"); | 4999 | dev_err(&pdev->dev, "can't remap ctl region\n"); |
4999 | goto err_reg; | 5000 | goto err_reg; |
5000 | } | 5001 | } |
5001 | addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); | 5002 | addr2 = ioremap_nocache(pci_resource_start(pdev, 2), |
5003 | CyPCI_Ywin); | ||
5002 | if (addr2 == NULL) { | 5004 | if (addr2 == NULL) { |
5003 | dev_err(&pdev->dev, "can't remap base region\n"); | 5005 | dev_err(&pdev->dev, "can't remap base region\n"); |
5004 | goto err_unmap; | 5006 | goto err_unmap; |
@@ -5013,7 +5015,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, | |||
5013 | } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { | 5015 | } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { |
5014 | struct RUNTIME_9060 __iomem *ctl_addr; | 5016 | struct RUNTIME_9060 __iomem *ctl_addr; |
5015 | 5017 | ||
5016 | ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); | 5018 | ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0), |
5019 | CyPCI_Zctl); | ||
5017 | if (addr0 == NULL) { | 5020 | if (addr0 == NULL) { |
5018 | dev_err(&pdev->dev, "can't remap ctl region\n"); | 5021 | dev_err(&pdev->dev, "can't remap ctl region\n"); |
5019 | goto err_reg; | 5022 | goto err_reg; |
@@ -5026,8 +5029,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, | |||
5026 | 5029 | ||
5027 | mailbox = (u32)readl(&ctl_addr->mail_box_0); | 5030 | mailbox = (u32)readl(&ctl_addr->mail_box_0); |
5028 | 5031 | ||
5029 | addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ? | 5032 | addr2 = ioremap_nocache(pci_resource_start(pdev, 2), |
5030 | CyPCI_Ze_win : CyPCI_Zwin); | 5033 | mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); |
5031 | if (addr2 == NULL) { | 5034 | if (addr2 == NULL) { |
5032 | dev_err(&pdev->dev, "can't remap base region\n"); | 5035 | dev_err(&pdev->dev, "can't remap base region\n"); |
5033 | goto err_unmap; | 5036 | goto err_unmap; |
@@ -5159,9 +5162,9 @@ err_null: | |||
5159 | cy_card[card_no].base_addr = NULL; | 5162 | cy_card[card_no].base_addr = NULL; |
5160 | free_irq(irq, &cy_card[card_no]); | 5163 | free_irq(irq, &cy_card[card_no]); |
5161 | err_unmap: | 5164 | err_unmap: |
5162 | pci_iounmap(pdev, addr0); | 5165 | iounmap(addr0); |
5163 | if (addr2) | 5166 | if (addr2) |
5164 | pci_iounmap(pdev, addr2); | 5167 | iounmap(addr2); |
5165 | err_reg: | 5168 | err_reg: |
5166 | pci_release_regions(pdev); | 5169 | pci_release_regions(pdev); |
5167 | err_dis: | 5170 | err_dis: |
@@ -5186,9 +5189,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev) | |||
5186 | cy_writew(cinfo->ctl_addr + 0x68, | 5189 | cy_writew(cinfo->ctl_addr + 0x68, |
5187 | readw(cinfo->ctl_addr + 0x68) & ~0x0900); | 5190 | readw(cinfo->ctl_addr + 0x68) & ~0x0900); |
5188 | 5191 | ||
5189 | pci_iounmap(pdev, cinfo->base_addr); | 5192 | iounmap(cinfo->base_addr); |
5190 | if (cinfo->ctl_addr) | 5193 | if (cinfo->ctl_addr) |
5191 | pci_iounmap(pdev, cinfo->ctl_addr); | 5194 | iounmap(cinfo->ctl_addr); |
5192 | if (cinfo->irq | 5195 | if (cinfo->irq |
5193 | #ifndef CONFIG_CYZ_INTR | 5196 | #ifndef CONFIG_CYZ_INTR |
5194 | && !IS_CYC_Z(*cinfo) | 5197 | && !IS_CYC_Z(*cinfo) |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 456e4ede049f..4998b2761e8f 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -1376,6 +1376,7 @@ static void post_fep_init(unsigned int crd) | |||
1376 | unsigned long flags; | 1376 | unsigned long flags; |
1377 | u16 tseg, rseg; | 1377 | u16 tseg, rseg; |
1378 | 1378 | ||
1379 | tty_port_init(&ch->port); | ||
1379 | ch->brdchan = bc; | 1380 | ch->brdchan = bc; |
1380 | ch->mailbox = gd; | 1381 | ch->mailbox = gd; |
1381 | INIT_WORK(&ch->tqueue, do_softint); | 1382 | INIT_WORK(&ch->tqueue, do_softint); |
@@ -1510,10 +1511,6 @@ static void post_fep_init(unsigned int crd) | |||
1510 | ch->fepstopca = 0; | 1511 | ch->fepstopca = 0; |
1511 | 1512 | ||
1512 | ch->close_delay = 50; | 1513 | ch->close_delay = 50; |
1513 | ch->port.count = 0; | ||
1514 | ch->port.blocked_open = 0; | ||
1515 | init_waitqueue_head(&ch->port.open_wait); | ||
1516 | init_waitqueue_head(&ch->port.close_wait); | ||
1517 | 1514 | ||
1518 | spin_unlock_irqrestore(&epca_lock, flags); | 1515 | spin_unlock_irqrestore(&epca_lock, flags); |
1519 | } | 1516 | } |
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 19d3afb0e50c..c6090f84a2e4 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c | |||
@@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch) | |||
54 | 54 | ||
55 | func_enter (); | 55 | func_enter (); |
56 | 56 | ||
57 | if (!tty) return 0; | ||
58 | |||
59 | port = tty->driver_data; | 57 | port = tty->driver_data; |
60 | 58 | ||
61 | if (!port) return 0; | 59 | if (!port) return 0; |
@@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty, | |||
97 | 95 | ||
98 | func_enter (); | 96 | func_enter (); |
99 | 97 | ||
100 | if (!tty) return 0; | ||
101 | |||
102 | port = tty->driver_data; | 98 | port = tty->driver_data; |
103 | 99 | ||
104 | if (!port) return 0; | 100 | if (!port) return 0; |
@@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty) | |||
185 | struct gs_port *port; | 181 | struct gs_port *port; |
186 | func_enter (); | 182 | func_enter (); |
187 | 183 | ||
188 | if (!tty) return 0; | ||
189 | port = tty->driver_data; | 184 | port = tty->driver_data; |
190 | 185 | ||
191 | if (!port->rd) return 0; | 186 | if (!port->rd) return 0; |
@@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty) | |||
274 | 269 | ||
275 | func_enter (); | 270 | func_enter (); |
276 | 271 | ||
277 | if (!tty) return; | ||
278 | |||
279 | port = tty->driver_data; | 272 | port = tty->driver_data; |
280 | 273 | ||
281 | if (!port) return; | 274 | if (!port) return; |
@@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty) | |||
296 | 289 | ||
297 | func_enter (); | 290 | func_enter (); |
298 | 291 | ||
299 | if (!tty) return; | ||
300 | |||
301 | port = tty->driver_data; | 292 | port = tty->driver_data; |
302 | 293 | ||
303 | if (!port) return; | 294 | if (!port) return; |
@@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty) | |||
321 | 312 | ||
322 | func_enter (); | 313 | func_enter (); |
323 | 314 | ||
324 | if (!tty) return; | ||
325 | |||
326 | port = tty->driver_data; | 315 | port = tty->driver_data; |
327 | 316 | ||
328 | if (!port) return; | 317 | if (!port) return; |
@@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty) | |||
341 | { | 330 | { |
342 | struct gs_port *port; | 331 | struct gs_port *port; |
343 | 332 | ||
344 | if (!tty) return; | ||
345 | |||
346 | port = tty->driver_data; | 333 | port = tty->driver_data; |
347 | 334 | ||
348 | if (!port) return; | 335 | if (!port) return; |
@@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty) | |||
393 | 380 | ||
394 | func_enter (); | 381 | func_enter (); |
395 | 382 | ||
396 | if (!tty) return; | ||
397 | |||
398 | port = tty->driver_data; | 383 | port = tty->driver_data; |
399 | tty = port->port.tty; | 384 | tty = port->port.tty; |
400 | if (!tty) | 385 | if (!tty) |
@@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp) | |||
426 | 411 | ||
427 | tty = port->port.tty; | 412 | tty = port->port.tty; |
428 | 413 | ||
429 | if (!tty) return 0; | ||
430 | |||
431 | gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); | 414 | gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); |
432 | /* | 415 | /* |
433 | * If the device is in the middle of being closed, then block | 416 | * If the device is in the middle of being closed, then block |
@@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp) | |||
523 | 506 | ||
524 | func_enter (); | 507 | func_enter (); |
525 | 508 | ||
526 | if (!tty) return; | ||
527 | |||
528 | port = (struct gs_port *) tty->driver_data; | 509 | port = (struct gs_port *) tty->driver_data; |
529 | 510 | ||
530 | if (!port) return; | 511 | if (!port) return; |
@@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty, | |||
621 | 602 | ||
622 | func_enter(); | 603 | func_enter(); |
623 | 604 | ||
624 | if (!tty) return; | ||
625 | |||
626 | port = tty->driver_data; | 605 | port = tty->driver_data; |
627 | 606 | ||
628 | if (!port) return; | 607 | if (!port) return; |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index b3f5dbc6d880..f3cfb4c76125 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -53,6 +53,11 @@ | |||
53 | 53 | ||
54 | #define HPET_RANGE_SIZE 1024 /* from HPET spec */ | 54 | #define HPET_RANGE_SIZE 1024 /* from HPET spec */ |
55 | 55 | ||
56 | |||
57 | /* WARNING -- don't get confused. These macros are never used | ||
58 | * to write the (single) counter, and rarely to read it. | ||
59 | * They're badly named; to fix, someday. | ||
60 | */ | ||
56 | #if BITS_PER_LONG == 64 | 61 | #if BITS_PER_LONG == 64 |
57 | #define write_counter(V, MC) writeq(V, MC) | 62 | #define write_counter(V, MC) writeq(V, MC) |
58 | #define read_counter(MC) readq(MC) | 63 | #define read_counter(MC) readq(MC) |
@@ -77,7 +82,7 @@ static struct clocksource clocksource_hpet = { | |||
77 | .rating = 250, | 82 | .rating = 250, |
78 | .read = read_hpet, | 83 | .read = read_hpet, |
79 | .mask = CLOCKSOURCE_MASK(64), | 84 | .mask = CLOCKSOURCE_MASK(64), |
80 | .mult = 0, /*to be caluclated*/ | 85 | .mult = 0, /* to be calculated */ |
81 | .shift = 10, | 86 | .shift = 10, |
82 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 87 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
83 | }; | 88 | }; |
@@ -86,8 +91,6 @@ static struct clocksource *hpet_clocksource; | |||
86 | 91 | ||
87 | /* A lock for concurrent access by app and isr hpet activity. */ | 92 | /* A lock for concurrent access by app and isr hpet activity. */ |
88 | static DEFINE_SPINLOCK(hpet_lock); | 93 | static DEFINE_SPINLOCK(hpet_lock); |
89 | /* A lock for concurrent intermodule access to hpet and isr hpet activity. */ | ||
90 | static DEFINE_SPINLOCK(hpet_task_lock); | ||
91 | 94 | ||
92 | #define HPET_DEV_NAME (7) | 95 | #define HPET_DEV_NAME (7) |
93 | 96 | ||
@@ -99,7 +102,6 @@ struct hpet_dev { | |||
99 | unsigned long hd_irqdata; | 102 | unsigned long hd_irqdata; |
100 | wait_queue_head_t hd_waitqueue; | 103 | wait_queue_head_t hd_waitqueue; |
101 | struct fasync_struct *hd_async_queue; | 104 | struct fasync_struct *hd_async_queue; |
102 | struct hpet_task *hd_task; | ||
103 | unsigned int hd_flags; | 105 | unsigned int hd_flags; |
104 | unsigned int hd_irq; | 106 | unsigned int hd_irq; |
105 | unsigned int hd_hdwirq; | 107 | unsigned int hd_hdwirq; |
@@ -173,11 +175,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data) | |||
173 | writel(isr, &devp->hd_hpet->hpet_isr); | 175 | writel(isr, &devp->hd_hpet->hpet_isr); |
174 | spin_unlock(&hpet_lock); | 176 | spin_unlock(&hpet_lock); |
175 | 177 | ||
176 | spin_lock(&hpet_task_lock); | ||
177 | if (devp->hd_task) | ||
178 | devp->hd_task->ht_func(devp->hd_task->ht_data); | ||
179 | spin_unlock(&hpet_task_lock); | ||
180 | |||
181 | wake_up_interruptible(&devp->hd_waitqueue); | 178 | wake_up_interruptible(&devp->hd_waitqueue); |
182 | 179 | ||
183 | kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN); | 180 | kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN); |
@@ -185,6 +182,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data) | |||
185 | return IRQ_HANDLED; | 182 | return IRQ_HANDLED; |
186 | } | 183 | } |
187 | 184 | ||
185 | static void hpet_timer_set_irq(struct hpet_dev *devp) | ||
186 | { | ||
187 | unsigned long v; | ||
188 | int irq, gsi; | ||
189 | struct hpet_timer __iomem *timer; | ||
190 | |||
191 | spin_lock_irq(&hpet_lock); | ||
192 | if (devp->hd_hdwirq) { | ||
193 | spin_unlock_irq(&hpet_lock); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | timer = devp->hd_timer; | ||
198 | |||
199 | /* we prefer level triggered mode */ | ||
200 | v = readl(&timer->hpet_config); | ||
201 | if (!(v & Tn_INT_TYPE_CNF_MASK)) { | ||
202 | v |= Tn_INT_TYPE_CNF_MASK; | ||
203 | writel(v, &timer->hpet_config); | ||
204 | } | ||
205 | spin_unlock_irq(&hpet_lock); | ||
206 | |||
207 | v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >> | ||
208 | Tn_INT_ROUTE_CAP_SHIFT; | ||
209 | |||
210 | /* | ||
211 | * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by | ||
212 | * legacy device. In IO APIC mode, we skip all the legacy IRQS. | ||
213 | */ | ||
214 | if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) | ||
215 | v &= ~0xf3df; | ||
216 | else | ||
217 | v &= ~0xffff; | ||
218 | |||
219 | for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ; | ||
220 | irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) { | ||
221 | |||
222 | if (irq >= NR_IRQS) { | ||
223 | irq = HPET_MAX_IRQ; | ||
224 | break; | ||
225 | } | ||
226 | |||
227 | gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE, | ||
228 | ACPI_ACTIVE_LOW); | ||
229 | if (gsi > 0) | ||
230 | break; | ||
231 | |||
232 | /* FIXME: Setup interrupt source table */ | ||
233 | } | ||
234 | |||
235 | if (irq < HPET_MAX_IRQ) { | ||
236 | spin_lock_irq(&hpet_lock); | ||
237 | v = readl(&timer->hpet_config); | ||
238 | v |= irq << Tn_INT_ROUTE_CNF_SHIFT; | ||
239 | writel(v, &timer->hpet_config); | ||
240 | devp->hd_hdwirq = gsi; | ||
241 | spin_unlock_irq(&hpet_lock); | ||
242 | } | ||
243 | return; | ||
244 | } | ||
245 | |||
188 | static int hpet_open(struct inode *inode, struct file *file) | 246 | static int hpet_open(struct inode *inode, struct file *file) |
189 | { | 247 | { |
190 | struct hpet_dev *devp; | 248 | struct hpet_dev *devp; |
@@ -199,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file) | |||
199 | 257 | ||
200 | for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) | 258 | for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) |
201 | for (i = 0; i < hpetp->hp_ntimer; i++) | 259 | for (i = 0; i < hpetp->hp_ntimer; i++) |
202 | if (hpetp->hp_dev[i].hd_flags & HPET_OPEN | 260 | if (hpetp->hp_dev[i].hd_flags & HPET_OPEN) |
203 | || hpetp->hp_dev[i].hd_task) | ||
204 | continue; | 261 | continue; |
205 | else { | 262 | else { |
206 | devp = &hpetp->hp_dev[i]; | 263 | devp = &hpetp->hp_dev[i]; |
@@ -219,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file) | |||
219 | spin_unlock_irq(&hpet_lock); | 276 | spin_unlock_irq(&hpet_lock); |
220 | unlock_kernel(); | 277 | unlock_kernel(); |
221 | 278 | ||
279 | hpet_timer_set_irq(devp); | ||
280 | |||
222 | return 0; | 281 | return 0; |
223 | } | 282 | } |
224 | 283 | ||
@@ -441,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) | |||
441 | devp->hd_irq = irq; | 500 | devp->hd_irq = irq; |
442 | t = devp->hd_ireqfreq; | 501 | t = devp->hd_ireqfreq; |
443 | v = readq(&timer->hpet_config); | 502 | v = readq(&timer->hpet_config); |
444 | g = v | Tn_INT_ENB_CNF_MASK; | 503 | |
504 | /* 64-bit comparators are not yet supported through the ioctls, | ||
505 | * so force this into 32-bit mode if it supports both modes | ||
506 | */ | ||
507 | g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK; | ||
445 | 508 | ||
446 | if (devp->hd_flags & HPET_PERIODIC) { | 509 | if (devp->hd_flags & HPET_PERIODIC) { |
447 | write_counter(t, &timer->hpet_compare); | 510 | write_counter(t, &timer->hpet_compare); |
@@ -451,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) | |||
451 | v |= Tn_VAL_SET_CNF_MASK; | 514 | v |= Tn_VAL_SET_CNF_MASK; |
452 | writeq(v, &timer->hpet_config); | 515 | writeq(v, &timer->hpet_config); |
453 | local_irq_save(flags); | 516 | local_irq_save(flags); |
517 | |||
518 | /* NOTE: what we modify here is a hidden accumulator | ||
519 | * register supported by periodic-capable comparators. | ||
520 | * We never want to modify the (single) counter; that | ||
521 | * would affect all the comparators. | ||
522 | */ | ||
454 | m = read_counter(&hpet->hpet_mc); | 523 | m = read_counter(&hpet->hpet_mc); |
455 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); | 524 | write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); |
456 | } else { | 525 | } else { |
@@ -604,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp) | |||
604 | return 0; | 673 | return 0; |
605 | } | 674 | } |
606 | 675 | ||
607 | static inline int hpet_tpcheck(struct hpet_task *tp) | ||
608 | { | ||
609 | struct hpet_dev *devp; | ||
610 | struct hpets *hpetp; | ||
611 | |||
612 | devp = tp->ht_opaque; | ||
613 | |||
614 | if (!devp) | ||
615 | return -ENXIO; | ||
616 | |||
617 | for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) | ||
618 | if (devp >= hpetp->hp_dev | ||
619 | && devp < (hpetp->hp_dev + hpetp->hp_ntimer) | ||
620 | && devp->hd_hpet == hpetp->hp_hpet) | ||
621 | return 0; | ||
622 | |||
623 | return -ENXIO; | ||
624 | } | ||
625 | |||
626 | #if 0 | ||
627 | int hpet_unregister(struct hpet_task *tp) | ||
628 | { | ||
629 | struct hpet_dev *devp; | ||
630 | struct hpet_timer __iomem *timer; | ||
631 | int err; | ||
632 | |||
633 | if ((err = hpet_tpcheck(tp))) | ||
634 | return err; | ||
635 | |||
636 | spin_lock_irq(&hpet_task_lock); | ||
637 | spin_lock(&hpet_lock); | ||
638 | |||
639 | devp = tp->ht_opaque; | ||
640 | if (devp->hd_task != tp) { | ||
641 | spin_unlock(&hpet_lock); | ||
642 | spin_unlock_irq(&hpet_task_lock); | ||
643 | return -ENXIO; | ||
644 | } | ||
645 | |||
646 | timer = devp->hd_timer; | ||
647 | writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK), | ||
648 | &timer->hpet_config); | ||
649 | devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC); | ||
650 | devp->hd_task = NULL; | ||
651 | spin_unlock(&hpet_lock); | ||
652 | spin_unlock_irq(&hpet_task_lock); | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | #endif /* 0 */ | ||
657 | |||
658 | static ctl_table hpet_table[] = { | 676 | static ctl_table hpet_table[] = { |
659 | { | 677 | { |
660 | .ctl_name = CTL_UNNUMBERED, | 678 | .ctl_name = CTL_UNNUMBERED, |
@@ -746,6 +764,7 @@ int hpet_alloc(struct hpet_data *hdp) | |||
746 | static struct hpets *last = NULL; | 764 | static struct hpets *last = NULL; |
747 | unsigned long period; | 765 | unsigned long period; |
748 | unsigned long long temp; | 766 | unsigned long long temp; |
767 | u32 remainder; | ||
749 | 768 | ||
750 | /* | 769 | /* |
751 | * hpet_alloc can be called by platform dependent code. | 770 | * hpet_alloc can be called by platform dependent code. |
@@ -809,9 +828,13 @@ int hpet_alloc(struct hpet_data *hdp) | |||
809 | printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); | 828 | printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); |
810 | printk("\n"); | 829 | printk("\n"); |
811 | 830 | ||
812 | printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", | 831 | temp = hpetp->hp_tick_freq; |
813 | hpetp->hp_which, hpetp->hp_ntimer, | 832 | remainder = do_div(temp, 1000000); |
814 | cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq); | 833 | printk(KERN_INFO |
834 | "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n", | ||
835 | hpetp->hp_which, hpetp->hp_ntimer, | ||
836 | cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, | ||
837 | (unsigned) temp, remainder); | ||
815 | 838 | ||
816 | mcfg = readq(&hpet->hpet_config); | 839 | mcfg = readq(&hpet->hpet_config); |
817 | if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { | 840 | if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { |
@@ -874,8 +897,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
874 | hdp->hd_address = ioremap(addr.minimum, addr.address_length); | 897 | hdp->hd_address = ioremap(addr.minimum, addr.address_length); |
875 | 898 | ||
876 | if (hpet_is_known(hdp)) { | 899 | if (hpet_is_known(hdp)) { |
877 | printk(KERN_DEBUG "%s: 0x%lx is busy\n", | ||
878 | __func__, hdp->hd_phys_address); | ||
879 | iounmap(hdp->hd_address); | 900 | iounmap(hdp->hd_address); |
880 | return AE_ALREADY_EXISTS; | 901 | return AE_ALREADY_EXISTS; |
881 | } | 902 | } |
@@ -891,8 +912,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
891 | HPET_RANGE_SIZE); | 912 | HPET_RANGE_SIZE); |
892 | 913 | ||
893 | if (hpet_is_known(hdp)) { | 914 | if (hpet_is_known(hdp)) { |
894 | printk(KERN_DEBUG "%s: 0x%lx is busy\n", | ||
895 | __func__, hdp->hd_phys_address); | ||
896 | iounmap(hdp->hd_address); | 915 | iounmap(hdp->hd_address); |
897 | return AE_ALREADY_EXISTS; | 916 | return AE_ALREADY_EXISTS; |
898 | } | 917 | } |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index fd64137b1ab9..ec7aded0a2df 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -819,11 +819,11 @@ static int hvc_init(void) | |||
819 | hvc_driver = drv; | 819 | hvc_driver = drv; |
820 | return 0; | 820 | return 0; |
821 | 821 | ||
822 | put_tty: | ||
823 | put_tty_driver(hvc_driver); | ||
824 | stop_thread: | 822 | stop_thread: |
825 | kthread_stop(hvc_task); | 823 | kthread_stop(hvc_task); |
826 | hvc_task = NULL; | 824 | hvc_task = NULL; |
825 | put_tty: | ||
826 | put_tty_driver(drv); | ||
827 | out: | 827 | out: |
828 | return err; | 828 | return err; |
829 | } | 829 | } |
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile index 939618f62fe1..bc397d92b499 100644 --- a/drivers/char/ip2/Makefile +++ b/drivers/char/ip2/Makefile | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_COMPUTONE) += ip2.o | 5 | obj-$(CONFIG_COMPUTONE) += ip2.o |
6 | 6 | ||
7 | ip2-objs := ip2base.o ip2main.o | 7 | ip2-objs := ip2main.o |
8 | 8 | ||
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c index 3601017f58cf..29db44de399f 100644 --- a/drivers/char/ip2/i2ellis.c +++ b/drivers/char/ip2/i2ellis.c | |||
@@ -69,38 +69,6 @@ static DEFINE_RWLOCK(Dl_spinlock); | |||
69 | //======================================================= | 69 | //======================================================= |
70 | 70 | ||
71 | //****************************************************************************** | 71 | //****************************************************************************** |
72 | // Function: iiEllisInit() | ||
73 | // Parameters: None | ||
74 | // | ||
75 | // Returns: Nothing | ||
76 | // | ||
77 | // Description: | ||
78 | // | ||
79 | // This routine performs any required initialization of the iiEllis subsystem. | ||
80 | // | ||
81 | //****************************************************************************** | ||
82 | static void | ||
83 | iiEllisInit(void) | ||
84 | { | ||
85 | } | ||
86 | |||
87 | //****************************************************************************** | ||
88 | // Function: iiEllisCleanup() | ||
89 | // Parameters: None | ||
90 | // | ||
91 | // Returns: Nothing | ||
92 | // | ||
93 | // Description: | ||
94 | // | ||
95 | // This routine performs any required cleanup of the iiEllis subsystem. | ||
96 | // | ||
97 | //****************************************************************************** | ||
98 | static void | ||
99 | iiEllisCleanup(void) | ||
100 | { | ||
101 | } | ||
102 | |||
103 | //****************************************************************************** | ||
104 | // Function: iiSetAddress(pB, address, delay) | 72 | // Function: iiSetAddress(pB, address, delay) |
105 | // Parameters: pB - pointer to the board structure | 73 | // Parameters: pB - pointer to the board structure |
106 | // address - the purported I/O address of the board | 74 | // address - the purported I/O address of the board |
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h index c88a64e527aa..fb6df2456018 100644 --- a/drivers/char/ip2/i2ellis.h +++ b/drivers/char/ip2/i2ellis.h | |||
@@ -511,7 +511,6 @@ typedef void (*delayFunc_t)(unsigned int); | |||
511 | // | 511 | // |
512 | // Initialization of a board & structure is in four (five!) parts: | 512 | // Initialization of a board & structure is in four (five!) parts: |
513 | // | 513 | // |
514 | // 0) iiEllisInit() - Initialize iiEllis subsystem. | ||
515 | // 1) iiSetAddress() - Define the board address & delay function for a board. | 514 | // 1) iiSetAddress() - Define the board address & delay function for a board. |
516 | // 2) iiReset() - Reset the board (provided it exists) | 515 | // 2) iiReset() - Reset the board (provided it exists) |
517 | // -- Note you may do this to several boards -- | 516 | // -- Note you may do this to several boards -- |
@@ -523,7 +522,6 @@ typedef void (*delayFunc_t)(unsigned int); | |||
523 | // loadware. To change loadware, you must begin again with step 2, resetting | 522 | // loadware. To change loadware, you must begin again with step 2, resetting |
524 | // the board again (step 1 not needed). | 523 | // the board again (step 1 not needed). |
525 | 524 | ||
526 | static void iiEllisInit(void); | ||
527 | static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t ); | 525 | static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t ); |
528 | static int iiReset(i2eBordStrPtr); | 526 | static int iiReset(i2eBordStrPtr); |
529 | static int iiResetDelay(i2eBordStrPtr); | 527 | static int iiResetDelay(i2eBordStrPtr); |
diff --git a/drivers/char/ip2/ip2base.c b/drivers/char/ip2/ip2base.c deleted file mode 100644 index 8155e247c04b..000000000000 --- a/drivers/char/ip2/ip2base.c +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | // ip2.c | ||
2 | // This is a dummy module to make the firmware available when needed | ||
3 | // and allows it to be unloaded when not. Rumor is the __initdata | ||
4 | // macro doesn't always works on all platforms so we use this kludge. | ||
5 | // If not compiled as a module it just makes fip_firm avaliable then | ||
6 | // __initdata should work as advertized | ||
7 | // | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/wait.h> | ||
12 | |||
13 | #ifndef __init | ||
14 | #define __init | ||
15 | #endif | ||
16 | #ifndef __initfunc | ||
17 | #define __initfunc(a) a | ||
18 | #endif | ||
19 | #ifndef __initdata | ||
20 | #define __initdata | ||
21 | #endif | ||
22 | |||
23 | #include "ip2types.h" | ||
24 | |||
25 | int | ||
26 | ip2_loadmain(int *, int *); // ref into ip2main.c | ||
27 | |||
28 | /* Note: Add compiled in defaults to these arrays, not to the structure | ||
29 | in ip2.h any longer. That structure WILL get overridden | ||
30 | by these values, or command line values, or insmod values!!! =mhw= | ||
31 | */ | ||
32 | static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 }; | ||
33 | static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; | ||
34 | |||
35 | static int poll_only = 0; | ||
36 | |||
37 | MODULE_AUTHOR("Doug McNash"); | ||
38 | MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); | ||
39 | module_param_array(irq, int, NULL, 0); | ||
40 | MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); | ||
41 | module_param_array(io, int, NULL, 0); | ||
42 | MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); | ||
43 | module_param(poll_only, bool, 0); | ||
44 | MODULE_PARM_DESC(poll_only,"Do not use card interrupts"); | ||
45 | |||
46 | |||
47 | static int __init ip2_init(void) | ||
48 | { | ||
49 | if( poll_only ) { | ||
50 | /* Hard lock the interrupts to zero */ | ||
51 | irq[0] = irq[1] = irq[2] = irq[3] = 0; | ||
52 | } | ||
53 | |||
54 | return ip2_loadmain(io, irq); | ||
55 | } | ||
56 | module_init(ip2_init); | ||
57 | |||
58 | MODULE_LICENSE("GPL"); | ||
59 | |||
60 | #ifndef MODULE | ||
61 | /****************************************************************************** | ||
62 | * ip2_setup: | ||
63 | * str: kernel command line string | ||
64 | * | ||
65 | * Can't autoprobe the boards so user must specify configuration on | ||
66 | * kernel command line. Sane people build it modular but the others | ||
67 | * come here. | ||
68 | * | ||
69 | * Alternating pairs of io,irq for up to 4 boards. | ||
70 | * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 | ||
71 | * | ||
72 | * io=0 => No board | ||
73 | * io=1 => PCI | ||
74 | * io=2 => EISA | ||
75 | * else => ISA I/O address | ||
76 | * | ||
77 | * irq=0 or invalid for ISA will revert to polling mode | ||
78 | * | ||
79 | * Any value = -1, do not overwrite compiled in value. | ||
80 | * | ||
81 | ******************************************************************************/ | ||
82 | static int __init ip2_setup(char *str) | ||
83 | { | ||
84 | int ints[10]; /* 4 boards, 2 parameters + 2 */ | ||
85 | int i, j; | ||
86 | |||
87 | str = get_options (str, ARRAY_SIZE(ints), ints); | ||
88 | |||
89 | for( i = 0, j = 1; i < 4; i++ ) { | ||
90 | if( j > ints[0] ) { | ||
91 | break; | ||
92 | } | ||
93 | if( ints[j] >= 0 ) { | ||
94 | io[i] = ints[j]; | ||
95 | } | ||
96 | j++; | ||
97 | if( j > ints[0] ) { | ||
98 | break; | ||
99 | } | ||
100 | if( ints[j] >= 0 ) { | ||
101 | irq[i] = ints[j]; | ||
102 | } | ||
103 | j++; | ||
104 | } | ||
105 | return 1; | ||
106 | } | ||
107 | __setup("ip2=", ip2_setup); | ||
108 | #endif /* !MODULE */ | ||
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 689f9dcd3b86..6774572d3759 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
@@ -150,15 +150,12 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); | |||
150 | /*************/ | 150 | /*************/ |
151 | 151 | ||
152 | /* String constants to identify ourselves */ | 152 | /* String constants to identify ourselves */ |
153 | static char *pcName = "Computone IntelliPort Plus multiport driver"; | 153 | static const char pcName[] = "Computone IntelliPort Plus multiport driver"; |
154 | static char *pcVersion = "1.2.14"; | 154 | static const char pcVersion[] = "1.2.14"; |
155 | 155 | ||
156 | /* String constants for port names */ | 156 | /* String constants for port names */ |
157 | static char *pcDriver_name = "ip2"; | 157 | static const char pcDriver_name[] = "ip2"; |
158 | static char *pcIpl = "ip2ipl"; | 158 | static const char pcIpl[] = "ip2ipl"; |
159 | |||
160 | // cheezy kludge or genius - you decide? | ||
161 | int ip2_loadmain(int *, int *); | ||
162 | 159 | ||
163 | /***********************/ | 160 | /***********************/ |
164 | /* Function Prototypes */ | 161 | /* Function Prototypes */ |
@@ -240,8 +237,8 @@ static const struct file_operations ip2_ipl = { | |||
240 | .open = ip2_ipl_open, | 237 | .open = ip2_ipl_open, |
241 | }; | 238 | }; |
242 | 239 | ||
243 | static unsigned long irq_counter = 0; | 240 | static unsigned long irq_counter; |
244 | static unsigned long bh_counter = 0; | 241 | static unsigned long bh_counter; |
245 | 242 | ||
246 | // Use immediate queue to service interrupts | 243 | // Use immediate queue to service interrupts |
247 | #define USE_IQI | 244 | #define USE_IQI |
@@ -252,7 +249,6 @@ static unsigned long bh_counter = 0; | |||
252 | */ | 249 | */ |
253 | #define POLL_TIMEOUT (jiffies + 1) | 250 | #define POLL_TIMEOUT (jiffies + 1) |
254 | static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); | 251 | static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); |
255 | static char TimerOn; | ||
256 | 252 | ||
257 | #ifdef IP2DEBUG_TRACE | 253 | #ifdef IP2DEBUG_TRACE |
258 | /* Trace (debug) buffer data */ | 254 | /* Trace (debug) buffer data */ |
@@ -268,8 +264,8 @@ static int tracewrap; | |||
268 | /**********/ | 264 | /**********/ |
269 | 265 | ||
270 | #if defined(MODULE) && defined(IP2DEBUG_OPEN) | 266 | #if defined(MODULE) && defined(IP2DEBUG_OPEN) |
271 | #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ | 267 | #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \ |
272 | tty->name,(pCh->flags),ip2_tty_driver->refcount, \ | 268 | tty->name,(pCh->flags), \ |
273 | tty->count,/*GET_USE_COUNT(module)*/0,s) | 269 | tty->count,/*GET_USE_COUNT(module)*/0,s) |
274 | #else | 270 | #else |
275 | #define DBG_CNT(s) | 271 | #define DBG_CNT(s) |
@@ -287,8 +283,9 @@ static int tracewrap; | |||
287 | 283 | ||
288 | MODULE_AUTHOR("Doug McNash"); | 284 | MODULE_AUTHOR("Doug McNash"); |
289 | MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); | 285 | MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); |
286 | MODULE_LICENSE("GPL"); | ||
290 | 287 | ||
291 | static int poll_only = 0; | 288 | static int poll_only; |
292 | 289 | ||
293 | static int Eisa_irq; | 290 | static int Eisa_irq; |
294 | static int Eisa_slot; | 291 | static int Eisa_slot; |
@@ -297,34 +294,46 @@ static int iindx; | |||
297 | static char rirqs[IP2_MAX_BOARDS]; | 294 | static char rirqs[IP2_MAX_BOARDS]; |
298 | static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; | 295 | static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; |
299 | 296 | ||
297 | /* Note: Add compiled in defaults to these arrays, not to the structure | ||
298 | in ip2.h any longer. That structure WILL get overridden | ||
299 | by these values, or command line values, or insmod values!!! =mhw= | ||
300 | */ | ||
301 | static int io[IP2_MAX_BOARDS]; | ||
302 | static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; | ||
303 | |||
304 | MODULE_AUTHOR("Doug McNash"); | ||
305 | MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); | ||
306 | module_param_array(irq, int, NULL, 0); | ||
307 | MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards"); | ||
308 | module_param_array(io, int, NULL, 0); | ||
309 | MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards"); | ||
310 | module_param(poll_only, bool, 0); | ||
311 | MODULE_PARM_DESC(poll_only, "Do not use card interrupts"); | ||
312 | |||
300 | /* for sysfs class support */ | 313 | /* for sysfs class support */ |
301 | static struct class *ip2_class; | 314 | static struct class *ip2_class; |
302 | 315 | ||
303 | // Some functions to keep track of what irq's we have | 316 | /* Some functions to keep track of what irqs we have */ |
304 | 317 | ||
305 | static int | 318 | static int __init is_valid_irq(int irq) |
306 | is_valid_irq(int irq) | ||
307 | { | 319 | { |
308 | int *i = Valid_Irqs; | 320 | int *i = Valid_Irqs; |
309 | 321 | ||
310 | while ((*i != 0) && (*i != irq)) { | 322 | while (*i != 0 && *i != irq) |
311 | i++; | 323 | i++; |
312 | } | 324 | |
313 | return (*i); | 325 | return *i; |
314 | } | 326 | } |
315 | 327 | ||
316 | static void | 328 | static void __init mark_requested_irq(char irq) |
317 | mark_requested_irq( char irq ) | ||
318 | { | 329 | { |
319 | rirqs[iindx++] = irq; | 330 | rirqs[iindx++] = irq; |
320 | } | 331 | } |
321 | 332 | ||
322 | #ifdef MODULE | 333 | static int __exit clear_requested_irq(char irq) |
323 | static int | ||
324 | clear_requested_irq( char irq ) | ||
325 | { | 334 | { |
326 | int i; | 335 | int i; |
327 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 336 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
328 | if (rirqs[i] == irq) { | 337 | if (rirqs[i] == irq) { |
329 | rirqs[i] = 0; | 338 | rirqs[i] = 0; |
330 | return 1; | 339 | return 1; |
@@ -332,17 +341,15 @@ clear_requested_irq( char irq ) | |||
332 | } | 341 | } |
333 | return 0; | 342 | return 0; |
334 | } | 343 | } |
335 | #endif | ||
336 | 344 | ||
337 | static int | 345 | static int have_requested_irq(char irq) |
338 | have_requested_irq( char irq ) | ||
339 | { | 346 | { |
340 | // array init to zeros so 0 irq will not be requested as a side effect | 347 | /* array init to zeros so 0 irq will not be requested as a side |
348 | * effect */ | ||
341 | int i; | 349 | int i; |
342 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 350 | for (i = 0; i < IP2_MAX_BOARDS; ++i) |
343 | if (rirqs[i] == irq) | 351 | if (rirqs[i] == irq) |
344 | return 1; | 352 | return 1; |
345 | } | ||
346 | return 0; | 353 | return 0; |
347 | } | 354 | } |
348 | 355 | ||
@@ -361,53 +368,45 @@ have_requested_irq( char irq ) | |||
361 | /* handle subsequent installations of the driver. All memory allocated by the */ | 368 | /* handle subsequent installations of the driver. All memory allocated by the */ |
362 | /* driver should be returned since it may be unloaded from memory. */ | 369 | /* driver should be returned since it may be unloaded from memory. */ |
363 | /******************************************************************************/ | 370 | /******************************************************************************/ |
364 | #ifdef MODULE | 371 | static void __exit ip2_cleanup_module(void) |
365 | void __exit | ||
366 | ip2_cleanup_module(void) | ||
367 | { | 372 | { |
368 | int err; | 373 | int err; |
369 | int i; | 374 | int i; |
370 | 375 | ||
371 | #ifdef IP2DEBUG_INIT | 376 | del_timer_sync(&PollTimer); |
372 | printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion ); | ||
373 | #endif | ||
374 | /* Stop poll timer if we had one. */ | ||
375 | if ( TimerOn ) { | ||
376 | del_timer ( &PollTimer ); | ||
377 | TimerOn = 0; | ||
378 | } | ||
379 | 377 | ||
380 | /* Reset the boards we have. */ | 378 | /* Reset the boards we have. */ |
381 | for( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 379 | for (i = 0; i < IP2_MAX_BOARDS; i++) |
382 | if ( i2BoardPtrTable[i] ) { | 380 | if (i2BoardPtrTable[i]) |
383 | iiReset( i2BoardPtrTable[i] ); | 381 | iiReset(i2BoardPtrTable[i]); |
384 | } | ||
385 | } | ||
386 | 382 | ||
387 | /* The following is done at most once, if any boards were installed. */ | 383 | /* The following is done at most once, if any boards were installed. */ |
388 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 384 | for (i = 0; i < IP2_MAX_BOARDS; i++) { |
389 | if ( i2BoardPtrTable[i] ) { | 385 | if (i2BoardPtrTable[i]) { |
390 | iiResetDelay( i2BoardPtrTable[i] ); | 386 | iiResetDelay(i2BoardPtrTable[i]); |
391 | /* free io addresses and Tibet */ | 387 | /* free io addresses and Tibet */ |
392 | release_region( ip2config.addr[i], 8 ); | 388 | release_region(ip2config.addr[i], 8); |
393 | device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); | 389 | device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); |
394 | device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); | 390 | device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, |
391 | 4 * i + 1)); | ||
395 | } | 392 | } |
396 | /* Disable and remove interrupt handler. */ | 393 | /* Disable and remove interrupt handler. */ |
397 | if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { | 394 | if (ip2config.irq[i] > 0 && |
398 | free_irq ( ip2config.irq[i], (void *)&pcName); | 395 | have_requested_irq(ip2config.irq[i])) { |
399 | clear_requested_irq( ip2config.irq[i]); | 396 | free_irq(ip2config.irq[i], (void *)&pcName); |
397 | clear_requested_irq(ip2config.irq[i]); | ||
400 | } | 398 | } |
401 | } | 399 | } |
402 | class_destroy(ip2_class); | 400 | class_destroy(ip2_class); |
403 | if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { | 401 | err = tty_unregister_driver(ip2_tty_driver); |
404 | printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); | 402 | if (err) |
405 | } | 403 | printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", |
404 | err); | ||
406 | put_tty_driver(ip2_tty_driver); | 405 | put_tty_driver(ip2_tty_driver); |
407 | unregister_chrdev(IP2_IPL_MAJOR, pcIpl); | 406 | unregister_chrdev(IP2_IPL_MAJOR, pcIpl); |
408 | remove_proc_entry("ip2mem", NULL); | 407 | remove_proc_entry("ip2mem", NULL); |
409 | 408 | ||
410 | // free memory | 409 | /* free memory */ |
411 | for (i = 0; i < IP2_MAX_BOARDS; i++) { | 410 | for (i = 0; i < IP2_MAX_BOARDS; i++) { |
412 | void *pB; | 411 | void *pB; |
413 | #ifdef CONFIG_PCI | 412 | #ifdef CONFIG_PCI |
@@ -417,24 +416,18 @@ ip2_cleanup_module(void) | |||
417 | ip2config.pci_dev[i] = NULL; | 416 | ip2config.pci_dev[i] = NULL; |
418 | } | 417 | } |
419 | #endif | 418 | #endif |
420 | if ((pB = i2BoardPtrTable[i]) != 0 ) { | 419 | pB = i2BoardPtrTable[i]; |
421 | kfree ( pB ); | 420 | if (pB != NULL) { |
421 | kfree(pB); | ||
422 | i2BoardPtrTable[i] = NULL; | 422 | i2BoardPtrTable[i] = NULL; |
423 | } | 423 | } |
424 | if ((DevTableMem[i]) != NULL ) { | 424 | if (DevTableMem[i] != NULL) { |
425 | kfree ( DevTableMem[i] ); | 425 | kfree(DevTableMem[i]); |
426 | DevTableMem[i] = NULL; | 426 | DevTableMem[i] = NULL; |
427 | } | 427 | } |
428 | } | 428 | } |
429 | |||
430 | /* Cleanup the iiEllis subsystem. */ | ||
431 | iiEllisCleanup(); | ||
432 | #ifdef IP2DEBUG_INIT | ||
433 | printk (KERN_DEBUG "IP2 Unloaded\n" ); | ||
434 | #endif | ||
435 | } | 429 | } |
436 | module_exit(ip2_cleanup_module); | 430 | module_exit(ip2_cleanup_module); |
437 | #endif /* MODULE */ | ||
438 | 431 | ||
439 | static const struct tty_operations ip2_ops = { | 432 | static const struct tty_operations ip2_ops = { |
440 | .open = ip2_open, | 433 | .open = ip2_open, |
@@ -494,139 +487,168 @@ static const struct firmware *ip2_request_firmware(void) | |||
494 | return fw; | 487 | return fw; |
495 | } | 488 | } |
496 | 489 | ||
497 | int | 490 | #ifndef MODULE |
498 | ip2_loadmain(int *iop, int *irqp) | 491 | /****************************************************************************** |
492 | * ip2_setup: | ||
493 | * str: kernel command line string | ||
494 | * | ||
495 | * Can't autoprobe the boards so user must specify configuration on | ||
496 | * kernel command line. Sane people build it modular but the others | ||
497 | * come here. | ||
498 | * | ||
499 | * Alternating pairs of io,irq for up to 4 boards. | ||
500 | * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 | ||
501 | * | ||
502 | * io=0 => No board | ||
503 | * io=1 => PCI | ||
504 | * io=2 => EISA | ||
505 | * else => ISA I/O address | ||
506 | * | ||
507 | * irq=0 or invalid for ISA will revert to polling mode | ||
508 | * | ||
509 | * Any value = -1, do not overwrite compiled in value. | ||
510 | * | ||
511 | ******************************************************************************/ | ||
512 | static int __init ip2_setup(char *str) | ||
513 | { | ||
514 | int j, ints[10]; /* 4 boards, 2 parameters + 2 */ | ||
515 | unsigned int i; | ||
516 | |||
517 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
518 | |||
519 | for (i = 0, j = 1; i < 4; i++) { | ||
520 | if (j > ints[0]) | ||
521 | break; | ||
522 | if (ints[j] >= 0) | ||
523 | io[i] = ints[j]; | ||
524 | j++; | ||
525 | if (j > ints[0]) | ||
526 | break; | ||
527 | if (ints[j] >= 0) | ||
528 | irq[i] = ints[j]; | ||
529 | j++; | ||
530 | } | ||
531 | return 1; | ||
532 | } | ||
533 | __setup("ip2=", ip2_setup); | ||
534 | #endif /* !MODULE */ | ||
535 | |||
536 | static int __init ip2_loadmain(void) | ||
499 | { | 537 | { |
500 | int i, j, box; | 538 | int i, j, box; |
501 | int err = 0; | 539 | int err = 0; |
502 | static int loaded; | ||
503 | i2eBordStrPtr pB = NULL; | 540 | i2eBordStrPtr pB = NULL; |
504 | int rc = -1; | 541 | int rc = -1; |
505 | static struct pci_dev *pci_dev_i = NULL; | 542 | struct pci_dev *pdev = NULL; |
506 | const struct firmware *fw = NULL; | 543 | const struct firmware *fw = NULL; |
507 | 544 | ||
508 | ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 ); | 545 | if (poll_only) { |
546 | /* Hard lock the interrupts to zero */ | ||
547 | irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0; | ||
548 | } | ||
549 | |||
550 | ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0); | ||
509 | 551 | ||
510 | /* process command line arguments to modprobe or | 552 | /* process command line arguments to modprobe or |
511 | insmod i.e. iop & irqp */ | 553 | insmod i.e. iop & irqp */ |
512 | /* irqp and iop should ALWAYS be specified now... But we check | 554 | /* irqp and iop should ALWAYS be specified now... But we check |
513 | them individually just to be sure, anyways... */ | 555 | them individually just to be sure, anyways... */ |
514 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 556 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
515 | if (iop) { | 557 | ip2config.addr[i] = io[i]; |
516 | ip2config.addr[i] = iop[i]; | 558 | if (irq[i] >= 0) |
517 | if (irqp) { | 559 | ip2config.irq[i] = irq[i]; |
518 | if( irqp[i] >= 0 ) { | 560 | else |
519 | ip2config.irq[i] = irqp[i]; | 561 | ip2config.irq[i] = 0; |
520 | } else { | 562 | /* This is a little bit of a hack. If poll_only=1 on command |
521 | ip2config.irq[i] = 0; | 563 | line back in ip2.c OR all IRQs on all specified boards are |
522 | } | 564 | explicitly set to 0, then drop to poll only mode and override |
523 | // This is a little bit of a hack. If poll_only=1 on command | 565 | PCI or EISA interrupts. This superceeds the old hack of |
524 | // line back in ip2.c OR all IRQs on all specified boards are | 566 | triggering if all interrupts were zero (like da default). |
525 | // explicitly set to 0, then drop to poll only mode and override | 567 | Still a hack but less prone to random acts of terrorism. |
526 | // PCI or EISA interrupts. This superceeds the old hack of | 568 | |
527 | // triggering if all interrupts were zero (like da default). | 569 | What we really should do, now that the IRQ default is set |
528 | // Still a hack but less prone to random acts of terrorism. | 570 | to -1, is to use 0 as a hard coded, do not probe. |
529 | // | 571 | |
530 | // What we really should do, now that the IRQ default is set | 572 | /\/\|=mhw=|\/\/ |
531 | // to -1, is to use 0 as a hard coded, do not probe. | 573 | */ |
532 | // | 574 | poll_only |= irq[i]; |
533 | // /\/\|=mhw=|\/\/ | ||
534 | poll_only |= irqp[i]; | ||
535 | } | ||
536 | } | ||
537 | } | 575 | } |
538 | poll_only = !poll_only; | 576 | poll_only = !poll_only; |
539 | 577 | ||
540 | /* Announce our presence */ | 578 | /* Announce our presence */ |
541 | printk( KERN_INFO "%s version %s\n", pcName, pcVersion ); | 579 | printk(KERN_INFO "%s version %s\n", pcName, pcVersion); |
542 | |||
543 | // ip2 can be unloaded and reloaded for no good reason | ||
544 | // we can't let that happen here or bad things happen | ||
545 | // second load hoses board but not system - fixme later | ||
546 | if (loaded) { | ||
547 | printk( KERN_INFO "Still loaded\n" ); | ||
548 | return 0; | ||
549 | } | ||
550 | loaded++; | ||
551 | 580 | ||
552 | ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS); | 581 | ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS); |
553 | if (!ip2_tty_driver) | 582 | if (!ip2_tty_driver) |
554 | return -ENOMEM; | 583 | return -ENOMEM; |
555 | 584 | ||
556 | /* Initialise the iiEllis subsystem. */ | ||
557 | iiEllisInit(); | ||
558 | |||
559 | /* Initialize arrays. */ | ||
560 | memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable ); | ||
561 | memset( DevTable, 0, sizeof DevTable ); | ||
562 | |||
563 | /* Initialise all the boards we can find (up to the maximum). */ | 585 | /* Initialise all the boards we can find (up to the maximum). */ |
564 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 586 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
565 | switch ( ip2config.addr[i] ) { | 587 | switch (ip2config.addr[i]) { |
566 | case 0: /* skip this slot even if card is present */ | 588 | case 0: /* skip this slot even if card is present */ |
567 | break; | 589 | break; |
568 | default: /* ISA */ | 590 | default: /* ISA */ |
569 | /* ISA address must be specified */ | 591 | /* ISA address must be specified */ |
570 | if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) { | 592 | if (ip2config.addr[i] < 0x100 || |
571 | printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n", | 593 | ip2config.addr[i] > 0x3f8) { |
572 | i, ip2config.addr[i] ); | 594 | printk(KERN_ERR "IP2: Bad ISA board %d " |
595 | "address %x\n", i, | ||
596 | ip2config.addr[i]); | ||
573 | ip2config.addr[i] = 0; | 597 | ip2config.addr[i] = 0; |
574 | } else { | 598 | break; |
575 | ip2config.type[i] = ISA; | 599 | } |
576 | 600 | ip2config.type[i] = ISA; | |
577 | /* Check for valid irq argument, set for polling if invalid */ | 601 | |
578 | if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) { | 602 | /* Check for valid irq argument, set for polling if |
579 | printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]); | 603 | * invalid */ |
580 | ip2config.irq[i] = 0;// 0 is polling and is valid in that sense | 604 | if (ip2config.irq[i] && |
581 | } | 605 | !is_valid_irq(ip2config.irq[i])) { |
606 | printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n", | ||
607 | ip2config.irq[i]); | ||
608 | /* 0 is polling and is valid in that sense */ | ||
609 | ip2config.irq[i] = 0; | ||
582 | } | 610 | } |
583 | break; | 611 | break; |
584 | case PCI: | 612 | case PCI: |
585 | #ifdef CONFIG_PCI | 613 | #ifdef CONFIG_PCI |
586 | { | 614 | { |
587 | int status; | 615 | u32 addr; |
616 | int status; | ||
588 | 617 | ||
589 | pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE, | 618 | pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE, |
590 | PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); | 619 | PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev); |
591 | if (pci_dev_i != NULL) { | 620 | if (pdev == NULL) { |
592 | unsigned int addr; | 621 | ip2config.addr[i] = 0; |
593 | 622 | printk(KERN_ERR "IP2: PCI board %d not " | |
594 | if (pci_enable_device(pci_dev_i)) { | 623 | "found\n", i); |
595 | printk( KERN_ERR "IP2: can't enable PCI device at %s\n", | 624 | break; |
596 | pci_name(pci_dev_i)); | 625 | } |
597 | break; | ||
598 | } | ||
599 | ip2config.type[i] = PCI; | ||
600 | ip2config.pci_dev[i] = pci_dev_get(pci_dev_i); | ||
601 | status = | ||
602 | pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); | ||
603 | if ( addr & 1 ) { | ||
604 | ip2config.addr[i]=(USHORT)(addr&0xfffe); | ||
605 | } else { | ||
606 | printk( KERN_ERR "IP2: PCI I/O address error\n"); | ||
607 | } | ||
608 | 626 | ||
609 | // If the PCI BIOS assigned it, lets try and use it. If we | 627 | if (pci_enable_device(pdev)) { |
610 | // can't acquire it or it screws up, deal with it then. | 628 | dev_err(&pdev->dev, "can't enable device\n"); |
611 | 629 | break; | |
612 | // if (!is_valid_irq(pci_irq)) { | ||
613 | // printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); | ||
614 | // pci_irq = 0; | ||
615 | // } | ||
616 | ip2config.irq[i] = pci_dev_i->irq; | ||
617 | } else { // ann error | ||
618 | ip2config.addr[i] = 0; | ||
619 | printk(KERN_ERR "IP2: PCI board %d not found\n", i); | ||
620 | } | ||
621 | } | 630 | } |
631 | ip2config.type[i] = PCI; | ||
632 | ip2config.pci_dev[i] = pci_dev_get(pdev); | ||
633 | status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, | ||
634 | &addr); | ||
635 | if (addr & 1) | ||
636 | ip2config.addr[i] = (USHORT)(addr & 0xfffe); | ||
637 | else | ||
638 | dev_err(&pdev->dev, "I/O address error\n"); | ||
639 | |||
640 | ip2config.irq[i] = pdev->irq; | ||
641 | } | ||
622 | #else | 642 | #else |
623 | printk( KERN_ERR "IP2: PCI card specified but PCI support not\n"); | 643 | printk(KERN_ERR "IP2: PCI card specified but PCI " |
624 | printk( KERN_ERR "IP2: configured in this kernel.\n"); | 644 | "support not enabled.\n"); |
625 | printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n"); | 645 | printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI " |
646 | "defined!\n"); | ||
626 | #endif /* CONFIG_PCI */ | 647 | #endif /* CONFIG_PCI */ |
627 | break; | 648 | break; |
628 | case EISA: | 649 | case EISA: |
629 | if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) { | 650 | ip2config.addr[i] = find_eisa_board(Eisa_slot + 1); |
651 | if (ip2config.addr[i] != 0) { | ||
630 | /* Eisa_irq set as side effect, boo */ | 652 | /* Eisa_irq set as side effect, boo */ |
631 | ip2config.type[i] = EISA; | 653 | ip2config.type[i] = EISA; |
632 | } | 654 | } |
@@ -634,31 +656,32 @@ ip2_loadmain(int *iop, int *irqp) | |||
634 | break; | 656 | break; |
635 | } /* switch */ | 657 | } /* switch */ |
636 | } /* for */ | 658 | } /* for */ |
637 | if (pci_dev_i) | 659 | pci_dev_put(pdev); |
638 | pci_dev_put(pci_dev_i); | ||
639 | 660 | ||
640 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 661 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
641 | if ( ip2config.addr[i] ) { | 662 | if (ip2config.addr[i]) { |
642 | pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL); | 663 | pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL); |
643 | if (pB) { | 664 | if (pB) { |
644 | i2BoardPtrTable[i] = pB; | 665 | i2BoardPtrTable[i] = pB; |
645 | iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer ); | 666 | iiSetAddress(pB, ip2config.addr[i], |
646 | iiReset( pB ); | 667 | ii2DelayTimer); |
647 | } else { | 668 | iiReset(pB); |
648 | printk(KERN_ERR "IP2: board memory allocation error\n"); | 669 | } else |
649 | } | 670 | printk(KERN_ERR "IP2: board memory allocation " |
671 | "error\n"); | ||
650 | } | 672 | } |
651 | } | 673 | } |
652 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 674 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
653 | if ( ( pB = i2BoardPtrTable[i] ) != NULL ) { | 675 | pB = i2BoardPtrTable[i]; |
654 | iiResetDelay( pB ); | 676 | if (pB != NULL) { |
677 | iiResetDelay(pB); | ||
655 | break; | 678 | break; |
656 | } | 679 | } |
657 | } | 680 | } |
658 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 681 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
659 | /* We don't want to request the firmware unless we have at | 682 | /* We don't want to request the firmware unless we have at |
660 | least one board */ | 683 | least one board */ |
661 | if ( i2BoardPtrTable[i] != NULL ) { | 684 | if (i2BoardPtrTable[i] != NULL) { |
662 | if (!fw) | 685 | if (!fw) |
663 | fw = ip2_request_firmware(); | 686 | fw = ip2_request_firmware(); |
664 | if (!fw) | 687 | if (!fw) |
@@ -669,7 +692,7 @@ ip2_loadmain(int *iop, int *irqp) | |||
669 | if (fw) | 692 | if (fw) |
670 | release_firmware(fw); | 693 | release_firmware(fw); |
671 | 694 | ||
672 | ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 ); | 695 | ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0); |
673 | 696 | ||
674 | ip2_tty_driver->owner = THIS_MODULE; | 697 | ip2_tty_driver->owner = THIS_MODULE; |
675 | ip2_tty_driver->name = "ttyF"; | 698 | ip2_tty_driver->name = "ttyF"; |
@@ -680,20 +703,23 @@ ip2_loadmain(int *iop, int *irqp) | |||
680 | ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL; | 703 | ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL; |
681 | ip2_tty_driver->init_termios = tty_std_termios; | 704 | ip2_tty_driver->init_termios = tty_std_termios; |
682 | ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; | 705 | ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; |
683 | ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 706 | ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | |
707 | TTY_DRIVER_DYNAMIC_DEV; | ||
684 | tty_set_operations(ip2_tty_driver, &ip2_ops); | 708 | tty_set_operations(ip2_tty_driver, &ip2_ops); |
685 | 709 | ||
686 | ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 ); | 710 | ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0); |
687 | 711 | ||
688 | /* Register the tty devices. */ | 712 | err = tty_register_driver(ip2_tty_driver); |
689 | if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) { | 713 | if (err) { |
690 | printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err); | 714 | printk(KERN_ERR "IP2: failed to register tty driver\n"); |
691 | put_tty_driver(ip2_tty_driver); | 715 | put_tty_driver(ip2_tty_driver); |
692 | return -EINVAL; | 716 | return err; /* leaking resources */ |
693 | } else | 717 | } |
694 | /* Register the IPL driver. */ | 718 | |
695 | if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { | 719 | err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl); |
696 | printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); | 720 | if (err) { |
721 | printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", | ||
722 | err); | ||
697 | } else { | 723 | } else { |
698 | /* create the sysfs class */ | 724 | /* create the sysfs class */ |
699 | ip2_class = class_create(THIS_MODULE, "ip2"); | 725 | ip2_class = class_create(THIS_MODULE, "ip2"); |
@@ -705,84 +731,86 @@ ip2_loadmain(int *iop, int *irqp) | |||
705 | /* Register the read_procmem thing */ | 731 | /* Register the read_procmem thing */ |
706 | if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { | 732 | if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { |
707 | printk(KERN_ERR "IP2: failed to register read_procmem\n"); | 733 | printk(KERN_ERR "IP2: failed to register read_procmem\n"); |
708 | } else { | 734 | return -EIO; /* leaking resources */ |
735 | } | ||
709 | 736 | ||
710 | ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 ); | 737 | ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0); |
711 | /* Register the interrupt handler or poll handler, depending upon the | 738 | /* Register the interrupt handler or poll handler, depending upon the |
712 | * specified interrupt. | 739 | * specified interrupt. |
713 | */ | 740 | */ |
714 | 741 | ||
715 | for( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 742 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
716 | if ( 0 == ip2config.addr[i] ) { | 743 | if (ip2config.addr[i] == 0) |
717 | continue; | 744 | continue; |
718 | } | ||
719 | 745 | ||
720 | if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { | 746 | pB = i2BoardPtrTable[i]; |
721 | device_create_drvdata(ip2_class, NULL, | 747 | if (pB != NULL) { |
722 | MKDEV(IP2_IPL_MAJOR, 4 * i), | 748 | device_create_drvdata(ip2_class, NULL, |
723 | NULL, "ipl%d", i); | 749 | MKDEV(IP2_IPL_MAJOR, 4 * i), |
724 | device_create_drvdata(ip2_class, NULL, | 750 | NULL, "ipl%d", i); |
725 | MKDEV(IP2_IPL_MAJOR, 4 * i + 1), | 751 | device_create_drvdata(ip2_class, NULL, |
726 | NULL, "stat%d", i); | 752 | MKDEV(IP2_IPL_MAJOR, 4 * i + 1), |
727 | 753 | NULL, "stat%d", i); | |
728 | for ( box = 0; box < ABS_MAX_BOXES; ++box ) | 754 | |
729 | { | 755 | for (box = 0; box < ABS_MAX_BOXES; box++) |
730 | for ( j = 0; j < ABS_BIGGEST_BOX; ++j ) | 756 | for (j = 0; j < ABS_BIGGEST_BOX; j++) |
731 | { | 757 | if (pB->i2eChannelMap[box] & (1 << j)) |
732 | if ( pB->i2eChannelMap[box] & (1 << j) ) | 758 | tty_register_device( |
733 | { | 759 | ip2_tty_driver, |
734 | tty_register_device(ip2_tty_driver, | 760 | j + ABS_BIGGEST_BOX * |
735 | j + ABS_BIGGEST_BOX * | 761 | (box+i*ABS_MAX_BOXES), |
736 | (box+i*ABS_MAX_BOXES), NULL); | 762 | NULL); |
737 | } | 763 | } |
738 | } | ||
739 | } | ||
740 | } | ||
741 | 764 | ||
742 | if (poll_only) { | 765 | if (poll_only) { |
743 | // Poll only forces driver to only use polling and | 766 | /* Poll only forces driver to only use polling and |
744 | // to ignore the probed PCI or EISA interrupts. | 767 | to ignore the probed PCI or EISA interrupts. */ |
745 | ip2config.irq[i] = CIR_POLL; | 768 | ip2config.irq[i] = CIR_POLL; |
746 | } | 769 | } |
747 | if ( ip2config.irq[i] == CIR_POLL ) { | 770 | if (ip2config.irq[i] == CIR_POLL) { |
748 | retry: | 771 | retry: |
749 | if (!TimerOn) { | 772 | if (!timer_pending(&PollTimer)) { |
750 | PollTimer.expires = POLL_TIMEOUT; | 773 | mod_timer(&PollTimer, POLL_TIMEOUT); |
751 | add_timer ( &PollTimer ); | 774 | printk(KERN_INFO "IP2: polling\n"); |
752 | TimerOn = 1; | ||
753 | printk( KERN_INFO "IP2: polling\n"); | ||
754 | } | ||
755 | } else { | ||
756 | if (have_requested_irq(ip2config.irq[i])) | ||
757 | continue; | ||
758 | rc = request_irq( ip2config.irq[i], ip2_interrupt, | ||
759 | IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0), | ||
760 | pcName, i2BoardPtrTable[i]); | ||
761 | if (rc) { | ||
762 | printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc); | ||
763 | ip2config.irq[i] = CIR_POLL; | ||
764 | printk( KERN_INFO "IP2: Polling %ld/sec.\n", | ||
765 | (POLL_TIMEOUT - jiffies)); | ||
766 | goto retry; | ||
767 | } | ||
768 | mark_requested_irq(ip2config.irq[i]); | ||
769 | /* Initialise the interrupt handler bottom half (aka slih). */ | ||
770 | } | 775 | } |
771 | } | 776 | } else { |
772 | for( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 777 | if (have_requested_irq(ip2config.irq[i])) |
773 | if ( i2BoardPtrTable[i] ) { | 778 | continue; |
774 | set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */ | 779 | rc = request_irq(ip2config.irq[i], ip2_interrupt, |
780 | IP2_SA_FLAGS | | ||
781 | (ip2config.type[i] == PCI ? IRQF_SHARED : 0), | ||
782 | pcName, i2BoardPtrTable[i]); | ||
783 | if (rc) { | ||
784 | printk(KERN_ERR "IP2: request_irq failed: " | ||
785 | "error %d\n", rc); | ||
786 | ip2config.irq[i] = CIR_POLL; | ||
787 | printk(KERN_INFO "IP2: Polling %ld/sec.\n", | ||
788 | (POLL_TIMEOUT - jiffies)); | ||
789 | goto retry; | ||
775 | } | 790 | } |
791 | mark_requested_irq(ip2config.irq[i]); | ||
792 | /* Initialise the interrupt handler bottom half | ||
793 | * (aka slih). */ | ||
776 | } | 794 | } |
777 | } | 795 | } |
778 | ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 ); | 796 | |
779 | goto out; | 797 | for (i = 0; i < IP2_MAX_BOARDS; ++i) { |
798 | if (i2BoardPtrTable[i]) { | ||
799 | /* set and enable board interrupt */ | ||
800 | set_irq(i, ip2config.irq[i]); | ||
801 | } | ||
802 | } | ||
803 | |||
804 | ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0); | ||
805 | |||
806 | return 0; | ||
780 | 807 | ||
781 | out_chrdev: | 808 | out_chrdev: |
782 | unregister_chrdev(IP2_IPL_MAJOR, "ip2"); | 809 | unregister_chrdev(IP2_IPL_MAJOR, "ip2"); |
783 | out: | 810 | /* unregister and put tty here */ |
784 | return err; | 811 | return err; |
785 | } | 812 | } |
813 | module_init(ip2_loadmain); | ||
786 | 814 | ||
787 | /******************************************************************************/ | 815 | /******************************************************************************/ |
788 | /* Function: ip2_init_board() */ | 816 | /* Function: ip2_init_board() */ |
@@ -1199,9 +1227,8 @@ ip2_polled_interrupt(void) | |||
1199 | { | 1227 | { |
1200 | int i; | 1228 | int i; |
1201 | i2eBordStrPtr pB; | 1229 | i2eBordStrPtr pB; |
1202 | const int irq = 0; | ||
1203 | 1230 | ||
1204 | ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq ); | 1231 | ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0); |
1205 | 1232 | ||
1206 | /* Service just the boards on the list using this irq */ | 1233 | /* Service just the boards on the list using this irq */ |
1207 | for( i = 0; i < i2nBoards; ++i ) { | 1234 | for( i = 0; i < i2nBoards; ++i ) { |
@@ -1210,9 +1237,8 @@ ip2_polled_interrupt(void) | |||
1210 | // Only process those boards which match our IRQ. | 1237 | // Only process those boards which match our IRQ. |
1211 | // IRQ = 0 for polled boards, we won't poll "IRQ" boards | 1238 | // IRQ = 0 for polled boards, we won't poll "IRQ" boards |
1212 | 1239 | ||
1213 | if ( pB && (pB->i2eUsingIrq == irq) ) { | 1240 | if (pB && pB->i2eUsingIrq == 0) |
1214 | ip2_irq_work(pB); | 1241 | ip2_irq_work(pB); |
1215 | } | ||
1216 | } | 1242 | } |
1217 | 1243 | ||
1218 | ++irq_counter; | 1244 | ++irq_counter; |
@@ -1250,16 +1276,12 @@ ip2_poll(unsigned long arg) | |||
1250 | { | 1276 | { |
1251 | ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 ); | 1277 | ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 ); |
1252 | 1278 | ||
1253 | TimerOn = 0; // it's the truth but not checked in service | ||
1254 | |||
1255 | // Just polled boards, IRQ = 0 will hit all non-interrupt boards. | 1279 | // Just polled boards, IRQ = 0 will hit all non-interrupt boards. |
1256 | // It will NOT poll boards handled by hard interrupts. | 1280 | // It will NOT poll boards handled by hard interrupts. |
1257 | // The issue of queued BH interrupts is handled in ip2_interrupt(). | 1281 | // The issue of queued BH interrupts is handled in ip2_interrupt(). |
1258 | ip2_polled_interrupt(); | 1282 | ip2_polled_interrupt(); |
1259 | 1283 | ||
1260 | PollTimer.expires = POLL_TIMEOUT; | 1284 | mod_timer(&PollTimer, POLL_TIMEOUT); |
1261 | add_timer( &PollTimer ); | ||
1262 | TimerOn = 1; | ||
1263 | 1285 | ||
1264 | ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); | 1286 | ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); |
1265 | } | 1287 | } |
@@ -2871,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) | |||
2871 | case 13: | 2893 | case 13: |
2872 | switch ( cmd ) { | 2894 | switch ( cmd ) { |
2873 | case 64: /* Driver - ip2stat */ | 2895 | case 64: /* Driver - ip2stat */ |
2874 | rc = put_user(ip2_tty_driver->refcount, pIndex++ ); | 2896 | rc = put_user(-1, pIndex++ ); |
2875 | rc = put_user(irq_counter, pIndex++ ); | 2897 | rc = put_user(irq_counter, pIndex++ ); |
2876 | rc = put_user(bh_counter, pIndex++ ); | 2898 | rc = put_user(bh_counter, pIndex++ ); |
2877 | break; | 2899 | break; |
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 8f7cc190b62d..7d30ee1d3fca 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data) | |||
421 | if (retries >= 100) | 421 | if (retries >= 100) |
422 | goto unlock; | 422 | goto unlock; |
423 | 423 | ||
424 | tty = tty_port_tty_get(&port->port); | ||
425 | if (tty == NULL) | ||
426 | goto put_unlock; | ||
427 | |||
424 | for (; count > 0; count--, port++) { | 428 | for (; count > 0; count--, port++) { |
425 | /* port not active or tx disabled to force flow control */ | 429 | /* port not active or tx disabled to force flow control */ |
426 | if (!(port->port.flags & ASYNC_INITIALIZED) || | 430 | if (!(port->port.flags & ASYNC_INITIALIZED) || |
427 | !(port->status & ISI_TXOK)) | 431 | !(port->status & ISI_TXOK)) |
428 | continue; | 432 | continue; |
429 | 433 | ||
430 | tty = port->port.tty; | ||
431 | |||
432 | if (tty == NULL) | ||
433 | continue; | ||
434 | |||
435 | txcount = min_t(short, TX_SIZE, port->xmit_cnt); | 434 | txcount = min_t(short, TX_SIZE, port->xmit_cnt); |
436 | if (txcount <= 0 || tty->stopped || tty->hw_stopped) | 435 | if (txcount <= 0 || tty->stopped || tty->hw_stopped) |
437 | continue; | 436 | continue; |
@@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data) | |||
489 | tty_wakeup(tty); | 488 | tty_wakeup(tty); |
490 | } | 489 | } |
491 | 490 | ||
491 | put_unlock: | ||
492 | tty_kref_put(tty); | ||
492 | unlock: | 493 | unlock: |
493 | spin_unlock_irqrestore(&isi_card[card].card_lock, flags); | 494 | spin_unlock_irqrestore(&isi_card[card].card_lock, flags); |
494 | /* schedule another tx for hopefully in about 10ms */ | 495 | /* schedule another tx for hopefully in about 10ms */ |
@@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
547 | return IRQ_HANDLED; | 548 | return IRQ_HANDLED; |
548 | } | 549 | } |
549 | 550 | ||
550 | tty = port->port.tty; | 551 | tty = tty_port_tty_get(&port->port); |
551 | if (tty == NULL) { | 552 | if (tty == NULL) { |
552 | word_count = byte_count >> 1; | 553 | word_count = byte_count >> 1; |
553 | while (byte_count > 1) { | 554 | while (byte_count > 1) { |
@@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
588 | } | 589 | } |
589 | 590 | ||
590 | if (port->port.flags & ASYNC_CTS_FLOW) { | 591 | if (port->port.flags & ASYNC_CTS_FLOW) { |
591 | if (port->port.tty->hw_stopped) { | 592 | if (tty->hw_stopped) { |
592 | if (header & ISI_CTS) { | 593 | if (header & ISI_CTS) { |
593 | port->port.tty->hw_stopped = 0; | 594 | port->port.tty->hw_stopped = 0; |
594 | /* start tx ing */ | 595 | /* start tx ing */ |
@@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
597 | tty_wakeup(tty); | 598 | tty_wakeup(tty); |
598 | } | 599 | } |
599 | } else if (!(header & ISI_CTS)) { | 600 | } else if (!(header & ISI_CTS)) { |
600 | port->port.tty->hw_stopped = 1; | 601 | tty->hw_stopped = 1; |
601 | /* stop tx ing */ | 602 | /* stop tx ing */ |
602 | port->status &= ~(ISI_TXOK | ISI_CTS); | 603 | port->status &= ~(ISI_TXOK | ISI_CTS); |
603 | } | 604 | } |
@@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) | |||
660 | } | 661 | } |
661 | outw(0x0000, base+0x04); /* enable interrupts */ | 662 | outw(0x0000, base+0x04); /* enable interrupts */ |
662 | spin_unlock(&card->card_lock); | 663 | spin_unlock(&card->card_lock); |
664 | tty_kref_put(tty); | ||
663 | 665 | ||
664 | return IRQ_HANDLED; | 666 | return IRQ_HANDLED; |
665 | } | 667 | } |
666 | 668 | ||
667 | static void isicom_config_port(struct isi_port *port) | 669 | static void isicom_config_port(struct tty_struct *tty) |
668 | { | 670 | { |
671 | struct isi_port *port = tty->driver_data; | ||
669 | struct isi_board *card = port->card; | 672 | struct isi_board *card = port->card; |
670 | struct tty_struct *tty; | ||
671 | unsigned long baud; | 673 | unsigned long baud; |
672 | unsigned long base = card->base; | 674 | unsigned long base = card->base; |
673 | u16 channel_setup, channel = port->channel, | 675 | u16 channel_setup, channel = port->channel, |
674 | shift_count = card->shift_count; | 676 | shift_count = card->shift_count; |
675 | unsigned char flow_ctrl; | 677 | unsigned char flow_ctrl; |
676 | 678 | ||
677 | tty = port->port.tty; | ||
678 | |||
679 | if (tty == NULL) | ||
680 | return; | ||
681 | /* FIXME: Switch to new tty baud API */ | 679 | /* FIXME: Switch to new tty baud API */ |
682 | baud = C_BAUD(tty); | 680 | baud = C_BAUD(tty); |
683 | if (baud & CBAUDEX) { | 681 | if (baud & CBAUDEX) { |
@@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port) | |||
690 | 688 | ||
691 | /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ | 689 | /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ |
692 | if (baud < 1 || baud > 4) | 690 | if (baud < 1 || baud > 4) |
693 | port->port.tty->termios->c_cflag &= ~CBAUDEX; | 691 | tty->termios->c_cflag &= ~CBAUDEX; |
694 | else | 692 | else |
695 | baud += 15; | 693 | baud += 15; |
696 | } | 694 | } |
@@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp) | |||
797 | spin_unlock_irqrestore(&bp->card_lock, flags); | 795 | spin_unlock_irqrestore(&bp->card_lock, flags); |
798 | } | 796 | } |
799 | 797 | ||
800 | static int isicom_setup_port(struct isi_port *port) | 798 | static int isicom_setup_port(struct tty_struct *tty) |
801 | { | 799 | { |
800 | struct isi_port *port = tty->driver_data; | ||
802 | struct isi_board *card = port->card; | 801 | struct isi_board *card = port->card; |
803 | unsigned long flags; | 802 | unsigned long flags; |
804 | 803 | ||
@@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port) | |||
808 | return -ENOMEM; | 807 | return -ENOMEM; |
809 | 808 | ||
810 | spin_lock_irqsave(&card->card_lock, flags); | 809 | spin_lock_irqsave(&card->card_lock, flags); |
811 | if (port->port.tty) | 810 | clear_bit(TTY_IO_ERROR, &tty->flags); |
812 | clear_bit(TTY_IO_ERROR, &port->port.tty->flags); | ||
813 | if (port->port.count == 1) | 811 | if (port->port.count == 1) |
814 | card->count++; | 812 | card->count++; |
815 | 813 | ||
@@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port) | |||
823 | InterruptTheCard(card->base); | 821 | InterruptTheCard(card->base); |
824 | } | 822 | } |
825 | 823 | ||
826 | isicom_config_port(port); | 824 | isicom_config_port(tty); |
827 | port->port.flags |= ASYNC_INITIALIZED; | 825 | port->port.flags |= ASYNC_INITIALIZED; |
828 | spin_unlock_irqrestore(&card->card_lock, flags); | 826 | spin_unlock_irqrestore(&card->card_lock, flags); |
829 | 827 | ||
@@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) | |||
934 | 932 | ||
935 | port->port.count++; | 933 | port->port.count++; |
936 | tty->driver_data = port; | 934 | tty->driver_data = port; |
937 | port->port.tty = tty; | 935 | tty_port_tty_set(&port->port, tty); |
938 | error = isicom_setup_port(port); | 936 | error = isicom_setup_port(tty); |
939 | if (error == 0) | 937 | if (error == 0) |
940 | error = block_til_ready(tty, filp, port); | 938 | error = block_til_ready(tty, filp, port); |
941 | return error; | 939 | return error; |
@@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port) | |||
955 | struct isi_board *card = port->card; | 953 | struct isi_board *card = port->card; |
956 | struct tty_struct *tty; | 954 | struct tty_struct *tty; |
957 | 955 | ||
958 | tty = port->port.tty; | 956 | tty = tty_port_tty_get(&port->port); |
959 | 957 | ||
960 | if (!(port->port.flags & ASYNC_INITIALIZED)) | 958 | if (!(port->port.flags & ASYNC_INITIALIZED)) { |
959 | tty_kref_put(tty); | ||
961 | return; | 960 | return; |
961 | } | ||
962 | 962 | ||
963 | tty_port_free_xmit_buf(&port->port); | 963 | tty_port_free_xmit_buf(&port->port); |
964 | port->port.flags &= ~ASYNC_INITIALIZED; | 964 | port->port.flags &= ~ASYNC_INITIALIZED; |
965 | /* 3rd October 2000 : Vinayak P Risbud */ | 965 | /* 3rd October 2000 : Vinayak P Risbud */ |
966 | port->port.tty = NULL; | 966 | tty_port_tty_set(&port->port, NULL); |
967 | 967 | ||
968 | /*Fix done by Anil .S on 30-04-2001 | 968 | /*Fix done by Anil .S on 30-04-2001 |
969 | remote login through isi port has dtr toggle problem | 969 | remote login through isi port has dtr toggle problem |
@@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file, | |||
1243 | return 0; | 1243 | return 0; |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | static int isicom_set_serial_info(struct isi_port *port, | 1246 | static int isicom_set_serial_info(struct tty_struct *tty, |
1247 | struct serial_struct __user *info) | 1247 | struct serial_struct __user *info) |
1248 | { | 1248 | { |
1249 | struct isi_port *port = tty->driver_data; | ||
1249 | struct serial_struct newinfo; | 1250 | struct serial_struct newinfo; |
1250 | int reconfig_port; | 1251 | int reconfig_port; |
1251 | 1252 | ||
@@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port, | |||
1276 | if (reconfig_port) { | 1277 | if (reconfig_port) { |
1277 | unsigned long flags; | 1278 | unsigned long flags; |
1278 | spin_lock_irqsave(&port->card->card_lock, flags); | 1279 | spin_lock_irqsave(&port->card->card_lock, flags); |
1279 | isicom_config_port(port); | 1280 | isicom_config_port(tty); |
1280 | spin_unlock_irqrestore(&port->card->card_lock, flags); | 1281 | spin_unlock_irqrestore(&port->card->card_lock, flags); |
1281 | } | 1282 | } |
1282 | unlock_kernel(); | 1283 | unlock_kernel(); |
@@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, | |||
1318 | return isicom_get_serial_info(port, argp); | 1319 | return isicom_get_serial_info(port, argp); |
1319 | 1320 | ||
1320 | case TIOCSSERIAL: | 1321 | case TIOCSSERIAL: |
1321 | return isicom_set_serial_info(port, argp); | 1322 | return isicom_set_serial_info(tty, argp); |
1322 | 1323 | ||
1323 | default: | 1324 | default: |
1324 | return -ENOIOCTLCMD; | 1325 | return -ENOIOCTLCMD; |
@@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty, | |||
1341 | return; | 1342 | return; |
1342 | 1343 | ||
1343 | spin_lock_irqsave(&port->card->card_lock, flags); | 1344 | spin_lock_irqsave(&port->card->card_lock, flags); |
1344 | isicom_config_port(port); | 1345 | isicom_config_port(tty); |
1345 | spin_unlock_irqrestore(&port->card->card_lock, flags); | 1346 | spin_unlock_irqrestore(&port->card->card_lock, flags); |
1346 | 1347 | ||
1347 | if ((old_termios->c_cflag & CRTSCTS) && | 1348 | if ((old_termios->c_cflag & CRTSCTS) && |
@@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty) | |||
1419 | 1420 | ||
1420 | port->port.count = 0; | 1421 | port->port.count = 0; |
1421 | port->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1422 | port->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
1422 | port->port.tty = NULL; | 1423 | tty_port_tty_set(&port->port, NULL); |
1423 | wake_up_interruptible(&port->port.open_wait); | 1424 | wake_up_interruptible(&port->port.open_wait); |
1424 | } | 1425 | } |
1425 | 1426 | ||
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 843a2afaf204..505d7a1f6b8c 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c | |||
@@ -623,24 +623,25 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un | |||
623 | static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp); | 623 | static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp); |
624 | static void stli_poll(unsigned long arg); | 624 | static void stli_poll(unsigned long arg); |
625 | static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp); | 625 | static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp); |
626 | static int stli_initopen(struct stlibrd *brdp, struct stliport *portp); | 626 | static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp); |
627 | static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); | 627 | static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); |
628 | static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); | 628 | static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); |
629 | static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp); | 629 | static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, |
630 | static int stli_setport(struct stliport *portp); | 630 | struct stliport *portp, struct file *filp); |
631 | static int stli_setport(struct tty_struct *tty); | ||
631 | static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); | 632 | static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); |
632 | static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); | 633 | static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); |
633 | static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); | 634 | static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); |
634 | static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp); | 635 | static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp); |
635 | static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); | 636 | static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); |
636 | static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); | 637 | static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); |
637 | static long stli_mktiocm(unsigned long sigvalue); | 638 | static long stli_mktiocm(unsigned long sigvalue); |
638 | static void stli_read(struct stlibrd *brdp, struct stliport *portp); | 639 | static void stli_read(struct stlibrd *brdp, struct stliport *portp); |
639 | static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp); | 640 | static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp); |
640 | static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp); | 641 | static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp); |
641 | static int stli_getbrdstats(combrd_t __user *bp); | 642 | static int stli_getbrdstats(combrd_t __user *bp); |
642 | static int stli_getportstats(struct stliport *portp, comstats_t __user *cp); | 643 | static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp); |
643 | static int stli_portcmdstats(struct stliport *portp); | 644 | static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp); |
644 | static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp); | 645 | static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp); |
645 | static int stli_getportstruct(struct stliport __user *arg); | 646 | static int stli_getportstruct(struct stliport __user *arg); |
646 | static int stli_getbrdstruct(struct stlibrd __user *arg); | 647 | static int stli_getbrdstruct(struct stlibrd __user *arg); |
@@ -731,12 +732,16 @@ static void stli_cleanup_ports(struct stlibrd *brdp) | |||
731 | { | 732 | { |
732 | struct stliport *portp; | 733 | struct stliport *portp; |
733 | unsigned int j; | 734 | unsigned int j; |
735 | struct tty_struct *tty; | ||
734 | 736 | ||
735 | for (j = 0; j < STL_MAXPORTS; j++) { | 737 | for (j = 0; j < STL_MAXPORTS; j++) { |
736 | portp = brdp->ports[j]; | 738 | portp = brdp->ports[j]; |
737 | if (portp != NULL) { | 739 | if (portp != NULL) { |
738 | if (portp->port.tty != NULL) | 740 | tty = tty_port_tty_get(&portp->port); |
739 | tty_hangup(portp->port.tty); | 741 | if (tty != NULL) { |
742 | tty_hangup(tty); | ||
743 | tty_kref_put(tty); | ||
744 | } | ||
740 | kfree(portp); | 745 | kfree(portp); |
741 | } | 746 | } |
742 | } | 747 | } |
@@ -824,7 +829,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) | |||
824 | * requires several commands to the board we will need to wait for any | 829 | * requires several commands to the board we will need to wait for any |
825 | * other open that is already initializing the port. | 830 | * other open that is already initializing the port. |
826 | */ | 831 | */ |
827 | portp->port.tty = tty; | 832 | tty_port_tty_set(&portp->port, tty); |
828 | tty->driver_data = portp; | 833 | tty->driver_data = portp; |
829 | portp->port.count++; | 834 | portp->port.count++; |
830 | 835 | ||
@@ -835,7 +840,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) | |||
835 | 840 | ||
836 | if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { | 841 | if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { |
837 | set_bit(ST_INITIALIZING, &portp->state); | 842 | set_bit(ST_INITIALIZING, &portp->state); |
838 | if ((rc = stli_initopen(brdp, portp)) >= 0) { | 843 | if ((rc = stli_initopen(tty, brdp, portp)) >= 0) { |
839 | portp->port.flags |= ASYNC_INITIALIZED; | 844 | portp->port.flags |= ASYNC_INITIALIZED; |
840 | clear_bit(TTY_IO_ERROR, &tty->flags); | 845 | clear_bit(TTY_IO_ERROR, &tty->flags); |
841 | } | 846 | } |
@@ -864,7 +869,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) | |||
864 | * then also we might have to wait for carrier. | 869 | * then also we might have to wait for carrier. |
865 | */ | 870 | */ |
866 | if (!(filp->f_flags & O_NONBLOCK)) { | 871 | if (!(filp->f_flags & O_NONBLOCK)) { |
867 | if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) | 872 | if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0) |
868 | return rc; | 873 | return rc; |
869 | } | 874 | } |
870 | portp->port.flags |= ASYNC_NORMAL_ACTIVE; | 875 | portp->port.flags |= ASYNC_NORMAL_ACTIVE; |
@@ -930,7 +935,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) | |||
930 | stli_flushbuffer(tty); | 935 | stli_flushbuffer(tty); |
931 | 936 | ||
932 | tty->closing = 0; | 937 | tty->closing = 0; |
933 | portp->port.tty = NULL; | 938 | tty_port_tty_set(&portp->port, NULL); |
934 | 939 | ||
935 | if (portp->openwaitcnt) { | 940 | if (portp->openwaitcnt) { |
936 | if (portp->close_delay) | 941 | if (portp->close_delay) |
@@ -952,9 +957,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp) | |||
952 | * this still all happens pretty quickly. | 957 | * this still all happens pretty quickly. |
953 | */ | 958 | */ |
954 | 959 | ||
955 | static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) | 960 | static int stli_initopen(struct tty_struct *tty, |
961 | struct stlibrd *brdp, struct stliport *portp) | ||
956 | { | 962 | { |
957 | struct tty_struct *tty; | ||
958 | asynotify_t nt; | 963 | asynotify_t nt; |
959 | asyport_t aport; | 964 | asyport_t aport; |
960 | int rc; | 965 | int rc; |
@@ -969,10 +974,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) | |||
969 | sizeof(asynotify_t), 0)) < 0) | 974 | sizeof(asynotify_t), 0)) < 0) |
970 | return rc; | 975 | return rc; |
971 | 976 | ||
972 | tty = portp->port.tty; | 977 | stli_mkasyport(tty, portp, &aport, tty->termios); |
973 | if (tty == NULL) | ||
974 | return -ENODEV; | ||
975 | stli_mkasyport(portp, &aport, tty->termios); | ||
976 | if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, | 978 | if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, |
977 | sizeof(asyport_t), 0)) < 0) | 979 | sizeof(asyport_t), 0)) < 0) |
978 | return rc; | 980 | return rc; |
@@ -1161,22 +1163,21 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l | |||
1161 | * waiting for the command to complete - so must have user context. | 1163 | * waiting for the command to complete - so must have user context. |
1162 | */ | 1164 | */ |
1163 | 1165 | ||
1164 | static int stli_setport(struct stliport *portp) | 1166 | static int stli_setport(struct tty_struct *tty) |
1165 | { | 1167 | { |
1168 | struct stliport *portp = tty->driver_data; | ||
1166 | struct stlibrd *brdp; | 1169 | struct stlibrd *brdp; |
1167 | asyport_t aport; | 1170 | asyport_t aport; |
1168 | 1171 | ||
1169 | if (portp == NULL) | 1172 | if (portp == NULL) |
1170 | return -ENODEV; | 1173 | return -ENODEV; |
1171 | if (portp->port.tty == NULL) | ||
1172 | return -ENODEV; | ||
1173 | if (portp->brdnr >= stli_nrbrds) | 1174 | if (portp->brdnr >= stli_nrbrds) |
1174 | return -ENODEV; | 1175 | return -ENODEV; |
1175 | brdp = stli_brds[portp->brdnr]; | 1176 | brdp = stli_brds[portp->brdnr]; |
1176 | if (brdp == NULL) | 1177 | if (brdp == NULL) |
1177 | return -ENODEV; | 1178 | return -ENODEV; |
1178 | 1179 | ||
1179 | stli_mkasyport(portp, &aport, portp->port.tty->termios); | 1180 | stli_mkasyport(tty, portp, &aport, tty->termios); |
1180 | return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)); | 1181 | return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)); |
1181 | } | 1182 | } |
1182 | 1183 | ||
@@ -1187,7 +1188,8 @@ static int stli_setport(struct stliport *portp) | |||
1187 | * maybe because if we are clocal then we don't need to wait... | 1188 | * maybe because if we are clocal then we don't need to wait... |
1188 | */ | 1189 | */ |
1189 | 1190 | ||
1190 | static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp) | 1191 | static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, |
1192 | struct stliport *portp, struct file *filp) | ||
1191 | { | 1193 | { |
1192 | unsigned long flags; | 1194 | unsigned long flags; |
1193 | int rc, doclocal; | 1195 | int rc, doclocal; |
@@ -1195,7 +1197,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct | |||
1195 | rc = 0; | 1197 | rc = 0; |
1196 | doclocal = 0; | 1198 | doclocal = 0; |
1197 | 1199 | ||
1198 | if (portp->port.tty->termios->c_cflag & CLOCAL) | 1200 | if (tty->termios->c_cflag & CLOCAL) |
1199 | doclocal++; | 1201 | doclocal++; |
1200 | 1202 | ||
1201 | spin_lock_irqsave(&stli_lock, flags); | 1203 | spin_lock_irqsave(&stli_lock, flags); |
@@ -1373,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty) | |||
1373 | stli_txcookrealsize = 0; | 1375 | stli_txcookrealsize = 0; |
1374 | stli_txcooktty = NULL; | 1376 | stli_txcooktty = NULL; |
1375 | 1377 | ||
1376 | if (tty == NULL) | ||
1377 | return; | ||
1378 | if (cooktty == NULL) | 1378 | if (cooktty == NULL) |
1379 | return; | 1379 | return; |
1380 | if (tty != cooktty) | 1380 | if (tty != cooktty) |
@@ -1572,10 +1572,11 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s | |||
1572 | * just quietly ignore any requests to change irq, etc. | 1572 | * just quietly ignore any requests to change irq, etc. |
1573 | */ | 1573 | */ |
1574 | 1574 | ||
1575 | static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp) | 1575 | static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp) |
1576 | { | 1576 | { |
1577 | struct serial_struct sio; | 1577 | struct serial_struct sio; |
1578 | int rc; | 1578 | int rc; |
1579 | struct stliport *portp = tty->driver_data; | ||
1579 | 1580 | ||
1580 | if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) | 1581 | if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) |
1581 | return -EFAULT; | 1582 | return -EFAULT; |
@@ -1594,7 +1595,7 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s | |||
1594 | portp->closing_wait = sio.closing_wait; | 1595 | portp->closing_wait = sio.closing_wait; |
1595 | portp->custom_divisor = sio.custom_divisor; | 1596 | portp->custom_divisor = sio.custom_divisor; |
1596 | 1597 | ||
1597 | if ((rc = stli_setport(portp)) < 0) | 1598 | if ((rc = stli_setport(tty)) < 0) |
1598 | return rc; | 1599 | return rc; |
1599 | return 0; | 1600 | return 0; |
1600 | } | 1601 | } |
@@ -1685,17 +1686,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm | |||
1685 | rc = stli_getserial(portp, argp); | 1686 | rc = stli_getserial(portp, argp); |
1686 | break; | 1687 | break; |
1687 | case TIOCSSERIAL: | 1688 | case TIOCSSERIAL: |
1688 | rc = stli_setserial(portp, argp); | 1689 | rc = stli_setserial(tty, argp); |
1689 | break; | 1690 | break; |
1690 | case STL_GETPFLAG: | 1691 | case STL_GETPFLAG: |
1691 | rc = put_user(portp->pflag, (unsigned __user *)argp); | 1692 | rc = put_user(portp->pflag, (unsigned __user *)argp); |
1692 | break; | 1693 | break; |
1693 | case STL_SETPFLAG: | 1694 | case STL_SETPFLAG: |
1694 | if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0) | 1695 | if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0) |
1695 | stli_setport(portp); | 1696 | stli_setport(tty); |
1696 | break; | 1697 | break; |
1697 | case COM_GETPORTSTATS: | 1698 | case COM_GETPORTSTATS: |
1698 | rc = stli_getportstats(portp, argp); | 1699 | rc = stli_getportstats(tty, portp, argp); |
1699 | break; | 1700 | break; |
1700 | case COM_CLRPORTSTATS: | 1701 | case COM_CLRPORTSTATS: |
1701 | rc = stli_clrportstats(portp, argp); | 1702 | rc = stli_clrportstats(portp, argp); |
@@ -1729,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) | |||
1729 | struct ktermios *tiosp; | 1730 | struct ktermios *tiosp; |
1730 | asyport_t aport; | 1731 | asyport_t aport; |
1731 | 1732 | ||
1732 | if (tty == NULL) | ||
1733 | return; | ||
1734 | portp = tty->driver_data; | 1733 | portp = tty->driver_data; |
1735 | if (portp == NULL) | 1734 | if (portp == NULL) |
1736 | return; | 1735 | return; |
@@ -1742,7 +1741,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) | |||
1742 | 1741 | ||
1743 | tiosp = tty->termios; | 1742 | tiosp = tty->termios; |
1744 | 1743 | ||
1745 | stli_mkasyport(portp, &aport, tiosp); | 1744 | stli_mkasyport(tty, portp, &aport, tiosp); |
1746 | stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); | 1745 | stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); |
1747 | stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1); | 1746 | stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1); |
1748 | stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, | 1747 | stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, |
@@ -1854,7 +1853,7 @@ static void stli_hangup(struct tty_struct *tty) | |||
1854 | clear_bit(ST_TXBUSY, &portp->state); | 1853 | clear_bit(ST_TXBUSY, &portp->state); |
1855 | clear_bit(ST_RXSTOP, &portp->state); | 1854 | clear_bit(ST_RXSTOP, &portp->state); |
1856 | set_bit(TTY_IO_ERROR, &tty->flags); | 1855 | set_bit(TTY_IO_ERROR, &tty->flags); |
1857 | portp->port.tty = NULL; | 1856 | tty_port_tty_set(&portp->port, NULL); |
1858 | portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1857 | portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
1859 | portp->port.count = 0; | 1858 | portp->port.count = 0; |
1860 | spin_unlock_irqrestore(&stli_lock, flags); | 1859 | spin_unlock_irqrestore(&stli_lock, flags); |
@@ -1935,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout) | |||
1935 | struct stliport *portp; | 1934 | struct stliport *portp; |
1936 | unsigned long tend; | 1935 | unsigned long tend; |
1937 | 1936 | ||
1938 | if (tty == NULL) | ||
1939 | return; | ||
1940 | portp = tty->driver_data; | 1937 | portp = tty->driver_data; |
1941 | if (portp == NULL) | 1938 | if (portp == NULL) |
1942 | return; | 1939 | return; |
@@ -1998,7 +1995,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn | |||
1998 | char *sp, *uart; | 1995 | char *sp, *uart; |
1999 | int rc, cnt; | 1996 | int rc, cnt; |
2000 | 1997 | ||
2001 | rc = stli_portcmdstats(portp); | 1998 | rc = stli_portcmdstats(NULL, portp); |
2002 | 1999 | ||
2003 | uart = "UNKNOWN"; | 2000 | uart = "UNKNOWN"; |
2004 | if (brdp->state & BST_STARTED) { | 2001 | if (brdp->state & BST_STARTED) { |
@@ -2188,7 +2185,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) | |||
2188 | 2185 | ||
2189 | if (test_bit(ST_RXSTOP, &portp->state)) | 2186 | if (test_bit(ST_RXSTOP, &portp->state)) |
2190 | return; | 2187 | return; |
2191 | tty = portp->port.tty; | 2188 | tty = tty_port_tty_get(&portp->port); |
2192 | if (tty == NULL) | 2189 | if (tty == NULL) |
2193 | return; | 2190 | return; |
2194 | 2191 | ||
@@ -2230,6 +2227,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) | |||
2230 | set_bit(ST_RXING, &portp->state); | 2227 | set_bit(ST_RXING, &portp->state); |
2231 | 2228 | ||
2232 | tty_schedule_flip(tty); | 2229 | tty_schedule_flip(tty); |
2230 | tty_kref_put(tty); | ||
2233 | } | 2231 | } |
2234 | 2232 | ||
2235 | /*****************************************************************************/ | 2233 | /*****************************************************************************/ |
@@ -2362,7 +2360,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) | |||
2362 | if (ap->notify) { | 2360 | if (ap->notify) { |
2363 | nt = ap->changed; | 2361 | nt = ap->changed; |
2364 | ap->notify = 0; | 2362 | ap->notify = 0; |
2365 | tty = portp->port.tty; | 2363 | tty = tty_port_tty_get(&portp->port); |
2366 | 2364 | ||
2367 | if (nt.signal & SG_DCD) { | 2365 | if (nt.signal & SG_DCD) { |
2368 | oldsigs = portp->sigs; | 2366 | oldsigs = portp->sigs; |
@@ -2399,6 +2397,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) | |||
2399 | tty_schedule_flip(tty); | 2397 | tty_schedule_flip(tty); |
2400 | } | 2398 | } |
2401 | } | 2399 | } |
2400 | tty_kref_put(tty); | ||
2402 | 2401 | ||
2403 | if (nt.data & DT_RXBUSY) { | 2402 | if (nt.data & DT_RXBUSY) { |
2404 | donerx++; | 2403 | donerx++; |
@@ -2535,14 +2534,15 @@ static void stli_poll(unsigned long arg) | |||
2535 | * the slave. | 2534 | * the slave. |
2536 | */ | 2535 | */ |
2537 | 2536 | ||
2538 | static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp) | 2537 | static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, |
2538 | asyport_t *pp, struct ktermios *tiosp) | ||
2539 | { | 2539 | { |
2540 | memset(pp, 0, sizeof(asyport_t)); | 2540 | memset(pp, 0, sizeof(asyport_t)); |
2541 | 2541 | ||
2542 | /* | 2542 | /* |
2543 | * Start of by setting the baud, char size, parity and stop bit info. | 2543 | * Start of by setting the baud, char size, parity and stop bit info. |
2544 | */ | 2544 | */ |
2545 | pp->baudout = tty_get_baud_rate(portp->port.tty); | 2545 | pp->baudout = tty_get_baud_rate(tty); |
2546 | if ((tiosp->c_cflag & CBAUD) == B38400) { | 2546 | if ((tiosp->c_cflag & CBAUD) == B38400) { |
2547 | if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | 2547 | if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) |
2548 | pp->baudout = 57600; | 2548 | pp->baudout = 57600; |
@@ -2695,7 +2695,7 @@ static int stli_initports(struct stlibrd *brdp) | |||
2695 | printk("STALLION: failed to allocate port structure\n"); | 2695 | printk("STALLION: failed to allocate port structure\n"); |
2696 | continue; | 2696 | continue; |
2697 | } | 2697 | } |
2698 | 2698 | tty_port_init(&portp->port); | |
2699 | portp->magic = STLI_PORTMAGIC; | 2699 | portp->magic = STLI_PORTMAGIC; |
2700 | portp->portnr = i; | 2700 | portp->portnr = i; |
2701 | portp->brdnr = brdp->brdnr; | 2701 | portp->brdnr = brdp->brdnr; |
@@ -4220,7 +4220,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, | |||
4220 | * what port to get stats for (used through board control device). | 4220 | * what port to get stats for (used through board control device). |
4221 | */ | 4221 | */ |
4222 | 4222 | ||
4223 | static int stli_portcmdstats(struct stliport *portp) | 4223 | static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) |
4224 | { | 4224 | { |
4225 | unsigned long flags; | 4225 | unsigned long flags; |
4226 | struct stlibrd *brdp; | 4226 | struct stlibrd *brdp; |
@@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct stliport *portp) | |||
4249 | stli_comstats.flags = portp->port.flags; | 4249 | stli_comstats.flags = portp->port.flags; |
4250 | 4250 | ||
4251 | spin_lock_irqsave(&brd_lock, flags); | 4251 | spin_lock_irqsave(&brd_lock, flags); |
4252 | if (portp->port.tty != NULL) { | 4252 | if (tty != NULL) { |
4253 | if (portp->port.tty->driver_data == portp) { | 4253 | if (portp->port.tty == tty) { |
4254 | stli_comstats.ttystate = portp->port.tty->flags; | 4254 | stli_comstats.ttystate = tty->flags; |
4255 | stli_comstats.rxbuffered = -1; | 4255 | stli_comstats.rxbuffered = -1; |
4256 | if (portp->port.tty->termios != NULL) { | 4256 | if (tty->termios != NULL) { |
4257 | stli_comstats.cflags = portp->port.tty->termios->c_cflag; | 4257 | stli_comstats.cflags = tty->termios->c_cflag; |
4258 | stli_comstats.iflags = portp->port.tty->termios->c_iflag; | 4258 | stli_comstats.iflags = tty->termios->c_iflag; |
4259 | stli_comstats.oflags = portp->port.tty->termios->c_oflag; | 4259 | stli_comstats.oflags = tty->termios->c_oflag; |
4260 | stli_comstats.lflags = portp->port.tty->termios->c_lflag; | 4260 | stli_comstats.lflags = tty->termios->c_lflag; |
4261 | } | 4261 | } |
4262 | } | 4262 | } |
4263 | } | 4263 | } |
@@ -4294,7 +4294,8 @@ static int stli_portcmdstats(struct stliport *portp) | |||
4294 | * what port to get stats for (used through board control device). | 4294 | * what port to get stats for (used through board control device). |
4295 | */ | 4295 | */ |
4296 | 4296 | ||
4297 | static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) | 4297 | static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, |
4298 | comstats_t __user *cp) | ||
4298 | { | 4299 | { |
4299 | struct stlibrd *brdp; | 4300 | struct stlibrd *brdp; |
4300 | int rc; | 4301 | int rc; |
@@ -4312,7 +4313,7 @@ static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) | |||
4312 | if (!brdp) | 4313 | if (!brdp) |
4313 | return -ENODEV; | 4314 | return -ENODEV; |
4314 | 4315 | ||
4315 | if ((rc = stli_portcmdstats(portp)) < 0) | 4316 | if ((rc = stli_portcmdstats(tty, portp)) < 0) |
4316 | return rc; | 4317 | return rc; |
4317 | 4318 | ||
4318 | return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ? | 4319 | return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ? |
@@ -4427,7 +4428,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un | |||
4427 | 4428 | ||
4428 | switch (cmd) { | 4429 | switch (cmd) { |
4429 | case COM_GETPORTSTATS: | 4430 | case COM_GETPORTSTATS: |
4430 | rc = stli_getportstats(NULL, argp); | 4431 | rc = stli_getportstats(NULL, NULL, argp); |
4431 | done++; | 4432 | done++; |
4432 | break; | 4433 | break; |
4433 | case COM_CLRPORTSTATS: | 4434 | case COM_CLRPORTSTATS: |
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index d3d7864e0c1e..5df4003ad873 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, | |||
205 | static void moxa_poll(unsigned long); | 205 | static void moxa_poll(unsigned long); |
206 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); | 206 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); |
207 | static void moxa_setup_empty_event(struct tty_struct *); | 207 | static void moxa_setup_empty_event(struct tty_struct *); |
208 | static void moxa_shut_down(struct moxa_port *); | 208 | static void moxa_shut_down(struct tty_struct *); |
209 | /* | 209 | /* |
210 | * moxa board interface functions: | 210 | * moxa board interface functions: |
211 | */ | 211 | */ |
@@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int); | |||
217 | static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); | 217 | static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); |
218 | static int MoxaPortLineStatus(struct moxa_port *); | 218 | static int MoxaPortLineStatus(struct moxa_port *); |
219 | static void MoxaPortFlushData(struct moxa_port *, int); | 219 | static void MoxaPortFlushData(struct moxa_port *, int); |
220 | static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int); | 220 | static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); |
221 | static int MoxaPortReadData(struct moxa_port *); | 221 | static int MoxaPortReadData(struct moxa_port *); |
222 | static int MoxaPortTxQueue(struct moxa_port *); | 222 | static int MoxaPortTxQueue(struct moxa_port *); |
223 | static int MoxaPortRxQueue(struct moxa_port *); | 223 | static int MoxaPortRxQueue(struct moxa_port *); |
@@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
332 | for (i = 0; i < MAX_BOARDS; i++) { | 332 | for (i = 0; i < MAX_BOARDS; i++) { |
333 | p = moxa_boards[i].ports; | 333 | p = moxa_boards[i].ports; |
334 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | 334 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { |
335 | struct tty_struct *ttyp; | ||
335 | memset(&tmp, 0, sizeof(tmp)); | 336 | memset(&tmp, 0, sizeof(tmp)); |
336 | if (!moxa_boards[i].ready) | 337 | if (!moxa_boards[i].ready) |
337 | goto copy; | 338 | goto copy; |
@@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
344 | if (status & 4) | 345 | if (status & 4) |
345 | tmp.dcd = 1; | 346 | tmp.dcd = 1; |
346 | 347 | ||
347 | if (!p->port.tty || !p->port.tty->termios) | 348 | ttyp = tty_port_tty_get(&p->port); |
349 | if (!ttyp || !ttyp->termios) | ||
348 | tmp.cflag = p->cflag; | 350 | tmp.cflag = p->cflag; |
349 | else | 351 | else |
350 | tmp.cflag = p->port.tty->termios->c_cflag; | 352 | tmp.cflag = ttyp->termios->c_cflag; |
353 | tty_kref_put(tty); | ||
351 | copy: | 354 | copy: |
352 | if (copy_to_user(argm, &tmp, sizeof(tmp))) { | 355 | if (copy_to_user(argm, &tmp, sizeof(tmp))) { |
353 | mutex_unlock(&moxa_openlock); | 356 | mutex_unlock(&moxa_openlock); |
@@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) | |||
880 | 883 | ||
881 | /* pci hot-un-plug support */ | 884 | /* pci hot-un-plug support */ |
882 | for (a = 0; a < brd->numPorts; a++) | 885 | for (a = 0; a < brd->numPorts; a++) |
883 | if (brd->ports[a].port.flags & ASYNC_INITIALIZED) | 886 | if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { |
884 | tty_hangup(brd->ports[a].port.tty); | 887 | struct tty_struct *tty = tty_port_tty_get( |
888 | &brd->ports[a].port); | ||
889 | if (tty) { | ||
890 | tty_hangup(tty); | ||
891 | tty_kref_put(tty); | ||
892 | } | ||
893 | } | ||
885 | while (1) { | 894 | while (1) { |
886 | opened = 0; | 895 | opened = 0; |
887 | for (a = 0; a < brd->numPorts; a++) | 896 | for (a = 0; a < brd->numPorts; a++) |
@@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void) | |||
1096 | module_init(moxa_init); | 1105 | module_init(moxa_init); |
1097 | module_exit(moxa_exit); | 1106 | module_exit(moxa_exit); |
1098 | 1107 | ||
1099 | static void moxa_close_port(struct moxa_port *ch) | 1108 | static void moxa_close_port(struct tty_struct *tty) |
1100 | { | 1109 | { |
1101 | moxa_shut_down(ch); | 1110 | struct moxa_port *ch = tty->driver_data; |
1111 | moxa_shut_down(tty); | ||
1102 | MoxaPortFlushData(ch, 2); | 1112 | MoxaPortFlushData(ch, 2); |
1103 | ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1113 | ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
1104 | ch->port.tty->driver_data = NULL; | 1114 | tty->driver_data = NULL; |
1105 | ch->port.tty = NULL; | 1115 | tty_port_tty_set(&ch->port, NULL); |
1106 | } | 1116 | } |
1107 | 1117 | ||
1108 | static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, | 1118 | static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, |
@@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) | |||
1161 | ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; | 1171 | ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; |
1162 | ch->port.count++; | 1172 | ch->port.count++; |
1163 | tty->driver_data = ch; | 1173 | tty->driver_data = ch; |
1164 | ch->port.tty = tty; | 1174 | tty_port_tty_set(&ch->port, tty); |
1165 | if (!(ch->port.flags & ASYNC_INITIALIZED)) { | 1175 | if (!(ch->port.flags & ASYNC_INITIALIZED)) { |
1166 | ch->statusflags = 0; | 1176 | ch->statusflags = 0; |
1167 | moxa_set_tty_param(tty, tty->termios); | 1177 | moxa_set_tty_param(tty, tty->termios); |
@@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) | |||
1179 | if (retval) { | 1189 | if (retval) { |
1180 | if (ch->port.count) /* 0 means already hung up... */ | 1190 | if (ch->port.count) /* 0 means already hung up... */ |
1181 | if (--ch->port.count == 0) | 1191 | if (--ch->port.count == 0) |
1182 | moxa_close_port(ch); | 1192 | moxa_close_port(tty); |
1183 | } else | 1193 | } else |
1184 | ch->port.flags |= ASYNC_NORMAL_ACTIVE; | 1194 | ch->port.flags |= ASYNC_NORMAL_ACTIVE; |
1185 | mutex_unlock(&moxa_openlock); | 1195 | mutex_unlock(&moxa_openlock); |
@@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) | |||
1219 | tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ | 1229 | tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ |
1220 | } | 1230 | } |
1221 | 1231 | ||
1222 | moxa_close_port(ch); | 1232 | moxa_close_port(tty); |
1223 | unlock: | 1233 | unlock: |
1224 | mutex_unlock(&moxa_openlock); | 1234 | mutex_unlock(&moxa_openlock); |
1225 | } | 1235 | } |
@@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty, | |||
1234 | return 0; | 1244 | return 0; |
1235 | 1245 | ||
1236 | spin_lock_bh(&moxa_lock); | 1246 | spin_lock_bh(&moxa_lock); |
1237 | len = MoxaPortWriteData(ch, buf, count); | 1247 | len = MoxaPortWriteData(tty, buf, count); |
1238 | spin_unlock_bh(&moxa_lock); | 1248 | spin_unlock_bh(&moxa_lock); |
1239 | 1249 | ||
1240 | ch->statusflags |= LOWWAIT; | 1250 | ch->statusflags |= LOWWAIT; |
@@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty) | |||
1409 | return; | 1419 | return; |
1410 | } | 1420 | } |
1411 | ch->port.count = 0; | 1421 | ch->port.count = 0; |
1412 | moxa_close_port(ch); | 1422 | moxa_close_port(tty); |
1413 | mutex_unlock(&moxa_openlock); | 1423 | mutex_unlock(&moxa_openlock); |
1414 | 1424 | ||
1415 | wake_up_interruptible(&ch->port.open_wait); | 1425 | wake_up_interruptible(&ch->port.open_wait); |
@@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty) | |||
1417 | 1427 | ||
1418 | static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) | 1428 | static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) |
1419 | { | 1429 | { |
1430 | struct tty_struct *tty; | ||
1420 | dcd = !!dcd; | 1431 | dcd = !!dcd; |
1421 | 1432 | ||
1422 | if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) { | 1433 | if (dcd != p->DCDState) { |
1423 | if (!dcd) | 1434 | tty = tty_port_tty_get(&p->port); |
1424 | tty_hangup(p->port.tty); | 1435 | if (tty && C_CLOCAL(tty) && !dcd) |
1436 | tty_hangup(tty); | ||
1437 | tty_kref_put(tty); | ||
1425 | } | 1438 | } |
1426 | p->DCDState = dcd; | 1439 | p->DCDState = dcd; |
1427 | } | 1440 | } |
@@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) | |||
1429 | static int moxa_poll_port(struct moxa_port *p, unsigned int handle, | 1442 | static int moxa_poll_port(struct moxa_port *p, unsigned int handle, |
1430 | u16 __iomem *ip) | 1443 | u16 __iomem *ip) |
1431 | { | 1444 | { |
1432 | struct tty_struct *tty = p->port.tty; | 1445 | struct tty_struct *tty = tty_port_tty_get(&p->port); |
1433 | void __iomem *ofsAddr; | 1446 | void __iomem *ofsAddr; |
1434 | unsigned int inited = p->port.flags & ASYNC_INITIALIZED; | 1447 | unsigned int inited = p->port.flags & ASYNC_INITIALIZED; |
1435 | u16 intr; | 1448 | u16 intr; |
@@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, | |||
1476 | tty_insert_flip_char(tty, 0, TTY_BREAK); | 1489 | tty_insert_flip_char(tty, 0, TTY_BREAK); |
1477 | tty_schedule_flip(tty); | 1490 | tty_schedule_flip(tty); |
1478 | } | 1491 | } |
1492 | tty_kref_put(tty); | ||
1479 | 1493 | ||
1480 | if (intr & IntrLine) | 1494 | if (intr & IntrLine) |
1481 | moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); | 1495 | moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); |
@@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty) | |||
1560 | spin_unlock_bh(&moxa_lock); | 1574 | spin_unlock_bh(&moxa_lock); |
1561 | } | 1575 | } |
1562 | 1576 | ||
1563 | static void moxa_shut_down(struct moxa_port *ch) | 1577 | static void moxa_shut_down(struct tty_struct *tty) |
1564 | { | 1578 | { |
1565 | struct tty_struct *tp = ch->port.tty; | 1579 | struct moxa_port *ch = tty->driver_data; |
1566 | 1580 | ||
1567 | if (!(ch->port.flags & ASYNC_INITIALIZED)) | 1581 | if (!(ch->port.flags & ASYNC_INITIALIZED)) |
1568 | return; | 1582 | return; |
@@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch) | |||
1572 | /* | 1586 | /* |
1573 | * If we're a modem control device and HUPCL is on, drop RTS & DTR. | 1587 | * If we're a modem control device and HUPCL is on, drop RTS & DTR. |
1574 | */ | 1588 | */ |
1575 | if (C_HUPCL(tp)) | 1589 | if (C_HUPCL(tty)) |
1576 | MoxaPortLineCtrl(ch, 0, 0); | 1590 | MoxaPortLineCtrl(ch, 0, 0); |
1577 | 1591 | ||
1578 | spin_lock_bh(&moxa_lock); | 1592 | spin_lock_bh(&moxa_lock); |
@@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port) | |||
1953 | return val; | 1967 | return val; |
1954 | } | 1968 | } |
1955 | 1969 | ||
1956 | static int MoxaPortWriteData(struct moxa_port *port, | 1970 | static int MoxaPortWriteData(struct tty_struct *tty, |
1957 | const unsigned char *buffer, int len) | 1971 | const unsigned char *buffer, int len) |
1958 | { | 1972 | { |
1973 | struct moxa_port *port = tty->driver_data; | ||
1959 | void __iomem *baseAddr, *ofsAddr, *ofs; | 1974 | void __iomem *baseAddr, *ofsAddr, *ofs; |
1960 | unsigned int c, total; | 1975 | unsigned int c, total; |
1961 | u16 head, tail, tx_mask, spage, epage; | 1976 | u16 head, tail, tx_mask, spage, epage; |
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index b638403e8e9c..8beef50f95a0 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c | |||
@@ -610,15 +610,13 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, | |||
610 | return 0; | 610 | return 0; |
611 | } | 611 | } |
612 | 612 | ||
613 | static int mxser_set_baud(struct mxser_port *info, long newspd) | 613 | static int mxser_set_baud(struct tty_struct *tty, long newspd) |
614 | { | 614 | { |
615 | struct mxser_port *info = tty->driver_data; | ||
615 | int quot = 0, baud; | 616 | int quot = 0, baud; |
616 | unsigned char cval; | 617 | unsigned char cval; |
617 | 618 | ||
618 | if (!info->port.tty || !info->port.tty->termios) | 619 | if (!info->ioaddr) |
619 | return -1; | ||
620 | |||
621 | if (!(info->ioaddr)) | ||
622 | return -1; | 620 | return -1; |
623 | 621 | ||
624 | if (newspd > info->max_baud) | 622 | if (newspd > info->max_baud) |
@@ -626,13 +624,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
626 | 624 | ||
627 | if (newspd == 134) { | 625 | if (newspd == 134) { |
628 | quot = 2 * info->baud_base / 269; | 626 | quot = 2 * info->baud_base / 269; |
629 | tty_encode_baud_rate(info->port.tty, 134, 134); | 627 | tty_encode_baud_rate(tty, 134, 134); |
630 | } else if (newspd) { | 628 | } else if (newspd) { |
631 | quot = info->baud_base / newspd; | 629 | quot = info->baud_base / newspd; |
632 | if (quot == 0) | 630 | if (quot == 0) |
633 | quot = 1; | 631 | quot = 1; |
634 | baud = info->baud_base/quot; | 632 | baud = info->baud_base/quot; |
635 | tty_encode_baud_rate(info->port.tty, baud, baud); | 633 | tty_encode_baud_rate(tty, baud, baud); |
636 | } else { | 634 | } else { |
637 | quot = 0; | 635 | quot = 0; |
638 | } | 636 | } |
@@ -658,7 +656,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
658 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ | 656 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ |
659 | 657 | ||
660 | #ifdef BOTHER | 658 | #ifdef BOTHER |
661 | if (C_BAUD(info->port.tty) == BOTHER) { | 659 | if (C_BAUD(tty) == BOTHER) { |
662 | quot = info->baud_base % newspd; | 660 | quot = info->baud_base % newspd; |
663 | quot *= 8; | 661 | quot *= 8; |
664 | if (quot % newspd > newspd / 2) { | 662 | if (quot % newspd > newspd / 2) { |
@@ -679,21 +677,20 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
679 | * This routine is called to set the UART divisor registers to match | 677 | * This routine is called to set the UART divisor registers to match |
680 | * the specified baud rate for a serial port. | 678 | * the specified baud rate for a serial port. |
681 | */ | 679 | */ |
682 | static int mxser_change_speed(struct mxser_port *info, | 680 | static int mxser_change_speed(struct tty_struct *tty, |
683 | struct ktermios *old_termios) | 681 | struct ktermios *old_termios) |
684 | { | 682 | { |
683 | struct mxser_port *info = tty->driver_data; | ||
685 | unsigned cflag, cval, fcr; | 684 | unsigned cflag, cval, fcr; |
686 | int ret = 0; | 685 | int ret = 0; |
687 | unsigned char status; | 686 | unsigned char status; |
688 | 687 | ||
689 | if (!info->port.tty || !info->port.tty->termios) | 688 | cflag = tty->termios->c_cflag; |
690 | return ret; | 689 | if (!info->ioaddr) |
691 | cflag = info->port.tty->termios->c_cflag; | ||
692 | if (!(info->ioaddr)) | ||
693 | return ret; | 690 | return ret; |
694 | 691 | ||
695 | if (mxser_set_baud_method[info->port.tty->index] == 0) | 692 | if (mxser_set_baud_method[tty->index] == 0) |
696 | mxser_set_baud(info, tty_get_baud_rate(info->port.tty)); | 693 | mxser_set_baud(tty, tty_get_baud_rate(tty)); |
697 | 694 | ||
698 | /* byte size and parity */ | 695 | /* byte size and parity */ |
699 | switch (cflag & CSIZE) { | 696 | switch (cflag & CSIZE) { |
@@ -762,9 +759,9 @@ static int mxser_change_speed(struct mxser_port *info, | |||
762 | info->MCR |= UART_MCR_AFE; | 759 | info->MCR |= UART_MCR_AFE; |
763 | } else { | 760 | } else { |
764 | status = inb(info->ioaddr + UART_MSR); | 761 | status = inb(info->ioaddr + UART_MSR); |
765 | if (info->port.tty->hw_stopped) { | 762 | if (tty->hw_stopped) { |
766 | if (status & UART_MSR_CTS) { | 763 | if (status & UART_MSR_CTS) { |
767 | info->port.tty->hw_stopped = 0; | 764 | tty->hw_stopped = 0; |
768 | if (info->type != PORT_16550A && | 765 | if (info->type != PORT_16550A && |
769 | !info->board->chip_flag) { | 766 | !info->board->chip_flag) { |
770 | outb(info->IER & ~UART_IER_THRI, | 767 | outb(info->IER & ~UART_IER_THRI, |
@@ -774,11 +771,11 @@ static int mxser_change_speed(struct mxser_port *info, | |||
774 | outb(info->IER, info->ioaddr + | 771 | outb(info->IER, info->ioaddr + |
775 | UART_IER); | 772 | UART_IER); |
776 | } | 773 | } |
777 | tty_wakeup(info->port.tty); | 774 | tty_wakeup(tty); |
778 | } | 775 | } |
779 | } else { | 776 | } else { |
780 | if (!(status & UART_MSR_CTS)) { | 777 | if (!(status & UART_MSR_CTS)) { |
781 | info->port.tty->hw_stopped = 1; | 778 | tty->hw_stopped = 1; |
782 | if ((info->type != PORT_16550A) && | 779 | if ((info->type != PORT_16550A) && |
783 | (!info->board->chip_flag)) { | 780 | (!info->board->chip_flag)) { |
784 | info->IER &= ~UART_IER_THRI; | 781 | info->IER &= ~UART_IER_THRI; |
@@ -804,21 +801,21 @@ static int mxser_change_speed(struct mxser_port *info, | |||
804 | * Set up parity check flag | 801 | * Set up parity check flag |
805 | */ | 802 | */ |
806 | info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; | 803 | info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; |
807 | if (I_INPCK(info->port.tty)) | 804 | if (I_INPCK(tty)) |
808 | info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; | 805 | info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; |
809 | if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) | 806 | if (I_BRKINT(tty) || I_PARMRK(tty)) |
810 | info->read_status_mask |= UART_LSR_BI; | 807 | info->read_status_mask |= UART_LSR_BI; |
811 | 808 | ||
812 | info->ignore_status_mask = 0; | 809 | info->ignore_status_mask = 0; |
813 | 810 | ||
814 | if (I_IGNBRK(info->port.tty)) { | 811 | if (I_IGNBRK(tty)) { |
815 | info->ignore_status_mask |= UART_LSR_BI; | 812 | info->ignore_status_mask |= UART_LSR_BI; |
816 | info->read_status_mask |= UART_LSR_BI; | 813 | info->read_status_mask |= UART_LSR_BI; |
817 | /* | 814 | /* |
818 | * If we're ignore parity and break indicators, ignore | 815 | * If we're ignore parity and break indicators, ignore |
819 | * overruns too. (For real raw support). | 816 | * overruns too. (For real raw support). |
820 | */ | 817 | */ |
821 | if (I_IGNPAR(info->port.tty)) { | 818 | if (I_IGNPAR(tty)) { |
822 | info->ignore_status_mask |= | 819 | info->ignore_status_mask |= |
823 | UART_LSR_OE | | 820 | UART_LSR_OE | |
824 | UART_LSR_PE | | 821 | UART_LSR_PE | |
@@ -830,16 +827,16 @@ static int mxser_change_speed(struct mxser_port *info, | |||
830 | } | 827 | } |
831 | } | 828 | } |
832 | if (info->board->chip_flag) { | 829 | if (info->board->chip_flag) { |
833 | mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty)); | 830 | mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty)); |
834 | mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty)); | 831 | mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty)); |
835 | if (I_IXON(info->port.tty)) { | 832 | if (I_IXON(tty)) { |
836 | mxser_enable_must_rx_software_flow_control( | 833 | mxser_enable_must_rx_software_flow_control( |
837 | info->ioaddr); | 834 | info->ioaddr); |
838 | } else { | 835 | } else { |
839 | mxser_disable_must_rx_software_flow_control( | 836 | mxser_disable_must_rx_software_flow_control( |
840 | info->ioaddr); | 837 | info->ioaddr); |
841 | } | 838 | } |
842 | if (I_IXOFF(info->port.tty)) { | 839 | if (I_IXOFF(tty)) { |
843 | mxser_enable_must_tx_software_flow_control( | 840 | mxser_enable_must_tx_software_flow_control( |
844 | info->ioaddr); | 841 | info->ioaddr); |
845 | } else { | 842 | } else { |
@@ -855,7 +852,8 @@ static int mxser_change_speed(struct mxser_port *info, | |||
855 | return ret; | 852 | return ret; |
856 | } | 853 | } |
857 | 854 | ||
858 | static void mxser_check_modem_status(struct mxser_port *port, int status) | 855 | static void mxser_check_modem_status(struct tty_struct *tty, |
856 | struct mxser_port *port, int status) | ||
859 | { | 857 | { |
860 | /* update input line counters */ | 858 | /* update input line counters */ |
861 | if (status & UART_MSR_TERI) | 859 | if (status & UART_MSR_TERI) |
@@ -874,10 +872,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) | |||
874 | wake_up_interruptible(&port->port.open_wait); | 872 | wake_up_interruptible(&port->port.open_wait); |
875 | } | 873 | } |
876 | 874 | ||
875 | tty = tty_port_tty_get(&port->port); | ||
877 | if (port->port.flags & ASYNC_CTS_FLOW) { | 876 | if (port->port.flags & ASYNC_CTS_FLOW) { |
878 | if (port->port.tty->hw_stopped) { | 877 | if (tty->hw_stopped) { |
879 | if (status & UART_MSR_CTS) { | 878 | if (status & UART_MSR_CTS) { |
880 | port->port.tty->hw_stopped = 0; | 879 | tty->hw_stopped = 0; |
881 | 880 | ||
882 | if ((port->type != PORT_16550A) && | 881 | if ((port->type != PORT_16550A) && |
883 | (!port->board->chip_flag)) { | 882 | (!port->board->chip_flag)) { |
@@ -887,11 +886,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) | |||
887 | outb(port->IER, port->ioaddr + | 886 | outb(port->IER, port->ioaddr + |
888 | UART_IER); | 887 | UART_IER); |
889 | } | 888 | } |
890 | tty_wakeup(port->port.tty); | 889 | tty_wakeup(tty); |
891 | } | 890 | } |
892 | } else { | 891 | } else { |
893 | if (!(status & UART_MSR_CTS)) { | 892 | if (!(status & UART_MSR_CTS)) { |
894 | port->port.tty->hw_stopped = 1; | 893 | tty->hw_stopped = 1; |
895 | if (port->type != PORT_16550A && | 894 | if (port->type != PORT_16550A && |
896 | !port->board->chip_flag) { | 895 | !port->board->chip_flag) { |
897 | port->IER &= ~UART_IER_THRI; | 896 | port->IER &= ~UART_IER_THRI; |
@@ -903,8 +902,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) | |||
903 | } | 902 | } |
904 | } | 903 | } |
905 | 904 | ||
906 | static int mxser_startup(struct mxser_port *info) | 905 | static int mxser_startup(struct tty_struct *tty) |
907 | { | 906 | { |
907 | struct mxser_port *info = tty->driver_data; | ||
908 | unsigned long page; | 908 | unsigned long page; |
909 | unsigned long flags; | 909 | unsigned long flags; |
910 | 910 | ||
@@ -921,8 +921,7 @@ static int mxser_startup(struct mxser_port *info) | |||
921 | } | 921 | } |
922 | 922 | ||
923 | if (!info->ioaddr || !info->type) { | 923 | if (!info->ioaddr || !info->type) { |
924 | if (info->port.tty) | 924 | set_bit(TTY_IO_ERROR, &tty->flags); |
925 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
926 | free_page(page); | 925 | free_page(page); |
927 | spin_unlock_irqrestore(&info->slock, flags); | 926 | spin_unlock_irqrestore(&info->slock, flags); |
928 | return 0; | 927 | return 0; |
@@ -952,8 +951,8 @@ static int mxser_startup(struct mxser_port *info) | |||
952 | if (inb(info->ioaddr + UART_LSR) == 0xff) { | 951 | if (inb(info->ioaddr + UART_LSR) == 0xff) { |
953 | spin_unlock_irqrestore(&info->slock, flags); | 952 | spin_unlock_irqrestore(&info->slock, flags); |
954 | if (capable(CAP_SYS_ADMIN)) { | 953 | if (capable(CAP_SYS_ADMIN)) { |
955 | if (info->port.tty) | 954 | if (tty) |
956 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | 955 | set_bit(TTY_IO_ERROR, &tty->flags); |
957 | return 0; | 956 | return 0; |
958 | } else | 957 | } else |
959 | return -ENODEV; | 958 | return -ENODEV; |
@@ -991,14 +990,13 @@ static int mxser_startup(struct mxser_port *info) | |||
991 | (void) inb(info->ioaddr + UART_IIR); | 990 | (void) inb(info->ioaddr + UART_IIR); |
992 | (void) inb(info->ioaddr + UART_MSR); | 991 | (void) inb(info->ioaddr + UART_MSR); |
993 | 992 | ||
994 | if (info->port.tty) | 993 | clear_bit(TTY_IO_ERROR, &tty->flags); |
995 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
996 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | 994 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; |
997 | 995 | ||
998 | /* | 996 | /* |
999 | * and set the speed of the serial port | 997 | * and set the speed of the serial port |
1000 | */ | 998 | */ |
1001 | mxser_change_speed(info, NULL); | 999 | mxser_change_speed(tty, NULL); |
1002 | info->port.flags |= ASYNC_INITIALIZED; | 1000 | info->port.flags |= ASYNC_INITIALIZED; |
1003 | spin_unlock_irqrestore(&info->slock, flags); | 1001 | spin_unlock_irqrestore(&info->slock, flags); |
1004 | 1002 | ||
@@ -1009,8 +1007,9 @@ static int mxser_startup(struct mxser_port *info) | |||
1009 | * This routine will shutdown a serial port; interrupts maybe disabled, and | 1007 | * This routine will shutdown a serial port; interrupts maybe disabled, and |
1010 | * DTR is dropped if the hangup on close termio flag is on. | 1008 | * DTR is dropped if the hangup on close termio flag is on. |
1011 | */ | 1009 | */ |
1012 | static void mxser_shutdown(struct mxser_port *info) | 1010 | static void mxser_shutdown(struct tty_struct *tty) |
1013 | { | 1011 | { |
1012 | struct mxser_port *info = tty->driver_data; | ||
1014 | unsigned long flags; | 1013 | unsigned long flags; |
1015 | 1014 | ||
1016 | if (!(info->port.flags & ASYNC_INITIALIZED)) | 1015 | if (!(info->port.flags & ASYNC_INITIALIZED)) |
@@ -1035,7 +1034,7 @@ static void mxser_shutdown(struct mxser_port *info) | |||
1035 | info->IER = 0; | 1034 | info->IER = 0; |
1036 | outb(0x00, info->ioaddr + UART_IER); | 1035 | outb(0x00, info->ioaddr + UART_IER); |
1037 | 1036 | ||
1038 | if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) | 1037 | if (tty->termios->c_cflag & HUPCL) |
1039 | info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); | 1038 | info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); |
1040 | outb(info->MCR, info->ioaddr + UART_MCR); | 1039 | outb(info->MCR, info->ioaddr + UART_MCR); |
1041 | 1040 | ||
@@ -1051,8 +1050,7 @@ static void mxser_shutdown(struct mxser_port *info) | |||
1051 | /* read data port to reset things */ | 1050 | /* read data port to reset things */ |
1052 | (void) inb(info->ioaddr + UART_RX); | 1051 | (void) inb(info->ioaddr + UART_RX); |
1053 | 1052 | ||
1054 | if (info->port.tty) | 1053 | set_bit(TTY_IO_ERROR, &tty->flags); |
1055 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1056 | 1054 | ||
1057 | info->port.flags &= ~ASYNC_INITIALIZED; | 1055 | info->port.flags &= ~ASYNC_INITIALIZED; |
1058 | 1056 | ||
@@ -1084,14 +1082,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) | |||
1084 | return -ENODEV; | 1082 | return -ENODEV; |
1085 | 1083 | ||
1086 | tty->driver_data = info; | 1084 | tty->driver_data = info; |
1087 | info->port.tty = tty; | 1085 | tty_port_tty_set(&info->port, tty); |
1088 | /* | 1086 | /* |
1089 | * Start up serial port | 1087 | * Start up serial port |
1090 | */ | 1088 | */ |
1091 | spin_lock_irqsave(&info->slock, flags); | 1089 | spin_lock_irqsave(&info->slock, flags); |
1092 | info->port.count++; | 1090 | info->port.count++; |
1093 | spin_unlock_irqrestore(&info->slock, flags); | 1091 | spin_unlock_irqrestore(&info->slock, flags); |
1094 | retval = mxser_startup(info); | 1092 | retval = mxser_startup(tty); |
1095 | if (retval) | 1093 | if (retval) |
1096 | return retval; | 1094 | return retval; |
1097 | 1095 | ||
@@ -1209,13 +1207,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) | |||
1209 | break; | 1207 | break; |
1210 | } | 1208 | } |
1211 | } | 1209 | } |
1212 | mxser_shutdown(info); | 1210 | mxser_shutdown(tty); |
1213 | 1211 | ||
1214 | mxser_flush_buffer(tty); | 1212 | mxser_flush_buffer(tty); |
1215 | tty_ldisc_flush(tty); | 1213 | tty_ldisc_flush(tty); |
1216 | 1214 | ||
1217 | tty->closing = 0; | 1215 | tty->closing = 0; |
1218 | info->port.tty = NULL; | 1216 | tty_port_tty_set(&info->port, NULL); |
1219 | if (info->port.blocked_open) { | 1217 | if (info->port.blocked_open) { |
1220 | if (info->port.close_delay) | 1218 | if (info->port.close_delay) |
1221 | schedule_timeout_interruptible(info->port.close_delay); | 1219 | schedule_timeout_interruptible(info->port.close_delay); |
@@ -1337,12 +1335,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) | |||
1337 | * friends of mxser_ioctl() | 1335 | * friends of mxser_ioctl() |
1338 | * ------------------------------------------------------------ | 1336 | * ------------------------------------------------------------ |
1339 | */ | 1337 | */ |
1340 | static int mxser_get_serial_info(struct mxser_port *info, | 1338 | static int mxser_get_serial_info(struct tty_struct *tty, |
1341 | struct serial_struct __user *retinfo) | 1339 | struct serial_struct __user *retinfo) |
1342 | { | 1340 | { |
1341 | struct mxser_port *info = tty->driver_data; | ||
1343 | struct serial_struct tmp = { | 1342 | struct serial_struct tmp = { |
1344 | .type = info->type, | 1343 | .type = info->type, |
1345 | .line = info->port.tty->index, | 1344 | .line = tty->index, |
1346 | .port = info->ioaddr, | 1345 | .port = info->ioaddr, |
1347 | .irq = info->board->irq, | 1346 | .irq = info->board->irq, |
1348 | .flags = info->port.flags, | 1347 | .flags = info->port.flags, |
@@ -1357,9 +1356,10 @@ static int mxser_get_serial_info(struct mxser_port *info, | |||
1357 | return 0; | 1356 | return 0; |
1358 | } | 1357 | } |
1359 | 1358 | ||
1360 | static int mxser_set_serial_info(struct mxser_port *info, | 1359 | static int mxser_set_serial_info(struct tty_struct *tty, |
1361 | struct serial_struct __user *new_info) | 1360 | struct serial_struct __user *new_info) |
1362 | { | 1361 | { |
1362 | struct mxser_port *info = tty->driver_data; | ||
1363 | struct serial_struct new_serial; | 1363 | struct serial_struct new_serial; |
1364 | speed_t baud; | 1364 | speed_t baud; |
1365 | unsigned long sl_flags; | 1365 | unsigned long sl_flags; |
@@ -1393,14 +1393,14 @@ static int mxser_set_serial_info(struct mxser_port *info, | |||
1393 | (new_serial.flags & ASYNC_FLAGS)); | 1393 | (new_serial.flags & ASYNC_FLAGS)); |
1394 | info->port.close_delay = new_serial.close_delay * HZ / 100; | 1394 | info->port.close_delay = new_serial.close_delay * HZ / 100; |
1395 | info->port.closing_wait = new_serial.closing_wait * HZ / 100; | 1395 | info->port.closing_wait = new_serial.closing_wait * HZ / 100; |
1396 | info->port.tty->low_latency = | 1396 | tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) |
1397 | (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1397 | ? 1 : 0; |
1398 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && | 1398 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && |
1399 | (new_serial.baud_base != info->baud_base || | 1399 | (new_serial.baud_base != info->baud_base || |
1400 | new_serial.custom_divisor != | 1400 | new_serial.custom_divisor != |
1401 | info->custom_divisor)) { | 1401 | info->custom_divisor)) { |
1402 | baud = new_serial.baud_base / new_serial.custom_divisor; | 1402 | baud = new_serial.baud_base / new_serial.custom_divisor; |
1403 | tty_encode_baud_rate(info->port.tty, baud, baud); | 1403 | tty_encode_baud_rate(tty, baud, baud); |
1404 | } | 1404 | } |
1405 | } | 1405 | } |
1406 | 1406 | ||
@@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct mxser_port *info, | |||
1411 | if (info->port.flags & ASYNC_INITIALIZED) { | 1411 | if (info->port.flags & ASYNC_INITIALIZED) { |
1412 | if (flags != (info->port.flags & ASYNC_SPD_MASK)) { | 1412 | if (flags != (info->port.flags & ASYNC_SPD_MASK)) { |
1413 | spin_lock_irqsave(&info->slock, sl_flags); | 1413 | spin_lock_irqsave(&info->slock, sl_flags); |
1414 | mxser_change_speed(info, NULL); | 1414 | mxser_change_speed(tty, NULL); |
1415 | spin_unlock_irqrestore(&info->slock, sl_flags); | 1415 | spin_unlock_irqrestore(&info->slock, sl_flags); |
1416 | } | 1416 | } |
1417 | } else | 1417 | } else |
1418 | retval = mxser_startup(info); | 1418 | retval = mxser_startup(tty); |
1419 | 1419 | ||
1420 | return retval; | 1420 | return retval; |
1421 | } | 1421 | } |
@@ -1461,7 +1461,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file) | |||
1461 | spin_lock_irqsave(&info->slock, flags); | 1461 | spin_lock_irqsave(&info->slock, flags); |
1462 | status = inb(info->ioaddr + UART_MSR); | 1462 | status = inb(info->ioaddr + UART_MSR); |
1463 | if (status & UART_MSR_ANY_DELTA) | 1463 | if (status & UART_MSR_ANY_DELTA) |
1464 | mxser_check_modem_status(info, status); | 1464 | mxser_check_modem_status(tty, info, status); |
1465 | spin_unlock_irqrestore(&info->slock, flags); | 1465 | spin_unlock_irqrestore(&info->slock, flags); |
1466 | return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | | 1466 | return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | |
1467 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | | 1467 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | |
@@ -1606,6 +1606,7 @@ static int __init mxser_read_register(int port, unsigned short *regs) | |||
1606 | static int mxser_ioctl_special(unsigned int cmd, void __user *argp) | 1606 | static int mxser_ioctl_special(unsigned int cmd, void __user *argp) |
1607 | { | 1607 | { |
1608 | struct mxser_port *port; | 1608 | struct mxser_port *port; |
1609 | struct tty_struct *tty; | ||
1609 | int result, status; | 1610 | int result, status; |
1610 | unsigned int i, j; | 1611 | unsigned int i, j; |
1611 | int ret = 0; | 1612 | int ret = 0; |
@@ -1643,12 +1644,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) | |||
1643 | 1644 | ||
1644 | if (!port->ioaddr) | 1645 | if (!port->ioaddr) |
1645 | goto copy; | 1646 | goto copy; |
1647 | |||
1648 | tty = tty_port_tty_get(&port->port); | ||
1646 | 1649 | ||
1647 | if (!port->port.tty || !port->port.tty->termios) | 1650 | if (!tty || !tty->termios) |
1648 | ms.cflag = port->normal_termios.c_cflag; | 1651 | ms.cflag = port->normal_termios.c_cflag; |
1649 | else | 1652 | else |
1650 | ms.cflag = port->port.tty->termios->c_cflag; | 1653 | ms.cflag = tty->termios->c_cflag; |
1651 | 1654 | tty_kref_put(tty); | |
1652 | status = inb(port->ioaddr + UART_MSR); | 1655 | status = inb(port->ioaddr + UART_MSR); |
1653 | if (status & UART_MSR_DCD) | 1656 | if (status & UART_MSR_DCD) |
1654 | ms.dcd = 1; | 1657 | ms.dcd = 1; |
@@ -1704,15 +1707,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) | |||
1704 | me->up_txcnt[p] = port->mon_data.up_txcnt; | 1707 | me->up_txcnt[p] = port->mon_data.up_txcnt; |
1705 | me->modem_status[p] = | 1708 | me->modem_status[p] = |
1706 | port->mon_data.modem_status; | 1709 | port->mon_data.modem_status; |
1707 | me->baudrate[p] = tty_get_baud_rate(port->port.tty); | 1710 | tty = tty_port_tty_get(&port->port); |
1708 | 1711 | ||
1709 | if (!port->port.tty || !port->port.tty->termios) { | 1712 | if (!tty || !tty->termios) { |
1710 | cflag = port->normal_termios.c_cflag; | 1713 | cflag = port->normal_termios.c_cflag; |
1711 | iflag = port->normal_termios.c_iflag; | 1714 | iflag = port->normal_termios.c_iflag; |
1715 | me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios); | ||
1712 | } else { | 1716 | } else { |
1713 | cflag = port->port.tty->termios->c_cflag; | 1717 | cflag = tty->termios->c_cflag; |
1714 | iflag = port->port.tty->termios->c_iflag; | 1718 | iflag = tty->termios->c_iflag; |
1719 | me->baudrate[p] = tty_get_baud_rate(tty); | ||
1715 | } | 1720 | } |
1721 | tty_kref_put(tty); | ||
1716 | 1722 | ||
1717 | me->databits[p] = cflag & CSIZE; | 1723 | me->databits[p] = cflag & CSIZE; |
1718 | me->stopbits[p] = cflag & CSTOPB; | 1724 | me->stopbits[p] = cflag & CSTOPB; |
@@ -1822,12 +1828,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1822 | switch (cmd) { | 1828 | switch (cmd) { |
1823 | case TIOCGSERIAL: | 1829 | case TIOCGSERIAL: |
1824 | lock_kernel(); | 1830 | lock_kernel(); |
1825 | retval = mxser_get_serial_info(info, argp); | 1831 | retval = mxser_get_serial_info(tty, argp); |
1826 | unlock_kernel(); | 1832 | unlock_kernel(); |
1827 | return retval; | 1833 | return retval; |
1828 | case TIOCSSERIAL: | 1834 | case TIOCSSERIAL: |
1829 | lock_kernel(); | 1835 | lock_kernel(); |
1830 | retval = mxser_set_serial_info(info, argp); | 1836 | retval = mxser_set_serial_info(tty, argp); |
1831 | unlock_kernel(); | 1837 | unlock_kernel(); |
1832 | return retval; | 1838 | return retval; |
1833 | case TIOCSERGETLSR: /* Get line status register */ | 1839 | case TIOCSERGETLSR: /* Get line status register */ |
@@ -1896,7 +1902,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1896 | 1902 | ||
1897 | lock_kernel(); | 1903 | lock_kernel(); |
1898 | status = mxser_get_msr(info->ioaddr, 1, tty->index); | 1904 | status = mxser_get_msr(info->ioaddr, 1, tty->index); |
1899 | mxser_check_modem_status(info, status); | 1905 | mxser_check_modem_status(tty, info, status); |
1900 | 1906 | ||
1901 | mcr = inb(info->ioaddr + UART_MCR); | 1907 | mcr = inb(info->ioaddr + UART_MCR); |
1902 | if (mcr & MOXA_MUST_MCR_XON_FLAG) | 1908 | if (mcr & MOXA_MUST_MCR_XON_FLAG) |
@@ -1909,7 +1915,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1909 | else | 1915 | else |
1910 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; | 1916 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; |
1911 | 1917 | ||
1912 | if (info->port.tty->hw_stopped) | 1918 | if (tty->hw_stopped) |
1913 | info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; | 1919 | info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; |
1914 | else | 1920 | else |
1915 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; | 1921 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; |
@@ -1958,7 +1964,7 @@ static void mxser_stoprx(struct tty_struct *tty) | |||
1958 | } | 1964 | } |
1959 | } | 1965 | } |
1960 | 1966 | ||
1961 | if (info->port.tty->termios->c_cflag & CRTSCTS) { | 1967 | if (tty->termios->c_cflag & CRTSCTS) { |
1962 | info->MCR &= ~UART_MCR_RTS; | 1968 | info->MCR &= ~UART_MCR_RTS; |
1963 | outb(info->MCR, info->ioaddr + UART_MCR); | 1969 | outb(info->MCR, info->ioaddr + UART_MCR); |
1964 | } | 1970 | } |
@@ -1995,7 +2001,7 @@ static void mxser_unthrottle(struct tty_struct *tty) | |||
1995 | } | 2001 | } |
1996 | } | 2002 | } |
1997 | 2003 | ||
1998 | if (info->port.tty->termios->c_cflag & CRTSCTS) { | 2004 | if (tty->termios->c_cflag & CRTSCTS) { |
1999 | info->MCR |= UART_MCR_RTS; | 2005 | info->MCR |= UART_MCR_RTS; |
2000 | outb(info->MCR, info->ioaddr + UART_MCR); | 2006 | outb(info->MCR, info->ioaddr + UART_MCR); |
2001 | } | 2007 | } |
@@ -2040,7 +2046,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi | |||
2040 | unsigned long flags; | 2046 | unsigned long flags; |
2041 | 2047 | ||
2042 | spin_lock_irqsave(&info->slock, flags); | 2048 | spin_lock_irqsave(&info->slock, flags); |
2043 | mxser_change_speed(info, old_termios); | 2049 | mxser_change_speed(tty, old_termios); |
2044 | spin_unlock_irqrestore(&info->slock, flags); | 2050 | spin_unlock_irqrestore(&info->slock, flags); |
2045 | 2051 | ||
2046 | if ((old_termios->c_cflag & CRTSCTS) && | 2052 | if ((old_termios->c_cflag & CRTSCTS) && |
@@ -2138,10 +2144,10 @@ static void mxser_hangup(struct tty_struct *tty) | |||
2138 | struct mxser_port *info = tty->driver_data; | 2144 | struct mxser_port *info = tty->driver_data; |
2139 | 2145 | ||
2140 | mxser_flush_buffer(tty); | 2146 | mxser_flush_buffer(tty); |
2141 | mxser_shutdown(info); | 2147 | mxser_shutdown(tty); |
2142 | info->port.count = 0; | 2148 | info->port.count = 0; |
2143 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 2149 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
2144 | info->port.tty = NULL; | 2150 | tty_port_tty_set(&info->port, NULL); |
2145 | wake_up_interruptible(&info->port.open_wait); | 2151 | wake_up_interruptible(&info->port.open_wait); |
2146 | } | 2152 | } |
2147 | 2153 | ||
@@ -2164,9 +2170,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) | |||
2164 | return 0; | 2170 | return 0; |
2165 | } | 2171 | } |
2166 | 2172 | ||
2167 | static void mxser_receive_chars(struct mxser_port *port, int *status) | 2173 | static void mxser_receive_chars(struct tty_struct *tty, |
2174 | struct mxser_port *port, int *status) | ||
2168 | { | 2175 | { |
2169 | struct tty_struct *tty = port->port.tty; | ||
2170 | unsigned char ch, gdl; | 2176 | unsigned char ch, gdl; |
2171 | int ignored = 0; | 2177 | int ignored = 0; |
2172 | int cnt = 0; | 2178 | int cnt = 0; |
@@ -2174,9 +2180,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status) | |||
2174 | int max = 256; | 2180 | int max = 256; |
2175 | 2181 | ||
2176 | recv_room = tty->receive_room; | 2182 | recv_room = tty->receive_room; |
2177 | if ((recv_room == 0) && (!port->ldisc_stop_rx)) | 2183 | if (recv_room == 0 && !port->ldisc_stop_rx) |
2178 | mxser_stoprx(tty); | 2184 | mxser_stoprx(tty); |
2179 | |||
2180 | if (port->board->chip_flag != MOXA_OTHER_UART) { | 2185 | if (port->board->chip_flag != MOXA_OTHER_UART) { |
2181 | 2186 | ||
2182 | if (*status & UART_LSR_SPECIAL) | 2187 | if (*status & UART_LSR_SPECIAL) |
@@ -2253,7 +2258,7 @@ intr_old: | |||
2253 | } while (*status & UART_LSR_DR); | 2258 | } while (*status & UART_LSR_DR); |
2254 | 2259 | ||
2255 | end_intr: | 2260 | end_intr: |
2256 | mxvar_log.rxcnt[port->port.tty->index] += cnt; | 2261 | mxvar_log.rxcnt[tty->index] += cnt; |
2257 | port->mon_data.rxcnt += cnt; | 2262 | port->mon_data.rxcnt += cnt; |
2258 | port->mon_data.up_rxcnt += cnt; | 2263 | port->mon_data.up_rxcnt += cnt; |
2259 | 2264 | ||
@@ -2267,14 +2272,14 @@ end_intr: | |||
2267 | spin_lock(&port->slock); | 2272 | spin_lock(&port->slock); |
2268 | } | 2273 | } |
2269 | 2274 | ||
2270 | static void mxser_transmit_chars(struct mxser_port *port) | 2275 | static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) |
2271 | { | 2276 | { |
2272 | int count, cnt; | 2277 | int count, cnt; |
2273 | 2278 | ||
2274 | if (port->x_char) { | 2279 | if (port->x_char) { |
2275 | outb(port->x_char, port->ioaddr + UART_TX); | 2280 | outb(port->x_char, port->ioaddr + UART_TX); |
2276 | port->x_char = 0; | 2281 | port->x_char = 0; |
2277 | mxvar_log.txcnt[port->port.tty->index]++; | 2282 | mxvar_log.txcnt[tty->index]++; |
2278 | port->mon_data.txcnt++; | 2283 | port->mon_data.txcnt++; |
2279 | port->mon_data.up_txcnt++; | 2284 | port->mon_data.up_txcnt++; |
2280 | port->icount.tx++; | 2285 | port->icount.tx++; |
@@ -2284,8 +2289,8 @@ static void mxser_transmit_chars(struct mxser_port *port) | |||
2284 | if (port->port.xmit_buf == NULL) | 2289 | if (port->port.xmit_buf == NULL) |
2285 | return; | 2290 | return; |
2286 | 2291 | ||
2287 | if ((port->xmit_cnt <= 0) || port->port.tty->stopped || | 2292 | if (port->xmit_cnt <= 0 || tty->stopped || |
2288 | (port->port.tty->hw_stopped && | 2293 | (tty->hw_stopped && |
2289 | (port->type != PORT_16550A) && | 2294 | (port->type != PORT_16550A) && |
2290 | (!port->board->chip_flag))) { | 2295 | (!port->board->chip_flag))) { |
2291 | port->IER &= ~UART_IER_THRI; | 2296 | port->IER &= ~UART_IER_THRI; |
@@ -2302,14 +2307,14 @@ static void mxser_transmit_chars(struct mxser_port *port) | |||
2302 | if (--port->xmit_cnt <= 0) | 2307 | if (--port->xmit_cnt <= 0) |
2303 | break; | 2308 | break; |
2304 | } while (--count > 0); | 2309 | } while (--count > 0); |
2305 | mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt); | 2310 | mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); |
2306 | 2311 | ||
2307 | port->mon_data.txcnt += (cnt - port->xmit_cnt); | 2312 | port->mon_data.txcnt += (cnt - port->xmit_cnt); |
2308 | port->mon_data.up_txcnt += (cnt - port->xmit_cnt); | 2313 | port->mon_data.up_txcnt += (cnt - port->xmit_cnt); |
2309 | port->icount.tx += (cnt - port->xmit_cnt); | 2314 | port->icount.tx += (cnt - port->xmit_cnt); |
2310 | 2315 | ||
2311 | if (port->xmit_cnt < WAKEUP_CHARS) | 2316 | if (port->xmit_cnt < WAKEUP_CHARS && tty) |
2312 | tty_wakeup(port->port.tty); | 2317 | tty_wakeup(tty); |
2313 | 2318 | ||
2314 | if (port->xmit_cnt <= 0) { | 2319 | if (port->xmit_cnt <= 0) { |
2315 | port->IER &= ~UART_IER_THRI; | 2320 | port->IER &= ~UART_IER_THRI; |
@@ -2328,6 +2333,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2328 | int max, irqbits, bits, msr; | 2333 | int max, irqbits, bits, msr; |
2329 | unsigned int int_cnt, pass_counter = 0; | 2334 | unsigned int int_cnt, pass_counter = 0; |
2330 | int handled = IRQ_NONE; | 2335 | int handled = IRQ_NONE; |
2336 | struct tty_struct *tty; | ||
2331 | 2337 | ||
2332 | for (i = 0; i < MXSER_BOARDS; i++) | 2338 | for (i = 0; i < MXSER_BOARDS; i++) |
2333 | if (dev_id == &mxser_boards[i]) { | 2339 | if (dev_id == &mxser_boards[i]) { |
@@ -2360,13 +2366,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2360 | if (iir & UART_IIR_NO_INT) | 2366 | if (iir & UART_IIR_NO_INT) |
2361 | break; | 2367 | break; |
2362 | iir &= MOXA_MUST_IIR_MASK; | 2368 | iir &= MOXA_MUST_IIR_MASK; |
2363 | if (!port->port.tty || | 2369 | tty = tty_port_tty_get(&port->port); |
2370 | if (!tty || | ||
2364 | (port->port.flags & ASYNC_CLOSING) || | 2371 | (port->port.flags & ASYNC_CLOSING) || |
2365 | !(port->port.flags & | 2372 | !(port->port.flags & |
2366 | ASYNC_INITIALIZED)) { | 2373 | ASYNC_INITIALIZED)) { |
2367 | status = inb(port->ioaddr + UART_LSR); | 2374 | status = inb(port->ioaddr + UART_LSR); |
2368 | outb(0x27, port->ioaddr + UART_FCR); | 2375 | outb(0x27, port->ioaddr + UART_FCR); |
2369 | inb(port->ioaddr + UART_MSR); | 2376 | inb(port->ioaddr + UART_MSR); |
2377 | tty_kref_put(tty); | ||
2370 | break; | 2378 | break; |
2371 | } | 2379 | } |
2372 | 2380 | ||
@@ -2387,27 +2395,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2387 | iir == MOXA_MUST_IIR_RDA || | 2395 | iir == MOXA_MUST_IIR_RDA || |
2388 | iir == MOXA_MUST_IIR_RTO || | 2396 | iir == MOXA_MUST_IIR_RTO || |
2389 | iir == MOXA_MUST_IIR_LSR) | 2397 | iir == MOXA_MUST_IIR_LSR) |
2390 | mxser_receive_chars(port, | 2398 | mxser_receive_chars(tty, port, |
2391 | &status); | 2399 | &status); |
2392 | 2400 | ||
2393 | } else { | 2401 | } else { |
2394 | status &= port->read_status_mask; | 2402 | status &= port->read_status_mask; |
2395 | if (status & UART_LSR_DR) | 2403 | if (status & UART_LSR_DR) |
2396 | mxser_receive_chars(port, | 2404 | mxser_receive_chars(tty, port, |
2397 | &status); | 2405 | &status); |
2398 | } | 2406 | } |
2399 | msr = inb(port->ioaddr + UART_MSR); | 2407 | msr = inb(port->ioaddr + UART_MSR); |
2400 | if (msr & UART_MSR_ANY_DELTA) | 2408 | if (msr & UART_MSR_ANY_DELTA) |
2401 | mxser_check_modem_status(port, msr); | 2409 | mxser_check_modem_status(tty, port, msr); |
2402 | 2410 | ||
2403 | if (port->board->chip_flag) { | 2411 | if (port->board->chip_flag) { |
2404 | if (iir == 0x02 && (status & | 2412 | if (iir == 0x02 && (status & |
2405 | UART_LSR_THRE)) | 2413 | UART_LSR_THRE)) |
2406 | mxser_transmit_chars(port); | 2414 | mxser_transmit_chars(tty, port); |
2407 | } else { | 2415 | } else { |
2408 | if (status & UART_LSR_THRE) | 2416 | if (status & UART_LSR_THRE) |
2409 | mxser_transmit_chars(port); | 2417 | mxser_transmit_chars(tty, port); |
2410 | } | 2418 | } |
2419 | tty_kref_put(tty); | ||
2411 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); | 2420 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); |
2412 | spin_unlock(&port->slock); | 2421 | spin_unlock(&port->slock); |
2413 | } | 2422 | } |
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 69ec6399c714..bacb3e2872ae 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c | |||
@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
764 | break; | 764 | break; |
765 | 765 | ||
766 | default: | 766 | default: |
767 | error = n_tty_ioctl (tty, file, cmd, arg); | 767 | error = n_tty_ioctl_helper(tty, file, cmd, arg); |
768 | break; | 768 | break; |
769 | } | 769 | } |
770 | return error; | 770 | return error; |
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index ae377aa473ba..4a8215a89ad3 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c | |||
@@ -372,14 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo, | |||
372 | static void put_char(struct r3964_info *pInfo, unsigned char ch) | 372 | static void put_char(struct r3964_info *pInfo, unsigned char ch) |
373 | { | 373 | { |
374 | struct tty_struct *tty = pInfo->tty; | 374 | struct tty_struct *tty = pInfo->tty; |
375 | |||
376 | if (tty == NULL) | ||
377 | return; | ||
378 | |||
379 | /* FIXME: put_char should not be called from an IRQ */ | 375 | /* FIXME: put_char should not be called from an IRQ */ |
380 | if (tty->ops->put_char) { | 376 | tty_put_char(tty, ch); |
381 | tty->ops->put_char(tty, ch); | ||
382 | } | ||
383 | pInfo->bcc ^= ch; | 377 | pInfo->bcc ^= ch; |
384 | } | 378 | } |
385 | 379 | ||
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 708c2b1dbe51..efbfe9612658 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -26,7 +26,7 @@ | |||
26 | * | 26 | * |
27 | * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to | 27 | * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to |
28 | * waiting writing processes-Sapan Bhatia <sapan@corewars.org>. | 28 | * waiting writing processes-Sapan Bhatia <sapan@corewars.org>. |
29 | * Also fixed a bug in BLOCKING mode where write_chan returns | 29 | * Also fixed a bug in BLOCKING mode where n_tty_write returns |
30 | * EAGAIN | 30 | * EAGAIN |
31 | */ | 31 | */ |
32 | 32 | ||
@@ -99,6 +99,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, | |||
99 | 99 | ||
100 | static void n_tty_set_room(struct tty_struct *tty) | 100 | static void n_tty_set_room(struct tty_struct *tty) |
101 | { | 101 | { |
102 | /* tty->read_cnt is not read locked ? */ | ||
102 | int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; | 103 | int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; |
103 | 104 | ||
104 | /* | 105 | /* |
@@ -121,6 +122,16 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) | |||
121 | } | 122 | } |
122 | } | 123 | } |
123 | 124 | ||
125 | /** | ||
126 | * put_tty_queue - add character to tty | ||
127 | * @c: character | ||
128 | * @tty: tty device | ||
129 | * | ||
130 | * Add a character to the tty read_buf queue. This is done under the | ||
131 | * read_lock to serialize character addition and also to protect us | ||
132 | * against parallel reads or flushes | ||
133 | */ | ||
134 | |||
124 | static void put_tty_queue(unsigned char c, struct tty_struct *tty) | 135 | static void put_tty_queue(unsigned char c, struct tty_struct *tty) |
125 | { | 136 | { |
126 | unsigned long flags; | 137 | unsigned long flags; |
@@ -137,14 +148,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty) | |||
137 | * check_unthrottle - allow new receive data | 148 | * check_unthrottle - allow new receive data |
138 | * @tty; tty device | 149 | * @tty; tty device |
139 | * | 150 | * |
140 | * Check whether to call the driver.unthrottle function. | 151 | * Check whether to call the driver unthrottle functions |
141 | * We test the TTY_THROTTLED bit first so that it always | 152 | * |
142 | * indicates the current state. The decision about whether | ||
143 | * it is worth allowing more input has been taken by the caller. | ||
144 | * Can sleep, may be called under the atomic_read_lock mutex but | 153 | * Can sleep, may be called under the atomic_read_lock mutex but |
145 | * this is not guaranteed. | 154 | * this is not guaranteed. |
146 | */ | 155 | */ |
147 | |||
148 | static void check_unthrottle(struct tty_struct *tty) | 156 | static void check_unthrottle(struct tty_struct *tty) |
149 | { | 157 | { |
150 | if (tty->count) | 158 | if (tty->count) |
@@ -158,6 +166,8 @@ static void check_unthrottle(struct tty_struct *tty) | |||
158 | * Reset the read buffer counters, clear the flags, | 166 | * Reset the read buffer counters, clear the flags, |
159 | * and make sure the driver is unthrottled. Called | 167 | * and make sure the driver is unthrottled. Called |
160 | * from n_tty_open() and n_tty_flush_buffer(). | 168 | * from n_tty_open() and n_tty_flush_buffer(). |
169 | * | ||
170 | * Locking: tty_read_lock for read fields. | ||
161 | */ | 171 | */ |
162 | static void reset_buffer_flags(struct tty_struct *tty) | 172 | static void reset_buffer_flags(struct tty_struct *tty) |
163 | { | 173 | { |
@@ -181,7 +191,7 @@ static void reset_buffer_flags(struct tty_struct *tty) | |||
181 | * at hangup) or when the N_TTY line discipline internally has to | 191 | * at hangup) or when the N_TTY line discipline internally has to |
182 | * clean the pending queue (for example some signals). | 192 | * clean the pending queue (for example some signals). |
183 | * | 193 | * |
184 | * Locking: ctrl_lock | 194 | * Locking: ctrl_lock, read_lock. |
185 | */ | 195 | */ |
186 | 196 | ||
187 | static void n_tty_flush_buffer(struct tty_struct *tty) | 197 | static void n_tty_flush_buffer(struct tty_struct *tty) |
@@ -207,6 +217,8 @@ static void n_tty_flush_buffer(struct tty_struct *tty) | |||
207 | * | 217 | * |
208 | * Report the number of characters buffered to be delivered to user | 218 | * Report the number of characters buffered to be delivered to user |
209 | * at this instant in time. | 219 | * at this instant in time. |
220 | * | ||
221 | * Locking: read_lock | ||
210 | */ | 222 | */ |
211 | 223 | ||
212 | static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) | 224 | static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) |
@@ -346,7 +358,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
346 | * the simple cases normally found and helps to generate blocks of | 358 | * the simple cases normally found and helps to generate blocks of |
347 | * symbols for the console driver and thus improve performance. | 359 | * symbols for the console driver and thus improve performance. |
348 | * | 360 | * |
349 | * Called from write_chan under the tty layer write lock. Relies | 361 | * Called from n_tty_write under the tty layer write lock. Relies |
350 | * on lock_kernel for the tty->column state. | 362 | * on lock_kernel for the tty->column state. |
351 | */ | 363 | */ |
352 | 364 | ||
@@ -410,6 +422,8 @@ break_out: | |||
410 | * | 422 | * |
411 | * Echo user input back onto the screen. This must be called only when | 423 | * Echo user input back onto the screen. This must be called only when |
412 | * L_ECHO(tty) is true. Called from the driver receive_buf path. | 424 | * L_ECHO(tty) is true. Called from the driver receive_buf path. |
425 | * | ||
426 | * Relies on BKL for tty column locking | ||
413 | */ | 427 | */ |
414 | 428 | ||
415 | static void echo_char(unsigned char c, struct tty_struct *tty) | 429 | static void echo_char(unsigned char c, struct tty_struct *tty) |
@@ -422,6 +436,12 @@ static void echo_char(unsigned char c, struct tty_struct *tty) | |||
422 | opost(c, tty); | 436 | opost(c, tty); |
423 | } | 437 | } |
424 | 438 | ||
439 | /** | ||
440 | * finsh_erasing - complete erase | ||
441 | * @tty: tty doing the erase | ||
442 | * | ||
443 | * Relies on BKL for tty column locking | ||
444 | */ | ||
425 | static inline void finish_erasing(struct tty_struct *tty) | 445 | static inline void finish_erasing(struct tty_struct *tty) |
426 | { | 446 | { |
427 | if (tty->erasing) { | 447 | if (tty->erasing) { |
@@ -439,6 +459,8 @@ static inline void finish_erasing(struct tty_struct *tty) | |||
439 | * Perform erase and necessary output when an erase character is | 459 | * Perform erase and necessary output when an erase character is |
440 | * present in the stream from the driver layer. Handles the complexities | 460 | * present in the stream from the driver layer. Handles the complexities |
441 | * of UTF-8 multibyte symbols. | 461 | * of UTF-8 multibyte symbols. |
462 | * | ||
463 | * Locking: read_lock for tty buffers, BKL for column/erasing state | ||
442 | */ | 464 | */ |
443 | 465 | ||
444 | static void eraser(unsigned char c, struct tty_struct *tty) | 466 | static void eraser(unsigned char c, struct tty_struct *tty) |
@@ -447,6 +469,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
447 | int head, seen_alnums, cnt; | 469 | int head, seen_alnums, cnt; |
448 | unsigned long flags; | 470 | unsigned long flags; |
449 | 471 | ||
472 | /* FIXME: locking needed ? */ | ||
450 | if (tty->read_head == tty->canon_head) { | 473 | if (tty->read_head == tty->canon_head) { |
451 | /* opost('\a', tty); */ /* what do you think? */ | 474 | /* opost('\a', tty); */ /* what do you think? */ |
452 | return; | 475 | return; |
@@ -481,6 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
481 | } | 504 | } |
482 | 505 | ||
483 | seen_alnums = 0; | 506 | seen_alnums = 0; |
507 | /* FIXME: Locking ?? */ | ||
484 | while (tty->read_head != tty->canon_head) { | 508 | while (tty->read_head != tty->canon_head) { |
485 | head = tty->read_head; | 509 | head = tty->read_head; |
486 | 510 | ||
@@ -583,6 +607,8 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
583 | * may caus terminal flushing to take place according to the termios | 607 | * may caus terminal flushing to take place according to the termios |
584 | * settings and character used. Called from the driver receive_buf | 608 | * settings and character used. Called from the driver receive_buf |
585 | * path so serialized. | 609 | * path so serialized. |
610 | * | ||
611 | * Locking: ctrl_lock, read_lock (both via flush buffer) | ||
586 | */ | 612 | */ |
587 | 613 | ||
588 | static inline void isig(int sig, struct tty_struct *tty, int flush) | 614 | static inline void isig(int sig, struct tty_struct *tty, int flush) |
@@ -1007,12 +1033,26 @@ int is_ignored(int sig) | |||
1007 | * and is protected from re-entry by the tty layer. The user is | 1033 | * and is protected from re-entry by the tty layer. The user is |
1008 | * guaranteed that this function will not be re-entered or in progress | 1034 | * guaranteed that this function will not be re-entered or in progress |
1009 | * when the ldisc is closed. | 1035 | * when the ldisc is closed. |
1036 | * | ||
1037 | * Locking: Caller holds tty->termios_mutex | ||
1010 | */ | 1038 | */ |
1011 | 1039 | ||
1012 | static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | 1040 | static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) |
1013 | { | 1041 | { |
1014 | if (!tty) | 1042 | int canon_change = 1; |
1015 | return; | 1043 | BUG_ON(!tty); |
1044 | |||
1045 | if (old) | ||
1046 | canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; | ||
1047 | if (canon_change) { | ||
1048 | memset(&tty->read_flags, 0, sizeof tty->read_flags); | ||
1049 | tty->canon_head = tty->read_tail; | ||
1050 | tty->canon_data = 0; | ||
1051 | tty->erasing = 0; | ||
1052 | } | ||
1053 | |||
1054 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | ||
1055 | wake_up_interruptible(&tty->read_wait); | ||
1016 | 1056 | ||
1017 | tty->icanon = (L_ICANON(tty) != 0); | 1057 | tty->icanon = (L_ICANON(tty) != 0); |
1018 | if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { | 1058 | if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { |
@@ -1143,7 +1183,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) | |||
1143 | * @b: user data | 1183 | * @b: user data |
1144 | * @nr: size of data | 1184 | * @nr: size of data |
1145 | * | 1185 | * |
1146 | * Helper function to speed up read_chan. It is only called when | 1186 | * Helper function to speed up n_tty_read. It is only called when |
1147 | * ICANON is off; it copies characters straight from the tty queue to | 1187 | * ICANON is off; it copies characters straight from the tty queue to |
1148 | * user space directly. It can be profitably called twice; once to | 1188 | * user space directly. It can be profitably called twice; once to |
1149 | * drain the space from the tail pointer to the (physical) end of the | 1189 | * drain the space from the tail pointer to the (physical) end of the |
@@ -1210,7 +1250,7 @@ static int job_control(struct tty_struct *tty, struct file *file) | |||
1210 | if (file->f_op->write != redirected_tty_write && | 1250 | if (file->f_op->write != redirected_tty_write && |
1211 | current->signal->tty == tty) { | 1251 | current->signal->tty == tty) { |
1212 | if (!tty->pgrp) | 1252 | if (!tty->pgrp) |
1213 | printk(KERN_ERR "read_chan: no tty->pgrp!\n"); | 1253 | printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); |
1214 | else if (task_pgrp(current) != tty->pgrp) { | 1254 | else if (task_pgrp(current) != tty->pgrp) { |
1215 | if (is_ignored(SIGTTIN) || | 1255 | if (is_ignored(SIGTTIN) || |
1216 | is_current_pgrp_orphaned()) | 1256 | is_current_pgrp_orphaned()) |
@@ -1225,7 +1265,7 @@ static int job_control(struct tty_struct *tty, struct file *file) | |||
1225 | 1265 | ||
1226 | 1266 | ||
1227 | /** | 1267 | /** |
1228 | * read_chan - read function for tty | 1268 | * n_tty_read - read function for tty |
1229 | * @tty: tty device | 1269 | * @tty: tty device |
1230 | * @file: file object | 1270 | * @file: file object |
1231 | * @buf: userspace buffer pointer | 1271 | * @buf: userspace buffer pointer |
@@ -1239,7 +1279,7 @@ static int job_control(struct tty_struct *tty, struct file *file) | |||
1239 | * This code must be sure never to sleep through a hangup. | 1279 | * This code must be sure never to sleep through a hangup. |
1240 | */ | 1280 | */ |
1241 | 1281 | ||
1242 | static ssize_t read_chan(struct tty_struct *tty, struct file *file, | 1282 | static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, |
1243 | unsigned char __user *buf, size_t nr) | 1283 | unsigned char __user *buf, size_t nr) |
1244 | { | 1284 | { |
1245 | unsigned char __user *b = buf; | 1285 | unsigned char __user *b = buf; |
@@ -1254,10 +1294,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, | |||
1254 | 1294 | ||
1255 | do_it_again: | 1295 | do_it_again: |
1256 | 1296 | ||
1257 | if (!tty->read_buf) { | 1297 | BUG_ON(!tty->read_buf); |
1258 | printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n"); | ||
1259 | return -EIO; | ||
1260 | } | ||
1261 | 1298 | ||
1262 | c = job_control(tty, file); | 1299 | c = job_control(tty, file); |
1263 | if (c < 0) | 1300 | if (c < 0) |
@@ -1444,7 +1481,7 @@ do_it_again: | |||
1444 | } | 1481 | } |
1445 | 1482 | ||
1446 | /** | 1483 | /** |
1447 | * write_chan - write function for tty | 1484 | * n_tty_write - write function for tty |
1448 | * @tty: tty device | 1485 | * @tty: tty device |
1449 | * @file: file object | 1486 | * @file: file object |
1450 | * @buf: userspace buffer pointer | 1487 | * @buf: userspace buffer pointer |
@@ -1458,7 +1495,7 @@ do_it_again: | |||
1458 | * This code must be sure never to sleep through a hangup. | 1495 | * This code must be sure never to sleep through a hangup. |
1459 | */ | 1496 | */ |
1460 | 1497 | ||
1461 | static ssize_t write_chan(struct tty_struct *tty, struct file *file, | 1498 | static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, |
1462 | const unsigned char *buf, size_t nr) | 1499 | const unsigned char *buf, size_t nr) |
1463 | { | 1500 | { |
1464 | const unsigned char *b = buf; | 1501 | const unsigned char *b = buf; |
@@ -1532,7 +1569,7 @@ break_out: | |||
1532 | } | 1569 | } |
1533 | 1570 | ||
1534 | /** | 1571 | /** |
1535 | * normal_poll - poll method for N_TTY | 1572 | * n_tty_poll - poll method for N_TTY |
1536 | * @tty: terminal device | 1573 | * @tty: terminal device |
1537 | * @file: file accessing it | 1574 | * @file: file accessing it |
1538 | * @wait: poll table | 1575 | * @wait: poll table |
@@ -1545,7 +1582,7 @@ break_out: | |||
1545 | * Called without the kernel lock held - fine | 1582 | * Called without the kernel lock held - fine |
1546 | */ | 1583 | */ |
1547 | 1584 | ||
1548 | static unsigned int normal_poll(struct tty_struct *tty, struct file *file, | 1585 | static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, |
1549 | poll_table *wait) | 1586 | poll_table *wait) |
1550 | { | 1587 | { |
1551 | unsigned int mask = 0; | 1588 | unsigned int mask = 0; |
@@ -1573,6 +1610,44 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, | |||
1573 | return mask; | 1610 | return mask; |
1574 | } | 1611 | } |
1575 | 1612 | ||
1613 | static unsigned long inq_canon(struct tty_struct *tty) | ||
1614 | { | ||
1615 | int nr, head, tail; | ||
1616 | |||
1617 | if (!tty->canon_data) | ||
1618 | return 0; | ||
1619 | head = tty->canon_head; | ||
1620 | tail = tty->read_tail; | ||
1621 | nr = (head - tail) & (N_TTY_BUF_SIZE-1); | ||
1622 | /* Skip EOF-chars.. */ | ||
1623 | while (head != tail) { | ||
1624 | if (test_bit(tail, tty->read_flags) && | ||
1625 | tty->read_buf[tail] == __DISABLED_CHAR) | ||
1626 | nr--; | ||
1627 | tail = (tail+1) & (N_TTY_BUF_SIZE-1); | ||
1628 | } | ||
1629 | return nr; | ||
1630 | } | ||
1631 | |||
1632 | static int n_tty_ioctl(struct tty_struct *tty, struct file *file, | ||
1633 | unsigned int cmd, unsigned long arg) | ||
1634 | { | ||
1635 | int retval; | ||
1636 | |||
1637 | switch (cmd) { | ||
1638 | case TIOCOUTQ: | ||
1639 | return put_user(tty_chars_in_buffer(tty), (int __user *) arg); | ||
1640 | case TIOCINQ: | ||
1641 | /* FIXME: Locking */ | ||
1642 | retval = tty->read_cnt; | ||
1643 | if (L_ICANON(tty)) | ||
1644 | retval = inq_canon(tty); | ||
1645 | return put_user(retval, (unsigned int __user *) arg); | ||
1646 | default: | ||
1647 | return n_tty_ioctl_helper(tty, file, cmd, arg); | ||
1648 | } | ||
1649 | } | ||
1650 | |||
1576 | struct tty_ldisc_ops tty_ldisc_N_TTY = { | 1651 | struct tty_ldisc_ops tty_ldisc_N_TTY = { |
1577 | .magic = TTY_LDISC_MAGIC, | 1652 | .magic = TTY_LDISC_MAGIC, |
1578 | .name = "n_tty", | 1653 | .name = "n_tty", |
@@ -1580,11 +1655,11 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { | |||
1580 | .close = n_tty_close, | 1655 | .close = n_tty_close, |
1581 | .flush_buffer = n_tty_flush_buffer, | 1656 | .flush_buffer = n_tty_flush_buffer, |
1582 | .chars_in_buffer = n_tty_chars_in_buffer, | 1657 | .chars_in_buffer = n_tty_chars_in_buffer, |
1583 | .read = read_chan, | 1658 | .read = n_tty_read, |
1584 | .write = write_chan, | 1659 | .write = n_tty_write, |
1585 | .ioctl = n_tty_ioctl, | 1660 | .ioctl = n_tty_ioctl, |
1586 | .set_termios = n_tty_set_termios, | 1661 | .set_termios = n_tty_set_termios, |
1587 | .poll = normal_poll, | 1662 | .poll = n_tty_poll, |
1588 | .receive_buf = n_tty_receive_buf, | 1663 | .receive_buf = n_tty_receive_buf, |
1589 | .write_wakeup = n_tty_write_wakeup | 1664 | .write_wakeup = n_tty_write_wakeup |
1590 | }; | 1665 | }; |
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index 66a0f931c66c..9a34a1935283 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c | |||
@@ -1599,7 +1599,10 @@ static int ntty_open(struct tty_struct *tty, struct file *file) | |||
1599 | return 0; | 1599 | return 0; |
1600 | } | 1600 | } |
1601 | 1601 | ||
1602 | /* Called when the userspace process close the tty, /dev/noz*. */ | 1602 | /* Called when the userspace process close the tty, /dev/noz*. Also |
1603 | called immediately if ntty_open fails in which case tty->driver_data | ||
1604 | will be NULL an we exit by the first return */ | ||
1605 | |||
1603 | static void ntty_close(struct tty_struct *tty, struct file *file) | 1606 | static void ntty_close(struct tty_struct *tty, struct file *file) |
1604 | { | 1607 | { |
1605 | struct nozomi *dc = get_dc_by_tty(tty); | 1608 | struct nozomi *dc = get_dc_by_tty(tty); |
diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c index 3a23e7694d55..569f2f7743a7 100644 --- a/drivers/char/pcmcia/ipwireless/tty.c +++ b/drivers/char/pcmcia/ipwireless/tty.c | |||
@@ -276,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) | |||
276 | struct ipw_tty *tty = linux_tty->driver_data; | 276 | struct ipw_tty *tty = linux_tty->driver_data; |
277 | int room; | 277 | int room; |
278 | 278 | ||
279 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
279 | if (!tty) | 280 | if (!tty) |
280 | return -ENODEV; | 281 | return -ENODEV; |
281 | 282 | ||
@@ -397,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set, | |||
397 | static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) | 398 | static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) |
398 | { | 399 | { |
399 | struct ipw_tty *tty = linux_tty->driver_data; | 400 | struct ipw_tty *tty = linux_tty->driver_data; |
401 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
400 | 402 | ||
401 | if (!tty) | 403 | if (!tty) |
402 | return -ENODEV; | 404 | return -ENODEV; |
@@ -412,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file, | |||
412 | unsigned int set, unsigned int clear) | 414 | unsigned int set, unsigned int clear) |
413 | { | 415 | { |
414 | struct ipw_tty *tty = linux_tty->driver_data; | 416 | struct ipw_tty *tty = linux_tty->driver_data; |
417 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
415 | 418 | ||
416 | if (!tty) | 419 | if (!tty) |
417 | return -ENODEV; | 420 | return -ENODEV; |
@@ -433,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, | |||
433 | if (!tty->open_count) | 436 | if (!tty->open_count) |
434 | return -EINVAL; | 437 | return -EINVAL; |
435 | 438 | ||
439 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
440 | |||
436 | switch (cmd) { | 441 | switch (cmd) { |
437 | case TIOCGSERIAL: | 442 | case TIOCGSERIAL: |
438 | return ipwireless_get_serial_info(tty, (void __user *) arg); | 443 | return ipwireless_get_serial_info(tty, (void __user *) arg); |
@@ -467,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, | |||
467 | } | 472 | } |
468 | return 0; | 473 | return 0; |
469 | 474 | ||
470 | case TCGETS: | ||
471 | case TCGETA: | ||
472 | return n_tty_ioctl(linux_tty, file, cmd, arg); | ||
473 | |||
474 | case TCFLSH: | ||
475 | return n_tty_ioctl(linux_tty, file, cmd, arg); | ||
476 | |||
477 | case FIONREAD: | 475 | case FIONREAD: |
478 | { | 476 | { |
479 | int val = 0; | 477 | int val = 0; |
@@ -482,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, | |||
482 | return -EFAULT; | 480 | return -EFAULT; |
483 | } | 481 | } |
484 | return 0; | 482 | return 0; |
483 | case TCFLSH: | ||
484 | return tty_perform_flush(linux_tty, arg); | ||
485 | } | 485 | } |
486 | } | 486 | } |
487 | 487 | return tty_mode_ioctl(linux_tty, file, cmd , arg); | |
488 | return -ENOIOCTLCMD; | ||
489 | } | 488 | } |
490 | 489 | ||
491 | static int add_tty(dev_node_t *nodesp, int j, | 490 | static int add_tty(dev_node_t *nodesp, int j, |
@@ -588,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty) | |||
588 | tty_hangup(ttyj->linux_tty); | 587 | tty_hangup(ttyj->linux_tty); |
589 | /* Wait till the tty_hangup has completed */ | 588 | /* Wait till the tty_hangup has completed */ |
590 | flush_scheduled_work(); | 589 | flush_scheduled_work(); |
590 | /* FIXME: Exactly how is the tty object locked here | ||
591 | against a parallel ioctl etc */ | ||
591 | mutex_lock(&ttyj->ipw_tty_mutex); | 592 | mutex_lock(&ttyj->ipw_tty_mutex); |
592 | } | 593 | } |
593 | while (ttyj->open_count) | 594 | while (ttyj->open_count) |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 76b27932d229..6d4582712b1f 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -8,10 +8,12 @@ | |||
8 | * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to | 8 | * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to |
9 | * waiting writers -- Sapan Bhatia <sapan@corewars.org> | 9 | * waiting writers -- Sapan Bhatia <sapan@corewars.org> |
10 | * | 10 | * |
11 | * | 11 | * When reading this code see also fs/devpts. In particular note that the |
12 | * driver_data field is used by the devpts side as a binding to the devpts | ||
13 | * inode. | ||
12 | */ | 14 | */ |
13 | 15 | ||
14 | #include <linux/module.h> /* For EXPORT_SYMBOL */ | 16 | #include <linux/module.h> |
15 | 17 | ||
16 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
17 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
@@ -23,26 +25,25 @@ | |||
23 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
24 | #include <linux/init.h> | 26 | #include <linux/init.h> |
25 | #include <linux/sysctl.h> | 27 | #include <linux/sysctl.h> |
26 | 28 | #include <linux/device.h> | |
27 | #include <asm/uaccess.h> | 29 | #include <linux/uaccess.h> |
28 | #include <asm/system.h> | ||
29 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
30 | #include <linux/devpts_fs.h> | 31 | #include <linux/devpts_fs.h> |
31 | 32 | ||
33 | #include <asm/system.h> | ||
34 | |||
32 | /* These are global because they are accessed in tty_io.c */ | 35 | /* These are global because they are accessed in tty_io.c */ |
33 | #ifdef CONFIG_UNIX98_PTYS | 36 | #ifdef CONFIG_UNIX98_PTYS |
34 | struct tty_driver *ptm_driver; | 37 | struct tty_driver *ptm_driver; |
35 | static struct tty_driver *pts_driver; | 38 | static struct tty_driver *pts_driver; |
36 | #endif | 39 | #endif |
37 | 40 | ||
38 | static void pty_close(struct tty_struct * tty, struct file * filp) | 41 | static void pty_close(struct tty_struct *tty, struct file *filp) |
39 | { | 42 | { |
40 | if (!tty) | 43 | BUG_ON(!tty); |
41 | return; | 44 | if (tty->driver->subtype == PTY_TYPE_MASTER) |
42 | if (tty->driver->subtype == PTY_TYPE_MASTER) { | 45 | WARN_ON(tty->count > 1); |
43 | if (tty->count > 1) | 46 | else { |
44 | printk("master pty_close: count = %d!!\n", tty->count); | ||
45 | } else { | ||
46 | if (tty->count > 2) | 47 | if (tty->count > 2) |
47 | return; | 48 | return; |
48 | } | 49 | } |
@@ -59,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp) | |||
59 | set_bit(TTY_OTHER_CLOSED, &tty->flags); | 60 | set_bit(TTY_OTHER_CLOSED, &tty->flags); |
60 | #ifdef CONFIG_UNIX98_PTYS | 61 | #ifdef CONFIG_UNIX98_PTYS |
61 | if (tty->driver == ptm_driver) | 62 | if (tty->driver == ptm_driver) |
62 | devpts_pty_kill(tty->index); | 63 | devpts_pty_kill(tty->link); |
63 | #endif | 64 | #endif |
64 | tty_vhangup(tty->link); | 65 | tty_vhangup(tty->link); |
65 | } | 66 | } |
@@ -69,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp) | |||
69 | * The unthrottle routine is called by the line discipline to signal | 70 | * The unthrottle routine is called by the line discipline to signal |
70 | * that it can receive more characters. For PTY's, the TTY_THROTTLED | 71 | * that it can receive more characters. For PTY's, the TTY_THROTTLED |
71 | * flag is always set, to force the line discipline to always call the | 72 | * flag is always set, to force the line discipline to always call the |
72 | * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE | 73 | * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE |
73 | * characters in the queue. This is necessary since each time this | 74 | * characters in the queue. This is necessary since each time this |
74 | * happens, we need to wake up any sleeping processes that could be | 75 | * happens, we need to wake up any sleeping processes that could be |
75 | * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() | 76 | * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() |
76 | * for the pty buffer to be drained. | 77 | * for the pty buffer to be drained. |
77 | */ | 78 | */ |
78 | static void pty_unthrottle(struct tty_struct * tty) | 79 | static void pty_unthrottle(struct tty_struct *tty) |
79 | { | 80 | { |
80 | struct tty_struct *o_tty = tty->link; | 81 | struct tty_struct *o_tty = tty->link; |
81 | 82 | ||
@@ -87,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty) | |||
87 | } | 88 | } |
88 | 89 | ||
89 | /* | 90 | /* |
90 | * WSH 05/24/97: modified to | 91 | * WSH 05/24/97: modified to |
91 | * (1) use space in tty->flip instead of a shared temp buffer | 92 | * (1) use space in tty->flip instead of a shared temp buffer |
92 | * The flip buffers aren't being used for a pty, so there's lots | 93 | * The flip buffers aren't being used for a pty, so there's lots |
93 | * of space available. The buffer is protected by a per-pty | 94 | * of space available. The buffer is protected by a per-pty |
@@ -100,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty) | |||
100 | * not our partners. We can't just take the other one blindly without | 101 | * not our partners. We can't just take the other one blindly without |
101 | * risking deadlocks. | 102 | * risking deadlocks. |
102 | */ | 103 | */ |
103 | static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count) | 104 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, |
105 | int count) | ||
104 | { | 106 | { |
105 | struct tty_struct *to = tty->link; | 107 | struct tty_struct *to = tty->link; |
106 | int c; | 108 | int c; |
@@ -112,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun | |||
112 | if (c > count) | 114 | if (c > count) |
113 | c = count; | 115 | c = count; |
114 | to->ldisc.ops->receive_buf(to, buf, NULL, c); | 116 | to->ldisc.ops->receive_buf(to, buf, NULL, c); |
115 | 117 | ||
116 | return c; | 118 | return c; |
117 | } | 119 | } |
118 | 120 | ||
@@ -128,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty) | |||
128 | 130 | ||
129 | /* | 131 | /* |
130 | * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior | 132 | * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior |
131 | * The chars_in_buffer() value is used by the ldisc select() function | 133 | * The chars_in_buffer() value is used by the ldisc select() function |
132 | * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256). | 134 | * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256). |
133 | * The pty driver chars_in_buffer() Master/Slave must behave differently: | 135 | * The pty driver chars_in_buffer() Master/Slave must behave differently: |
134 | * | 136 | * |
135 | * The Master side needs to allow typed-ahead commands to accumulate | 137 | * The Master side needs to allow typed-ahead commands to accumulate |
136 | * while being canonicalized, so we report "our buffer" as empty until | 138 | * while being canonicalized, so we report "our buffer" as empty until |
137 | * some threshold is reached, and then report the count. (Any count > | 139 | * some threshold is reached, and then report the count. (Any count > |
138 | * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock | 140 | * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock |
139 | * the count returned must be 0 if no canonical data is available to be | 141 | * the count returned must be 0 if no canonical data is available to be |
140 | * read. (The N_TTY ldisc.chars_in_buffer now knows this.) | 142 | * read. (The N_TTY ldisc.chars_in_buffer now knows this.) |
141 | * | 143 | * |
142 | * The Slave side passes all characters in raw mode to the Master side's | 144 | * The Slave side passes all characters in raw mode to the Master side's |
143 | * buffer where they can be read immediately, so in this case we can | 145 | * buffer where they can be read immediately, so in this case we can |
144 | * return the true count in the buffer. | 146 | * return the true count in the buffer. |
@@ -155,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty) | |||
155 | /* The ldisc must report 0 if no characters available to be read */ | 157 | /* The ldisc must report 0 if no characters available to be read */ |
156 | count = to->ldisc.ops->chars_in_buffer(to); | 158 | count = to->ldisc.ops->chars_in_buffer(to); |
157 | 159 | ||
158 | if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; | 160 | if (tty->driver->subtype == PTY_TYPE_SLAVE) |
161 | return count; | ||
159 | 162 | ||
160 | /* Master side driver ... if the other side's read buffer is less than | 163 | /* Master side driver ... if the other side's read buffer is less than |
161 | * half full, return 0 to allow writers to proceed; otherwise return | 164 | * half full, return 0 to allow writers to proceed; otherwise return |
162 | * the count. This leaves a comfortable margin to avoid overflow, | 165 | * the count. This leaves a comfortable margin to avoid overflow, |
163 | * and still allows half a buffer's worth of typed-ahead commands. | 166 | * and still allows half a buffer's worth of typed-ahead commands. |
164 | */ | 167 | */ |
165 | return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); | 168 | return (count < N_TTY_BUF_SIZE/2) ? 0 : count; |
166 | } | 169 | } |
167 | 170 | ||
168 | /* Set the lock flag on a pty */ | 171 | /* Set the lock flag on a pty */ |
169 | static int pty_set_lock(struct tty_struct *tty, int __user * arg) | 172 | static int pty_set_lock(struct tty_struct *tty, int __user *arg) |
170 | { | 173 | { |
171 | int val; | 174 | int val; |
172 | if (get_user(val,arg)) | 175 | if (get_user(val, arg)) |
173 | return -EFAULT; | 176 | return -EFAULT; |
174 | if (val) | 177 | if (val) |
175 | set_bit(TTY_PTY_LOCK, &tty->flags); | 178 | set_bit(TTY_PTY_LOCK, &tty->flags); |
@@ -182,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty) | |||
182 | { | 185 | { |
183 | struct tty_struct *to = tty->link; | 186 | struct tty_struct *to = tty->link; |
184 | unsigned long flags; | 187 | unsigned long flags; |
185 | 188 | ||
186 | if (!to) | 189 | if (!to) |
187 | return; | 190 | return; |
188 | 191 | ||
189 | if (to->ldisc.ops->flush_buffer) | 192 | if (to->ldisc.ops->flush_buffer) |
190 | to->ldisc.ops->flush_buffer(to); | 193 | to->ldisc.ops->flush_buffer(to); |
191 | 194 | ||
192 | if (to->packet) { | 195 | if (to->packet) { |
193 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 196 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
194 | tty->ctrl_status |= TIOCPKT_FLUSHWRITE; | 197 | tty->ctrl_status |= TIOCPKT_FLUSHWRITE; |
@@ -197,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty) | |||
197 | } | 200 | } |
198 | } | 201 | } |
199 | 202 | ||
200 | static int pty_open(struct tty_struct *tty, struct file * filp) | 203 | static int pty_open(struct tty_struct *tty, struct file *filp) |
201 | { | 204 | { |
202 | int retval = -ENODEV; | 205 | int retval = -ENODEV; |
203 | 206 | ||
@@ -220,13 +223,65 @@ out: | |||
220 | return retval; | 223 | return retval; |
221 | } | 224 | } |
222 | 225 | ||
223 | static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | 226 | static void pty_set_termios(struct tty_struct *tty, |
227 | struct ktermios *old_termios) | ||
228 | { | ||
229 | tty->termios->c_cflag &= ~(CSIZE | PARENB); | ||
230 | tty->termios->c_cflag |= (CS8 | CREAD); | ||
231 | } | ||
232 | |||
233 | static int pty_install(struct tty_driver *driver, struct tty_struct *tty) | ||
224 | { | 234 | { |
225 | tty->termios->c_cflag &= ~(CSIZE | PARENB); | 235 | struct tty_struct *o_tty; |
226 | tty->termios->c_cflag |= (CS8 | CREAD); | 236 | int idx = tty->index; |
237 | int retval; | ||
238 | |||
239 | o_tty = alloc_tty_struct(); | ||
240 | if (!o_tty) | ||
241 | return -ENOMEM; | ||
242 | if (!try_module_get(driver->other->owner)) { | ||
243 | /* This cannot in fact currently happen */ | ||
244 | free_tty_struct(o_tty); | ||
245 | return -ENOMEM; | ||
246 | } | ||
247 | initialize_tty_struct(o_tty, driver->other, idx); | ||
248 | |||
249 | /* We always use new tty termios data so we can do this | ||
250 | the easy way .. */ | ||
251 | retval = tty_init_termios(tty); | ||
252 | if (retval) | ||
253 | goto free_mem_out; | ||
254 | |||
255 | retval = tty_init_termios(o_tty); | ||
256 | if (retval) { | ||
257 | tty_free_termios(tty); | ||
258 | goto free_mem_out; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * Everything allocated ... set up the o_tty structure. | ||
263 | */ | ||
264 | driver->other->ttys[idx] = o_tty; | ||
265 | tty_driver_kref_get(driver->other); | ||
266 | if (driver->subtype == PTY_TYPE_MASTER) | ||
267 | o_tty->count++; | ||
268 | /* Establish the links in both directions */ | ||
269 | tty->link = o_tty; | ||
270 | o_tty->link = tty; | ||
271 | |||
272 | tty_driver_kref_get(driver); | ||
273 | tty->count++; | ||
274 | driver->ttys[idx] = tty; | ||
275 | return 0; | ||
276 | free_mem_out: | ||
277 | module_put(o_tty->driver->owner); | ||
278 | free_tty_struct(o_tty); | ||
279 | return -ENOMEM; | ||
227 | } | 280 | } |
228 | 281 | ||
282 | |||
229 | static const struct tty_operations pty_ops = { | 283 | static const struct tty_operations pty_ops = { |
284 | .install = pty_install, | ||
230 | .open = pty_open, | 285 | .open = pty_open, |
231 | .close = pty_close, | 286 | .close = pty_close, |
232 | .write = pty_write, | 287 | .write = pty_write, |
@@ -329,8 +384,11 @@ static inline void legacy_pty_init(void) { } | |||
329 | * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. | 384 | * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. |
330 | */ | 385 | */ |
331 | int pty_limit = NR_UNIX98_PTY_DEFAULT; | 386 | int pty_limit = NR_UNIX98_PTY_DEFAULT; |
332 | static int pty_limit_min = 0; | 387 | static int pty_limit_min; |
333 | static int pty_limit_max = NR_UNIX98_PTY_MAX; | 388 | static int pty_limit_max = NR_UNIX98_PTY_MAX; |
389 | static int pty_count; | ||
390 | |||
391 | static struct cdev ptmx_cdev; | ||
334 | 392 | ||
335 | static struct ctl_table pty_table[] = { | 393 | static struct ctl_table pty_table[] = { |
336 | { | 394 | { |
@@ -348,6 +406,7 @@ static struct ctl_table pty_table[] = { | |||
348 | .procname = "nr", | 406 | .procname = "nr", |
349 | .maxlen = sizeof(int), | 407 | .maxlen = sizeof(int), |
350 | .mode = 0444, | 408 | .mode = 0444, |
409 | .data = &pty_count, | ||
351 | .proc_handler = &proc_dointvec, | 410 | .proc_handler = &proc_dointvec, |
352 | }, { | 411 | }, { |
353 | .ctl_name = 0 | 412 | .ctl_name = 0 |
@@ -388,7 +447,127 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, | |||
388 | return -ENOIOCTLCMD; | 447 | return -ENOIOCTLCMD; |
389 | } | 448 | } |
390 | 449 | ||
450 | /** | ||
451 | * ptm_unix98_lookup - find a pty master | ||
452 | * @driver: ptm driver | ||
453 | * @idx: tty index | ||
454 | * | ||
455 | * Look up a pty master device. Called under the tty_mutex for now. | ||
456 | * This provides our locking. | ||
457 | */ | ||
458 | |||
459 | static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, | ||
460 | struct inode *ptm_inode, int idx) | ||
461 | { | ||
462 | struct tty_struct *tty = devpts_get_tty(ptm_inode, idx); | ||
463 | if (tty) | ||
464 | tty = tty->link; | ||
465 | return tty; | ||
466 | } | ||
467 | |||
468 | /** | ||
469 | * pts_unix98_lookup - find a pty slave | ||
470 | * @driver: pts driver | ||
471 | * @idx: tty index | ||
472 | * | ||
473 | * Look up a pty master device. Called under the tty_mutex for now. | ||
474 | * This provides our locking. | ||
475 | */ | ||
476 | |||
477 | static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, | ||
478 | struct inode *pts_inode, int idx) | ||
479 | { | ||
480 | struct tty_struct *tty = devpts_get_tty(pts_inode, idx); | ||
481 | /* Master must be open before slave */ | ||
482 | if (!tty) | ||
483 | return ERR_PTR(-EIO); | ||
484 | return tty; | ||
485 | } | ||
486 | |||
487 | static void pty_unix98_shutdown(struct tty_struct *tty) | ||
488 | { | ||
489 | /* We have our own method as we don't use the tty index */ | ||
490 | kfree(tty->termios); | ||
491 | } | ||
492 | |||
493 | /* We have no need to install and remove our tty objects as devpts does all | ||
494 | the work for us */ | ||
495 | |||
496 | static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) | ||
497 | { | ||
498 | struct tty_struct *o_tty; | ||
499 | int idx = tty->index; | ||
500 | |||
501 | o_tty = alloc_tty_struct(); | ||
502 | if (!o_tty) | ||
503 | return -ENOMEM; | ||
504 | if (!try_module_get(driver->other->owner)) { | ||
505 | /* This cannot in fact currently happen */ | ||
506 | free_tty_struct(o_tty); | ||
507 | return -ENOMEM; | ||
508 | } | ||
509 | initialize_tty_struct(o_tty, driver->other, idx); | ||
510 | |||
511 | tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); | ||
512 | if (tty->termios == NULL) | ||
513 | goto free_mem_out; | ||
514 | *tty->termios = driver->init_termios; | ||
515 | tty->termios_locked = tty->termios + 1; | ||
516 | |||
517 | o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); | ||
518 | if (o_tty->termios == NULL) | ||
519 | goto free_mem_out; | ||
520 | *o_tty->termios = driver->other->init_termios; | ||
521 | o_tty->termios_locked = o_tty->termios + 1; | ||
522 | |||
523 | tty_driver_kref_get(driver->other); | ||
524 | if (driver->subtype == PTY_TYPE_MASTER) | ||
525 | o_tty->count++; | ||
526 | /* Establish the links in both directions */ | ||
527 | tty->link = o_tty; | ||
528 | o_tty->link = tty; | ||
529 | /* | ||
530 | * All structures have been allocated, so now we install them. | ||
531 | * Failures after this point use release_tty to clean up, so | ||
532 | * there's no need to null out the local pointers. | ||
533 | */ | ||
534 | tty_driver_kref_get(driver); | ||
535 | tty->count++; | ||
536 | pty_count++; | ||
537 | return 0; | ||
538 | free_mem_out: | ||
539 | kfree(o_tty->termios); | ||
540 | module_put(o_tty->driver->owner); | ||
541 | free_tty_struct(o_tty); | ||
542 | kfree(tty->termios); | ||
543 | return -ENOMEM; | ||
544 | } | ||
545 | |||
546 | static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) | ||
547 | { | ||
548 | pty_count--; | ||
549 | } | ||
550 | |||
551 | static const struct tty_operations ptm_unix98_ops = { | ||
552 | .lookup = ptm_unix98_lookup, | ||
553 | .install = pty_unix98_install, | ||
554 | .remove = pty_unix98_remove, | ||
555 | .open = pty_open, | ||
556 | .close = pty_close, | ||
557 | .write = pty_write, | ||
558 | .write_room = pty_write_room, | ||
559 | .flush_buffer = pty_flush_buffer, | ||
560 | .chars_in_buffer = pty_chars_in_buffer, | ||
561 | .unthrottle = pty_unthrottle, | ||
562 | .set_termios = pty_set_termios, | ||
563 | .ioctl = pty_unix98_ioctl, | ||
564 | .shutdown = pty_unix98_shutdown | ||
565 | }; | ||
566 | |||
391 | static const struct tty_operations pty_unix98_ops = { | 567 | static const struct tty_operations pty_unix98_ops = { |
568 | .lookup = pts_unix98_lookup, | ||
569 | .install = pty_unix98_install, | ||
570 | .remove = pty_unix98_remove, | ||
392 | .open = pty_open, | 571 | .open = pty_open, |
393 | .close = pty_close, | 572 | .close = pty_close, |
394 | .write = pty_write, | 573 | .write = pty_write, |
@@ -397,9 +576,73 @@ static const struct tty_operations pty_unix98_ops = { | |||
397 | .chars_in_buffer = pty_chars_in_buffer, | 576 | .chars_in_buffer = pty_chars_in_buffer, |
398 | .unthrottle = pty_unthrottle, | 577 | .unthrottle = pty_unthrottle, |
399 | .set_termios = pty_set_termios, | 578 | .set_termios = pty_set_termios, |
400 | .ioctl = pty_unix98_ioctl | 579 | .shutdown = pty_unix98_shutdown |
401 | }; | 580 | }; |
402 | 581 | ||
582 | /** | ||
583 | * ptmx_open - open a unix 98 pty master | ||
584 | * @inode: inode of device file | ||
585 | * @filp: file pointer to tty | ||
586 | * | ||
587 | * Allocate a unix98 pty master device from the ptmx driver. | ||
588 | * | ||
589 | * Locking: tty_mutex protects the init_dev work. tty->count should | ||
590 | * protect the rest. | ||
591 | * allocated_ptys_lock handles the list of free pty numbers | ||
592 | */ | ||
593 | |||
594 | static int __ptmx_open(struct inode *inode, struct file *filp) | ||
595 | { | ||
596 | struct tty_struct *tty; | ||
597 | int retval; | ||
598 | int index; | ||
599 | |||
600 | nonseekable_open(inode, filp); | ||
601 | |||
602 | /* find a device that is not in use. */ | ||
603 | index = devpts_new_index(inode); | ||
604 | if (index < 0) | ||
605 | return index; | ||
606 | |||
607 | mutex_lock(&tty_mutex); | ||
608 | tty = tty_init_dev(ptm_driver, index, 1); | ||
609 | mutex_unlock(&tty_mutex); | ||
610 | |||
611 | if (IS_ERR(tty)) { | ||
612 | retval = PTR_ERR(tty); | ||
613 | goto out; | ||
614 | } | ||
615 | |||
616 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | ||
617 | filp->private_data = tty; | ||
618 | file_move(filp, &tty->tty_files); | ||
619 | |||
620 | retval = devpts_pty_new(inode, tty->link); | ||
621 | if (retval) | ||
622 | goto out1; | ||
623 | |||
624 | retval = ptm_driver->ops->open(tty, filp); | ||
625 | if (!retval) | ||
626 | return 0; | ||
627 | out1: | ||
628 | tty_release_dev(filp); | ||
629 | return retval; | ||
630 | out: | ||
631 | devpts_kill_index(inode, index); | ||
632 | return retval; | ||
633 | } | ||
634 | |||
635 | static int ptmx_open(struct inode *inode, struct file *filp) | ||
636 | { | ||
637 | int ret; | ||
638 | |||
639 | lock_kernel(); | ||
640 | ret = __ptmx_open(inode, filp); | ||
641 | unlock_kernel(); | ||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | static struct file_operations ptmx_fops; | ||
403 | 646 | ||
404 | static void __init unix98_pty_init(void) | 647 | static void __init unix98_pty_init(void) |
405 | { | 648 | { |
@@ -427,7 +670,7 @@ static void __init unix98_pty_init(void) | |||
427 | ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | | 670 | ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | |
428 | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; | 671 | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; |
429 | ptm_driver->other = pts_driver; | 672 | ptm_driver->other = pts_driver; |
430 | tty_set_operations(ptm_driver, &pty_unix98_ops); | 673 | tty_set_operations(ptm_driver, &ptm_unix98_ops); |
431 | 674 | ||
432 | pts_driver->owner = THIS_MODULE; | 675 | pts_driver->owner = THIS_MODULE; |
433 | pts_driver->driver_name = "pty_slave"; | 676 | pts_driver->driver_name = "pty_slave"; |
@@ -443,16 +686,26 @@ static void __init unix98_pty_init(void) | |||
443 | pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | | 686 | pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | |
444 | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; | 687 | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; |
445 | pts_driver->other = ptm_driver; | 688 | pts_driver->other = ptm_driver; |
446 | tty_set_operations(pts_driver, &pty_ops); | 689 | tty_set_operations(pts_driver, &pty_unix98_ops); |
447 | 690 | ||
448 | if (tty_register_driver(ptm_driver)) | 691 | if (tty_register_driver(ptm_driver)) |
449 | panic("Couldn't register Unix98 ptm driver"); | 692 | panic("Couldn't register Unix98 ptm driver"); |
450 | if (tty_register_driver(pts_driver)) | 693 | if (tty_register_driver(pts_driver)) |
451 | panic("Couldn't register Unix98 pts driver"); | 694 | panic("Couldn't register Unix98 pts driver"); |
452 | 695 | ||
453 | pty_table[1].data = &ptm_driver->refcount; | ||
454 | register_sysctl_table(pty_root_table); | 696 | register_sysctl_table(pty_root_table); |
697 | |||
698 | /* Now create the /dev/ptmx special device */ | ||
699 | tty_default_fops(&ptmx_fops); | ||
700 | ptmx_fops.open = ptmx_open; | ||
701 | |||
702 | cdev_init(&ptmx_cdev, &ptmx_fops); | ||
703 | if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || | ||
704 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) | ||
705 | panic("Couldn't register /dev/ptmx driver\n"); | ||
706 | device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); | ||
455 | } | 707 | } |
708 | |||
456 | #else | 709 | #else |
457 | static inline void unix98_pty_init(void) { } | 710 | static inline void unix98_pty_init(void) { } |
458 | #endif | 711 | #endif |
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 19db1eb87c26..8b8f07a7f505 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c | |||
@@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = { | |||
405 | 405 | ||
406 | static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); | 406 | static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); |
407 | static int stl_brdinit(struct stlbrd *brdp); | 407 | static int stl_brdinit(struct stlbrd *brdp); |
408 | static int stl_getportstats(struct stlport *portp, comstats_t __user *cp); | 408 | static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp); |
409 | static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); | 409 | static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); |
410 | static int stl_waitcarrier(struct stlport *portp, struct file *filp); | 410 | static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp); |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * CD1400 uart specific handling functions. | 413 | * CD1400 uart specific handling functions. |
@@ -612,8 +612,9 @@ static struct class *stallion_class; | |||
612 | static void stl_cd_change(struct stlport *portp) | 612 | static void stl_cd_change(struct stlport *portp) |
613 | { | 613 | { |
614 | unsigned int oldsigs = portp->sigs; | 614 | unsigned int oldsigs = portp->sigs; |
615 | struct tty_struct *tty = tty_port_tty_get(&portp->port); | ||
615 | 616 | ||
616 | if (!portp->port.tty) | 617 | if (!tty) |
617 | return; | 618 | return; |
618 | 619 | ||
619 | portp->sigs = stl_getsignals(portp); | 620 | portp->sigs = stl_getsignals(portp); |
@@ -623,7 +624,8 @@ static void stl_cd_change(struct stlport *portp) | |||
623 | 624 | ||
624 | if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) | 625 | if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) |
625 | if (portp->port.flags & ASYNC_CHECK_CD) | 626 | if (portp->port.flags & ASYNC_CHECK_CD) |
626 | tty_hangup(portp->port.tty); | 627 | tty_hangup(tty); |
628 | tty_kref_put(tty); | ||
627 | } | 629 | } |
628 | 630 | ||
629 | /* | 631 | /* |
@@ -734,7 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) | |||
734 | * On the first open of the device setup the port hardware, and | 736 | * On the first open of the device setup the port hardware, and |
735 | * initialize the per port data structure. | 737 | * initialize the per port data structure. |
736 | */ | 738 | */ |
737 | portp->port.tty = tty; | 739 | tty_port_tty_set(&portp->port, tty); |
738 | tty->driver_data = portp; | 740 | tty->driver_data = portp; |
739 | portp->port.count++; | 741 | portp->port.count++; |
740 | 742 | ||
@@ -774,7 +776,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) | |||
774 | * then also we might have to wait for carrier. | 776 | * then also we might have to wait for carrier. |
775 | */ | 777 | */ |
776 | if (!(filp->f_flags & O_NONBLOCK)) | 778 | if (!(filp->f_flags & O_NONBLOCK)) |
777 | if ((rc = stl_waitcarrier(portp, filp)) != 0) | 779 | if ((rc = stl_waitcarrier(tty, portp, filp)) != 0) |
778 | return rc; | 780 | return rc; |
779 | 781 | ||
780 | portp->port.flags |= ASYNC_NORMAL_ACTIVE; | 782 | portp->port.flags |= ASYNC_NORMAL_ACTIVE; |
@@ -789,7 +791,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp) | |||
789 | * maybe because if we are clocal then we don't need to wait... | 791 | * maybe because if we are clocal then we don't need to wait... |
790 | */ | 792 | */ |
791 | 793 | ||
792 | static int stl_waitcarrier(struct stlport *portp, struct file *filp) | 794 | static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, |
795 | struct file *filp) | ||
793 | { | 796 | { |
794 | unsigned long flags; | 797 | unsigned long flags; |
795 | int rc, doclocal; | 798 | int rc, doclocal; |
@@ -801,7 +804,7 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp) | |||
801 | 804 | ||
802 | spin_lock_irqsave(&stallion_lock, flags); | 805 | spin_lock_irqsave(&stallion_lock, flags); |
803 | 806 | ||
804 | if (portp->port.tty->termios->c_cflag & CLOCAL) | 807 | if (tty->termios->c_cflag & CLOCAL) |
805 | doclocal++; | 808 | doclocal++; |
806 | 809 | ||
807 | portp->openwaitcnt++; | 810 | portp->openwaitcnt++; |
@@ -846,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty) | |||
846 | 849 | ||
847 | pr_debug("stl_flushbuffer(tty=%p)\n", tty); | 850 | pr_debug("stl_flushbuffer(tty=%p)\n", tty); |
848 | 851 | ||
849 | if (tty == NULL) | ||
850 | return; | ||
851 | portp = tty->driver_data; | 852 | portp = tty->driver_data; |
852 | if (portp == NULL) | 853 | if (portp == NULL) |
853 | return; | 854 | return; |
@@ -865,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) | |||
865 | 866 | ||
866 | pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); | 867 | pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); |
867 | 868 | ||
868 | if (tty == NULL) | ||
869 | return; | ||
870 | portp = tty->driver_data; | 869 | portp = tty->driver_data; |
871 | if (portp == NULL) | 870 | if (portp == NULL) |
872 | return; | 871 | return; |
@@ -949,7 +948,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) | |||
949 | tty_ldisc_flush(tty); | 948 | tty_ldisc_flush(tty); |
950 | 949 | ||
951 | tty->closing = 0; | 950 | tty->closing = 0; |
952 | portp->port.tty = NULL; | 951 | tty_port_tty_set(&portp->port, NULL); |
953 | 952 | ||
954 | if (portp->openwaitcnt) { | 953 | if (portp->openwaitcnt) { |
955 | if (portp->close_delay) | 954 | if (portp->close_delay) |
@@ -1033,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch) | |||
1033 | 1032 | ||
1034 | pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch); | 1033 | pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch); |
1035 | 1034 | ||
1036 | if (tty == NULL) | ||
1037 | return -EINVAL; | ||
1038 | portp = tty->driver_data; | 1035 | portp = tty->driver_data; |
1039 | if (portp == NULL) | 1036 | if (portp == NULL) |
1040 | return -EINVAL; | 1037 | return -EINVAL; |
@@ -1070,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty) | |||
1070 | 1067 | ||
1071 | pr_debug("stl_flushchars(tty=%p)\n", tty); | 1068 | pr_debug("stl_flushchars(tty=%p)\n", tty); |
1072 | 1069 | ||
1073 | if (tty == NULL) | ||
1074 | return; | ||
1075 | portp = tty->driver_data; | 1070 | portp = tty->driver_data; |
1076 | if (portp == NULL) | 1071 | if (portp == NULL) |
1077 | return; | 1072 | return; |
@@ -1090,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty) | |||
1090 | 1085 | ||
1091 | pr_debug("stl_writeroom(tty=%p)\n", tty); | 1086 | pr_debug("stl_writeroom(tty=%p)\n", tty); |
1092 | 1087 | ||
1093 | if (tty == NULL) | ||
1094 | return 0; | ||
1095 | portp = tty->driver_data; | 1088 | portp = tty->driver_data; |
1096 | if (portp == NULL) | 1089 | if (portp == NULL) |
1097 | return 0; | 1090 | return 0; |
@@ -1122,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty) | |||
1122 | 1115 | ||
1123 | pr_debug("stl_charsinbuffer(tty=%p)\n", tty); | 1116 | pr_debug("stl_charsinbuffer(tty=%p)\n", tty); |
1124 | 1117 | ||
1125 | if (tty == NULL) | ||
1126 | return 0; | ||
1127 | portp = tty->driver_data; | 1118 | portp = tty->driver_data; |
1128 | if (portp == NULL) | 1119 | if (portp == NULL) |
1129 | return 0; | 1120 | return 0; |
@@ -1183,8 +1174,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) | |||
1183 | * just quietly ignore any requests to change irq, etc. | 1174 | * just quietly ignore any requests to change irq, etc. |
1184 | */ | 1175 | */ |
1185 | 1176 | ||
1186 | static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) | 1177 | static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp) |
1187 | { | 1178 | { |
1179 | struct stlport * portp = tty->driver_data; | ||
1188 | struct serial_struct sio; | 1180 | struct serial_struct sio; |
1189 | 1181 | ||
1190 | pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp); | 1182 | pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp); |
@@ -1205,7 +1197,7 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) | |||
1205 | portp->close_delay = sio.close_delay; | 1197 | portp->close_delay = sio.close_delay; |
1206 | portp->closing_wait = sio.closing_wait; | 1198 | portp->closing_wait = sio.closing_wait; |
1207 | portp->custom_divisor = sio.custom_divisor; | 1199 | portp->custom_divisor = sio.custom_divisor; |
1208 | stl_setport(portp, portp->port.tty->termios); | 1200 | stl_setport(portp, tty->termios); |
1209 | return 0; | 1201 | return 0; |
1210 | } | 1202 | } |
1211 | 1203 | ||
@@ -1215,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file) | |||
1215 | { | 1207 | { |
1216 | struct stlport *portp; | 1208 | struct stlport *portp; |
1217 | 1209 | ||
1218 | if (tty == NULL) | ||
1219 | return -ENODEV; | ||
1220 | portp = tty->driver_data; | 1210 | portp = tty->driver_data; |
1221 | if (portp == NULL) | 1211 | if (portp == NULL) |
1222 | return -ENODEV; | 1212 | return -ENODEV; |
@@ -1232,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file, | |||
1232 | struct stlport *portp; | 1222 | struct stlport *portp; |
1233 | int rts = -1, dtr = -1; | 1223 | int rts = -1, dtr = -1; |
1234 | 1224 | ||
1235 | if (tty == NULL) | ||
1236 | return -ENODEV; | ||
1237 | portp = tty->driver_data; | 1225 | portp = tty->driver_data; |
1238 | if (portp == NULL) | 1226 | if (portp == NULL) |
1239 | return -ENODEV; | 1227 | return -ENODEV; |
@@ -1262,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd | |||
1262 | pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd, | 1250 | pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd, |
1263 | arg); | 1251 | arg); |
1264 | 1252 | ||
1265 | if (tty == NULL) | ||
1266 | return -ENODEV; | ||
1267 | portp = tty->driver_data; | 1253 | portp = tty->driver_data; |
1268 | if (portp == NULL) | 1254 | if (portp == NULL) |
1269 | return -ENODEV; | 1255 | return -ENODEV; |
@@ -1282,10 +1268,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd | |||
1282 | rc = stl_getserial(portp, argp); | 1268 | rc = stl_getserial(portp, argp); |
1283 | break; | 1269 | break; |
1284 | case TIOCSSERIAL: | 1270 | case TIOCSSERIAL: |
1285 | rc = stl_setserial(portp, argp); | 1271 | rc = stl_setserial(tty, argp); |
1286 | break; | 1272 | break; |
1287 | case COM_GETPORTSTATS: | 1273 | case COM_GETPORTSTATS: |
1288 | rc = stl_getportstats(portp, argp); | 1274 | rc = stl_getportstats(tty, portp, argp); |
1289 | break; | 1275 | break; |
1290 | case COM_CLRPORTSTATS: | 1276 | case COM_CLRPORTSTATS: |
1291 | rc = stl_clrportstats(portp, argp); | 1277 | rc = stl_clrportstats(portp, argp); |
@@ -1317,8 +1303,6 @@ static void stl_start(struct tty_struct *tty) | |||
1317 | 1303 | ||
1318 | pr_debug("stl_start(tty=%p)\n", tty); | 1304 | pr_debug("stl_start(tty=%p)\n", tty); |
1319 | 1305 | ||
1320 | if (tty == NULL) | ||
1321 | return; | ||
1322 | portp = tty->driver_data; | 1306 | portp = tty->driver_data; |
1323 | if (portp == NULL) | 1307 | if (portp == NULL) |
1324 | return; | 1308 | return; |
@@ -1334,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old) | |||
1334 | 1318 | ||
1335 | pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); | 1319 | pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); |
1336 | 1320 | ||
1337 | if (tty == NULL) | ||
1338 | return; | ||
1339 | portp = tty->driver_data; | 1321 | portp = tty->driver_data; |
1340 | if (portp == NULL) | 1322 | if (portp == NULL) |
1341 | return; | 1323 | return; |
@@ -1369,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty) | |||
1369 | 1351 | ||
1370 | pr_debug("stl_throttle(tty=%p)\n", tty); | 1352 | pr_debug("stl_throttle(tty=%p)\n", tty); |
1371 | 1353 | ||
1372 | if (tty == NULL) | ||
1373 | return; | ||
1374 | portp = tty->driver_data; | 1354 | portp = tty->driver_data; |
1375 | if (portp == NULL) | 1355 | if (portp == NULL) |
1376 | return; | 1356 | return; |
@@ -1389,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty) | |||
1389 | 1369 | ||
1390 | pr_debug("stl_unthrottle(tty=%p)\n", tty); | 1370 | pr_debug("stl_unthrottle(tty=%p)\n", tty); |
1391 | 1371 | ||
1392 | if (tty == NULL) | ||
1393 | return; | ||
1394 | portp = tty->driver_data; | 1372 | portp = tty->driver_data; |
1395 | if (portp == NULL) | 1373 | if (portp == NULL) |
1396 | return; | 1374 | return; |
@@ -1410,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty) | |||
1410 | 1388 | ||
1411 | pr_debug("stl_stop(tty=%p)\n", tty); | 1389 | pr_debug("stl_stop(tty=%p)\n", tty); |
1412 | 1390 | ||
1413 | if (tty == NULL) | ||
1414 | return; | ||
1415 | portp = tty->driver_data; | 1391 | portp = tty->driver_data; |
1416 | if (portp == NULL) | 1392 | if (portp == NULL) |
1417 | return; | 1393 | return; |
@@ -1432,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty) | |||
1432 | 1408 | ||
1433 | pr_debug("stl_hangup(tty=%p)\n", tty); | 1409 | pr_debug("stl_hangup(tty=%p)\n", tty); |
1434 | 1410 | ||
1435 | if (tty == NULL) | ||
1436 | return; | ||
1437 | portp = tty->driver_data; | 1411 | portp = tty->driver_data; |
1438 | if (portp == NULL) | 1412 | if (portp == NULL) |
1439 | return; | 1413 | return; |
@@ -1452,7 +1426,7 @@ static void stl_hangup(struct tty_struct *tty) | |||
1452 | portp->tx.head = NULL; | 1426 | portp->tx.head = NULL; |
1453 | portp->tx.tail = NULL; | 1427 | portp->tx.tail = NULL; |
1454 | } | 1428 | } |
1455 | portp->port.tty = NULL; | 1429 | tty_port_tty_set(&portp->port, NULL); |
1456 | portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1430 | portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
1457 | portp->port.count = 0; | 1431 | portp->port.count = 0; |
1458 | wake_up_interruptible(&portp->port.open_wait); | 1432 | wake_up_interruptible(&portp->port.open_wait); |
@@ -1466,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state) | |||
1466 | 1440 | ||
1467 | pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); | 1441 | pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); |
1468 | 1442 | ||
1469 | if (tty == NULL) | ||
1470 | return -EINVAL; | ||
1471 | portp = tty->driver_data; | 1443 | portp = tty->driver_data; |
1472 | if (portp == NULL) | 1444 | if (portp == NULL) |
1473 | return -EINVAL; | 1445 | return -EINVAL; |
@@ -1484,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) | |||
1484 | 1456 | ||
1485 | pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); | 1457 | pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); |
1486 | 1458 | ||
1487 | if (tty == NULL) | ||
1488 | return; | ||
1489 | portp = tty->driver_data; | 1459 | portp = tty->driver_data; |
1490 | if (portp == NULL) | 1460 | if (portp == NULL) |
1491 | return; | 1461 | return; |
@@ -1805,7 +1775,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) | |||
1805 | "(size=%Zd)\n", sizeof(struct stlport)); | 1775 | "(size=%Zd)\n", sizeof(struct stlport)); |
1806 | break; | 1776 | break; |
1807 | } | 1777 | } |
1808 | 1778 | tty_port_init(&portp->port); | |
1809 | portp->magic = STL_PORTMAGIC; | 1779 | portp->magic = STL_PORTMAGIC; |
1810 | portp->portnr = i; | 1780 | portp->portnr = i; |
1811 | portp->brdnr = panelp->brdnr; | 1781 | portp->brdnr = panelp->brdnr; |
@@ -1832,6 +1802,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp) | |||
1832 | struct stlpanel *panelp; | 1802 | struct stlpanel *panelp; |
1833 | struct stlport *portp; | 1803 | struct stlport *portp; |
1834 | unsigned int j, k; | 1804 | unsigned int j, k; |
1805 | struct tty_struct *tty; | ||
1835 | 1806 | ||
1836 | for (j = 0; j < STL_MAXPANELS; j++) { | 1807 | for (j = 0; j < STL_MAXPANELS; j++) { |
1837 | panelp = brdp->panels[j]; | 1808 | panelp = brdp->panels[j]; |
@@ -1841,8 +1812,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp) | |||
1841 | portp = panelp->ports[k]; | 1812 | portp = panelp->ports[k]; |
1842 | if (portp == NULL) | 1813 | if (portp == NULL) |
1843 | continue; | 1814 | continue; |
1844 | if (portp->port.tty != NULL) | 1815 | tty = tty_port_tty_get(&portp->port); |
1845 | stl_hangup(portp->port.tty); | 1816 | if (tty != NULL) { |
1817 | stl_hangup(tty); | ||
1818 | tty_kref_put(tty); | ||
1819 | } | ||
1846 | kfree(portp->tx.buf); | 1820 | kfree(portp->tx.buf); |
1847 | kfree(portp); | 1821 | kfree(portp); |
1848 | } | 1822 | } |
@@ -2498,7 +2472,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) | |||
2498 | * what port to get stats for (used through board control device). | 2472 | * what port to get stats for (used through board control device). |
2499 | */ | 2473 | */ |
2500 | 2474 | ||
2501 | static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) | 2475 | static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp) |
2502 | { | 2476 | { |
2503 | comstats_t stl_comstats; | 2477 | comstats_t stl_comstats; |
2504 | unsigned char *head, *tail; | 2478 | unsigned char *head, *tail; |
@@ -2525,18 +2499,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) | |||
2525 | portp->stats.rxbuffered = 0; | 2499 | portp->stats.rxbuffered = 0; |
2526 | 2500 | ||
2527 | spin_lock_irqsave(&stallion_lock, flags); | 2501 | spin_lock_irqsave(&stallion_lock, flags); |
2528 | if (portp->port.tty != NULL) | 2502 | if (tty != NULL && portp->port.tty == tty) { |
2529 | if (portp->port.tty->driver_data == portp) { | 2503 | portp->stats.ttystate = tty->flags; |
2530 | portp->stats.ttystate = portp->port.tty->flags; | 2504 | /* No longer available as a statistic */ |
2531 | /* No longer available as a statistic */ | 2505 | portp->stats.rxbuffered = 1; /*tty->flip.count; */ |
2532 | portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */ | 2506 | if (tty->termios != NULL) { |
2533 | if (portp->port.tty->termios != NULL) { | 2507 | portp->stats.cflags = tty->termios->c_cflag; |
2534 | portp->stats.cflags = portp->port.tty->termios->c_cflag; | 2508 | portp->stats.iflags = tty->termios->c_iflag; |
2535 | portp->stats.iflags = portp->port.tty->termios->c_iflag; | 2509 | portp->stats.oflags = tty->termios->c_oflag; |
2536 | portp->stats.oflags = portp->port.tty->termios->c_oflag; | 2510 | portp->stats.lflags = tty->termios->c_lflag; |
2537 | portp->stats.lflags = portp->port.tty->termios->c_lflag; | ||
2538 | } | ||
2539 | } | 2511 | } |
2512 | } | ||
2540 | spin_unlock_irqrestore(&stallion_lock, flags); | 2513 | spin_unlock_irqrestore(&stallion_lock, flags); |
2541 | 2514 | ||
2542 | head = portp->tx.head; | 2515 | head = portp->tx.head; |
@@ -2640,7 +2613,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns | |||
2640 | 2613 | ||
2641 | switch (cmd) { | 2614 | switch (cmd) { |
2642 | case COM_GETPORTSTATS: | 2615 | case COM_GETPORTSTATS: |
2643 | rc = stl_getportstats(NULL, argp); | 2616 | rc = stl_getportstats(NULL, NULL, argp); |
2644 | break; | 2617 | break; |
2645 | case COM_CLRPORTSTATS: | 2618 | case COM_CLRPORTSTATS: |
2646 | rc = stl_clrportstats(NULL, argp); | 2619 | rc = stl_clrportstats(NULL, argp); |
@@ -3243,7 +3216,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) | |||
3243 | 3216 | ||
3244 | if (portp == NULL) | 3217 | if (portp == NULL) |
3245 | return; | 3218 | return; |
3246 | tty = portp->port.tty; | 3219 | tty = tty_port_tty_get(&portp->port); |
3247 | if (tty == NULL) | 3220 | if (tty == NULL) |
3248 | return; | 3221 | return; |
3249 | 3222 | ||
@@ -3288,6 +3261,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) | |||
3288 | 3261 | ||
3289 | BRDDISABLE(portp->brdnr); | 3262 | BRDDISABLE(portp->brdnr); |
3290 | spin_unlock_irqrestore(&brd_lock, flags); | 3263 | spin_unlock_irqrestore(&brd_lock, flags); |
3264 | tty_kref_put(tty); | ||
3291 | } | 3265 | } |
3292 | 3266 | ||
3293 | /*****************************************************************************/ | 3267 | /*****************************************************************************/ |
@@ -3305,7 +3279,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) | |||
3305 | 3279 | ||
3306 | if (portp == NULL) | 3280 | if (portp == NULL) |
3307 | return; | 3281 | return; |
3308 | tty = portp->port.tty; | 3282 | tty = tty_port_tty_get(&portp->port); |
3309 | if (tty == NULL) | 3283 | if (tty == NULL) |
3310 | return; | 3284 | return; |
3311 | 3285 | ||
@@ -3325,6 +3299,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) | |||
3325 | } | 3299 | } |
3326 | BRDDISABLE(portp->brdnr); | 3300 | BRDDISABLE(portp->brdnr); |
3327 | spin_unlock_irqrestore(&brd_lock, flags); | 3301 | spin_unlock_irqrestore(&brd_lock, flags); |
3302 | tty_kref_put(tty); | ||
3328 | } | 3303 | } |
3329 | 3304 | ||
3330 | /*****************************************************************************/ | 3305 | /*****************************************************************************/ |
@@ -3478,6 +3453,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) | |||
3478 | int len, stlen; | 3453 | int len, stlen; |
3479 | char *head, *tail; | 3454 | char *head, *tail; |
3480 | unsigned char ioack, srer; | 3455 | unsigned char ioack, srer; |
3456 | struct tty_struct *tty; | ||
3481 | 3457 | ||
3482 | pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); | 3458 | pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); |
3483 | 3459 | ||
@@ -3504,8 +3480,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) | |||
3504 | if ((len == 0) || ((len < STL_TXBUFLOW) && | 3480 | if ((len == 0) || ((len < STL_TXBUFLOW) && |
3505 | (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { | 3481 | (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { |
3506 | set_bit(ASYI_TXLOW, &portp->istate); | 3482 | set_bit(ASYI_TXLOW, &portp->istate); |
3507 | if (portp->port.tty) | 3483 | tty = tty_port_tty_get(&portp->port); |
3508 | tty_wakeup(portp->port.tty); | 3484 | if (tty) { |
3485 | tty_wakeup(tty); | ||
3486 | tty_kref_put(tty); | ||
3487 | } | ||
3509 | } | 3488 | } |
3510 | 3489 | ||
3511 | if (len == 0) { | 3490 | if (len == 0) { |
@@ -3569,7 +3548,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) | |||
3569 | return; | 3548 | return; |
3570 | } | 3549 | } |
3571 | portp = panelp->ports[(ioack >> 3)]; | 3550 | portp = panelp->ports[(ioack >> 3)]; |
3572 | tty = portp->port.tty; | 3551 | tty = tty_port_tty_get(&portp->port); |
3573 | 3552 | ||
3574 | if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { | 3553 | if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { |
3575 | outb((RDCR + portp->uartaddr), ioaddr); | 3554 | outb((RDCR + portp->uartaddr), ioaddr); |
@@ -3633,10 +3612,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) | |||
3633 | } | 3612 | } |
3634 | } else { | 3613 | } else { |
3635 | printk("STALLION: bad RX interrupt ack value=%x\n", ioack); | 3614 | printk("STALLION: bad RX interrupt ack value=%x\n", ioack); |
3615 | tty_kref_put(tty); | ||
3636 | return; | 3616 | return; |
3637 | } | 3617 | } |
3638 | 3618 | ||
3639 | stl_rxalldone: | 3619 | stl_rxalldone: |
3620 | tty_kref_put(tty); | ||
3640 | outb((EOSRR + portp->uartaddr), ioaddr); | 3621 | outb((EOSRR + portp->uartaddr), ioaddr); |
3641 | outb(0, (ioaddr + EREG_DATA)); | 3622 | outb(0, (ioaddr + EREG_DATA)); |
3642 | } | 3623 | } |
@@ -4175,7 +4156,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) | |||
4175 | 4156 | ||
4176 | if (portp == NULL) | 4157 | if (portp == NULL) |
4177 | return; | 4158 | return; |
4178 | tty = portp->port.tty; | 4159 | tty = tty_port_tty_get(&portp->port); |
4179 | if (tty == NULL) | 4160 | if (tty == NULL) |
4180 | return; | 4161 | return; |
4181 | 4162 | ||
@@ -4226,6 +4207,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) | |||
4226 | 4207 | ||
4227 | BRDDISABLE(portp->brdnr); | 4208 | BRDDISABLE(portp->brdnr); |
4228 | spin_unlock_irqrestore(&brd_lock, flags); | 4209 | spin_unlock_irqrestore(&brd_lock, flags); |
4210 | tty_kref_put(tty); | ||
4229 | } | 4211 | } |
4230 | 4212 | ||
4231 | /*****************************************************************************/ | 4213 | /*****************************************************************************/ |
@@ -4244,7 +4226,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) | |||
4244 | 4226 | ||
4245 | if (portp == NULL) | 4227 | if (portp == NULL) |
4246 | return; | 4228 | return; |
4247 | tty = portp->port.tty; | 4229 | tty = tty_port_tty_get(&portp->port); |
4248 | if (tty == NULL) | 4230 | if (tty == NULL) |
4249 | return; | 4231 | return; |
4250 | 4232 | ||
@@ -4269,6 +4251,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) | |||
4269 | } | 4251 | } |
4270 | BRDDISABLE(portp->brdnr); | 4252 | BRDDISABLE(portp->brdnr); |
4271 | spin_unlock_irqrestore(&brd_lock, flags); | 4253 | spin_unlock_irqrestore(&brd_lock, flags); |
4254 | tty_kref_put(tty); | ||
4272 | } | 4255 | } |
4273 | 4256 | ||
4274 | /*****************************************************************************/ | 4257 | /*****************************************************************************/ |
@@ -4408,6 +4391,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase) | |||
4408 | 4391 | ||
4409 | static void stl_sc26198txisr(struct stlport *portp) | 4392 | static void stl_sc26198txisr(struct stlport *portp) |
4410 | { | 4393 | { |
4394 | struct tty_struct *tty; | ||
4411 | unsigned int ioaddr; | 4395 | unsigned int ioaddr; |
4412 | unsigned char mr0; | 4396 | unsigned char mr0; |
4413 | int len, stlen; | 4397 | int len, stlen; |
@@ -4422,8 +4406,11 @@ static void stl_sc26198txisr(struct stlport *portp) | |||
4422 | if ((len == 0) || ((len < STL_TXBUFLOW) && | 4406 | if ((len == 0) || ((len < STL_TXBUFLOW) && |
4423 | (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { | 4407 | (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { |
4424 | set_bit(ASYI_TXLOW, &portp->istate); | 4408 | set_bit(ASYI_TXLOW, &portp->istate); |
4425 | if (portp->port.tty) | 4409 | tty = tty_port_tty_get(&portp->port); |
4426 | tty_wakeup(portp->port.tty); | 4410 | if (tty) { |
4411 | tty_wakeup(tty); | ||
4412 | tty_kref_put(tty); | ||
4413 | } | ||
4427 | } | 4414 | } |
4428 | 4415 | ||
4429 | if (len == 0) { | 4416 | if (len == 0) { |
@@ -4476,7 +4463,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) | |||
4476 | 4463 | ||
4477 | pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); | 4464 | pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); |
4478 | 4465 | ||
4479 | tty = portp->port.tty; | 4466 | tty = tty_port_tty_get(&portp->port); |
4480 | ioaddr = portp->ioaddr; | 4467 | ioaddr = portp->ioaddr; |
4481 | outb(GIBCR, (ioaddr + XP_ADDR)); | 4468 | outb(GIBCR, (ioaddr + XP_ADDR)); |
4482 | len = inb(ioaddr + XP_DATA) + 1; | 4469 | len = inb(ioaddr + XP_DATA) + 1; |
@@ -4515,6 +4502,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) | |||
4515 | stl_sc26198txunflow(portp, tty); | 4502 | stl_sc26198txunflow(portp, tty); |
4516 | } | 4503 | } |
4517 | } | 4504 | } |
4505 | tty_kref_put(tty); | ||
4518 | } | 4506 | } |
4519 | 4507 | ||
4520 | /*****************************************************************************/ | 4508 | /*****************************************************************************/ |
@@ -4528,7 +4516,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char | |||
4528 | struct tty_struct *tty; | 4516 | struct tty_struct *tty; |
4529 | unsigned int ioaddr; | 4517 | unsigned int ioaddr; |
4530 | 4518 | ||
4531 | tty = portp->port.tty; | 4519 | tty = tty_port_tty_get(&portp->port); |
4532 | ioaddr = portp->ioaddr; | 4520 | ioaddr = portp->ioaddr; |
4533 | 4521 | ||
4534 | if (status & SR_RXPARITY) | 4522 | if (status & SR_RXPARITY) |
@@ -4566,6 +4554,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char | |||
4566 | if (status == 0) | 4554 | if (status == 0) |
4567 | portp->stats.rxtotal++; | 4555 | portp->stats.rxtotal++; |
4568 | } | 4556 | } |
4557 | tty_kref_put(tty); | ||
4569 | } | 4558 | } |
4570 | 4559 | ||
4571 | /*****************************************************************************/ | 4560 | /*****************************************************************************/ |
diff --git a/drivers/char/sx.c b/drivers/char/sx.c index c385206f9db5..5b8d7a1aa3e6 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c | |||
@@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board, | |||
2504 | del_timer(&board->timer); | 2504 | del_timer(&board->timer); |
2505 | if (pdev) { | 2505 | if (pdev) { |
2506 | #ifdef CONFIG_PCI | 2506 | #ifdef CONFIG_PCI |
2507 | pci_iounmap(pdev, board->base); | 2507 | pci_iounmap(pdev, board->base2); |
2508 | pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2); | 2508 | pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2); |
2509 | #endif | 2509 | #endif |
2510 | } else { | 2510 | } else { |
@@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev, | |||
2703 | 2703 | ||
2704 | return 0; | 2704 | return 0; |
2705 | err_unmap: | 2705 | err_unmap: |
2706 | pci_iounmap(pdev, board->base); | 2706 | pci_iounmap(pdev, board->base2); |
2707 | err_reg: | 2707 | err_reg: |
2708 | pci_release_region(pdev, reg); | 2708 | pci_release_region(pdev, reg); |
2709 | err_flag: | 2709 | err_flag: |
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ae766d868454..1fee7034a386 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -954,72 +954,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel); | |||
954 | 954 | ||
955 | /* | 955 | /* |
956 | * Device file system interface to the TPM | 956 | * Device file system interface to the TPM |
957 | * | ||
958 | * It's assured that the chip will be opened just once, | ||
959 | * by the check of is_open variable, which is protected | ||
960 | * by driver_lock. | ||
957 | */ | 961 | */ |
958 | int tpm_open(struct inode *inode, struct file *file) | 962 | int tpm_open(struct inode *inode, struct file *file) |
959 | { | 963 | { |
960 | int rc = 0, minor = iminor(inode); | 964 | int minor = iminor(inode); |
961 | struct tpm_chip *chip = NULL, *pos; | 965 | struct tpm_chip *chip = NULL, *pos; |
962 | 966 | ||
963 | lock_kernel(); | 967 | rcu_read_lock(); |
964 | spin_lock(&driver_lock); | 968 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { |
965 | |||
966 | list_for_each_entry(pos, &tpm_chip_list, list) { | ||
967 | if (pos->vendor.miscdev.minor == minor) { | 969 | if (pos->vendor.miscdev.minor == minor) { |
968 | chip = pos; | 970 | chip = pos; |
971 | get_device(chip->dev); | ||
969 | break; | 972 | break; |
970 | } | 973 | } |
971 | } | 974 | } |
975 | rcu_read_unlock(); | ||
972 | 976 | ||
973 | if (chip == NULL) { | 977 | if (!chip) |
974 | rc = -ENODEV; | 978 | return -ENODEV; |
975 | goto err_out; | ||
976 | } | ||
977 | 979 | ||
978 | if (chip->num_opens) { | 980 | if (test_and_set_bit(0, &chip->is_open)) { |
979 | dev_dbg(chip->dev, "Another process owns this TPM\n"); | 981 | dev_dbg(chip->dev, "Another process owns this TPM\n"); |
980 | rc = -EBUSY; | 982 | put_device(chip->dev); |
981 | goto err_out; | 983 | return -EBUSY; |
982 | } | 984 | } |
983 | 985 | ||
984 | chip->num_opens++; | ||
985 | get_device(chip->dev); | ||
986 | |||
987 | spin_unlock(&driver_lock); | ||
988 | |||
989 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); | 986 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); |
990 | if (chip->data_buffer == NULL) { | 987 | if (chip->data_buffer == NULL) { |
991 | chip->num_opens--; | 988 | clear_bit(0, &chip->is_open); |
992 | put_device(chip->dev); | 989 | put_device(chip->dev); |
993 | unlock_kernel(); | ||
994 | return -ENOMEM; | 990 | return -ENOMEM; |
995 | } | 991 | } |
996 | 992 | ||
997 | atomic_set(&chip->data_pending, 0); | 993 | atomic_set(&chip->data_pending, 0); |
998 | 994 | ||
999 | file->private_data = chip; | 995 | file->private_data = chip; |
1000 | unlock_kernel(); | ||
1001 | return 0; | 996 | return 0; |
1002 | |||
1003 | err_out: | ||
1004 | spin_unlock(&driver_lock); | ||
1005 | unlock_kernel(); | ||
1006 | return rc; | ||
1007 | } | 997 | } |
1008 | EXPORT_SYMBOL_GPL(tpm_open); | 998 | EXPORT_SYMBOL_GPL(tpm_open); |
1009 | 999 | ||
1000 | /* | ||
1001 | * Called on file close | ||
1002 | */ | ||
1010 | int tpm_release(struct inode *inode, struct file *file) | 1003 | int tpm_release(struct inode *inode, struct file *file) |
1011 | { | 1004 | { |
1012 | struct tpm_chip *chip = file->private_data; | 1005 | struct tpm_chip *chip = file->private_data; |
1013 | 1006 | ||
1007 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
1014 | flush_scheduled_work(); | 1008 | flush_scheduled_work(); |
1015 | spin_lock(&driver_lock); | ||
1016 | file->private_data = NULL; | 1009 | file->private_data = NULL; |
1017 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
1018 | atomic_set(&chip->data_pending, 0); | 1010 | atomic_set(&chip->data_pending, 0); |
1019 | chip->num_opens--; | ||
1020 | put_device(chip->dev); | ||
1021 | kfree(chip->data_buffer); | 1011 | kfree(chip->data_buffer); |
1022 | spin_unlock(&driver_lock); | 1012 | clear_bit(0, &chip->is_open); |
1013 | put_device(chip->dev); | ||
1023 | return 0; | 1014 | return 0; |
1024 | } | 1015 | } |
1025 | EXPORT_SYMBOL_GPL(tpm_release); | 1016 | EXPORT_SYMBOL_GPL(tpm_release); |
@@ -1093,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev) | |||
1093 | } | 1084 | } |
1094 | 1085 | ||
1095 | spin_lock(&driver_lock); | 1086 | spin_lock(&driver_lock); |
1096 | 1087 | list_del_rcu(&chip->list); | |
1097 | list_del(&chip->list); | ||
1098 | |||
1099 | spin_unlock(&driver_lock); | 1088 | spin_unlock(&driver_lock); |
1089 | synchronize_rcu(); | ||
1100 | 1090 | ||
1101 | misc_deregister(&chip->vendor.miscdev); | 1091 | misc_deregister(&chip->vendor.miscdev); |
1102 | |||
1103 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 1092 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
1104 | tpm_bios_log_teardown(chip->bios_dir); | 1093 | tpm_bios_log_teardown(chip->bios_dir); |
1105 | 1094 | ||
@@ -1144,25 +1133,33 @@ int tpm_pm_resume(struct device *dev) | |||
1144 | } | 1133 | } |
1145 | EXPORT_SYMBOL_GPL(tpm_pm_resume); | 1134 | EXPORT_SYMBOL_GPL(tpm_pm_resume); |
1146 | 1135 | ||
1136 | /* In case vendor provided release function, call it too.*/ | ||
1137 | |||
1138 | void tpm_dev_vendor_release(struct tpm_chip *chip) | ||
1139 | { | ||
1140 | if (chip->vendor.release) | ||
1141 | chip->vendor.release(chip->dev); | ||
1142 | |||
1143 | clear_bit(chip->dev_num, dev_mask); | ||
1144 | kfree(chip->vendor.miscdev.name); | ||
1145 | } | ||
1146 | EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | ||
1147 | |||
1148 | |||
1147 | /* | 1149 | /* |
1148 | * Once all references to platform device are down to 0, | 1150 | * Once all references to platform device are down to 0, |
1149 | * release all allocated structures. | 1151 | * release all allocated structures. |
1150 | * In case vendor provided release function, | ||
1151 | * call it too. | ||
1152 | */ | 1152 | */ |
1153 | static void tpm_dev_release(struct device *dev) | 1153 | static void tpm_dev_release(struct device *dev) |
1154 | { | 1154 | { |
1155 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1155 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1156 | 1156 | ||
1157 | if (chip->vendor.release) | 1157 | tpm_dev_vendor_release(chip); |
1158 | chip->vendor.release(dev); | ||
1159 | 1158 | ||
1160 | chip->release(dev); | 1159 | chip->release(dev); |
1161 | |||
1162 | clear_bit(chip->dev_num, dev_mask); | ||
1163 | kfree(chip->vendor.miscdev.name); | ||
1164 | kfree(chip); | 1160 | kfree(chip); |
1165 | } | 1161 | } |
1162 | EXPORT_SYMBOL_GPL(tpm_dev_release); | ||
1166 | 1163 | ||
1167 | /* | 1164 | /* |
1168 | * Called from tpm_<specific>.c probe function only for devices | 1165 | * Called from tpm_<specific>.c probe function only for devices |
@@ -1171,8 +1168,8 @@ static void tpm_dev_release(struct device *dev) | |||
1171 | * upon errant exit from this function specific probe function should call | 1168 | * upon errant exit from this function specific probe function should call |
1172 | * pci_disable_device | 1169 | * pci_disable_device |
1173 | */ | 1170 | */ |
1174 | struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific | 1171 | struct tpm_chip *tpm_register_hardware(struct device *dev, |
1175 | *entry) | 1172 | const struct tpm_vendor_specific *entry) |
1176 | { | 1173 | { |
1177 | #define DEVNAME_SIZE 7 | 1174 | #define DEVNAME_SIZE 7 |
1178 | 1175 | ||
@@ -1231,21 +1228,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend | |||
1231 | return NULL; | 1228 | return NULL; |
1232 | } | 1229 | } |
1233 | 1230 | ||
1234 | spin_lock(&driver_lock); | ||
1235 | |||
1236 | list_add(&chip->list, &tpm_chip_list); | ||
1237 | |||
1238 | spin_unlock(&driver_lock); | ||
1239 | |||
1240 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1231 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { |
1241 | list_del(&chip->list); | ||
1242 | misc_deregister(&chip->vendor.miscdev); | 1232 | misc_deregister(&chip->vendor.miscdev); |
1243 | put_device(chip->dev); | 1233 | put_device(chip->dev); |
1234 | |||
1244 | return NULL; | 1235 | return NULL; |
1245 | } | 1236 | } |
1246 | 1237 | ||
1247 | chip->bios_dir = tpm_bios_log_setup(devname); | 1238 | chip->bios_dir = tpm_bios_log_setup(devname); |
1248 | 1239 | ||
1240 | /* Make chip available */ | ||
1241 | spin_lock(&driver_lock); | ||
1242 | list_add_rcu(&chip->list, &tpm_chip_list); | ||
1243 | spin_unlock(&driver_lock); | ||
1244 | |||
1249 | return chip; | 1245 | return chip; |
1250 | } | 1246 | } |
1251 | EXPORT_SYMBOL_GPL(tpm_register_hardware); | 1247 | EXPORT_SYMBOL_GPL(tpm_register_hardware); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e885148b4cfb..8e30df4a4388 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -90,7 +90,7 @@ struct tpm_chip { | |||
90 | struct device *dev; /* Device stuff */ | 90 | struct device *dev; /* Device stuff */ |
91 | 91 | ||
92 | int dev_num; /* /dev/tpm# */ | 92 | int dev_num; /* /dev/tpm# */ |
93 | int num_opens; /* only one allowed */ | 93 | unsigned long is_open; /* only one allowed */ |
94 | int time_expired; | 94 | int time_expired; |
95 | 95 | ||
96 | /* Data passed to and from the tpm via the read/write calls */ | 96 | /* Data passed to and from the tpm via the read/write calls */ |
@@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *, | |||
132 | const struct tpm_vendor_specific *); | 132 | const struct tpm_vendor_specific *); |
133 | extern int tpm_open(struct inode *, struct file *); | 133 | extern int tpm_open(struct inode *, struct file *); |
134 | extern int tpm_release(struct inode *, struct file *); | 134 | extern int tpm_release(struct inode *, struct file *); |
135 | extern void tpm_dev_vendor_release(struct tpm_chip *); | ||
135 | extern ssize_t tpm_write(struct file *, const char __user *, size_t, | 136 | extern ssize_t tpm_write(struct file *, const char __user *, size_t, |
136 | loff_t *); | 137 | loff_t *); |
137 | extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); | 138 | extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ed1879c0dd8d..717af7ad1bdf 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { | |||
630 | {"", 0} /* Terminator */ | 630 | {"", 0} /* Terminator */ |
631 | }; | 631 | }; |
632 | 632 | ||
633 | static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) | ||
634 | { | ||
635 | struct tpm_chip *chip = pnp_get_drvdata(dev); | ||
636 | |||
637 | tpm_dev_vendor_release(chip); | ||
638 | |||
639 | kfree(chip); | ||
640 | } | ||
641 | |||
642 | |||
633 | static struct pnp_driver tis_pnp_driver = { | 643 | static struct pnp_driver tis_pnp_driver = { |
634 | .name = "tpm_tis", | 644 | .name = "tpm_tis", |
635 | .id_table = tpm_pnp_tbl, | 645 | .id_table = tpm_pnp_tbl, |
636 | .probe = tpm_tis_pnp_init, | 646 | .probe = tpm_tis_pnp_init, |
637 | .suspend = tpm_tis_pnp_suspend, | 647 | .suspend = tpm_tis_pnp_suspend, |
638 | .resume = tpm_tis_pnp_resume, | 648 | .resume = tpm_tis_pnp_resume, |
649 | .remove = tpm_tis_pnp_remove, | ||
639 | }; | 650 | }; |
640 | 651 | ||
641 | #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 | 652 | #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 |
@@ -683,6 +694,7 @@ static void __exit cleanup_tis(void) | |||
683 | spin_lock(&tis_lock); | 694 | spin_lock(&tis_lock); |
684 | list_for_each_entry_safe(i, j, &tis_chips, list) { | 695 | list_for_each_entry_safe(i, j, &tis_chips, list) { |
685 | chip = to_tpm_chip(i); | 696 | chip = to_tpm_chip(i); |
697 | tpm_remove_hardware(chip->dev); | ||
686 | iowrite32(~TPM_GLOBAL_INT_ENABLE & | 698 | iowrite32(~TPM_GLOBAL_INT_ENABLE & |
687 | ioread32(chip->vendor.iobase + | 699 | ioread32(chip->vendor.iobase + |
688 | TPM_INT_ENABLE(chip->vendor. | 700 | TPM_INT_ENABLE(chip->vendor. |
@@ -694,9 +706,9 @@ static void __exit cleanup_tis(void) | |||
694 | free_irq(chip->vendor.irq, chip); | 706 | free_irq(chip->vendor.irq, chip); |
695 | iounmap(i->iobase); | 707 | iounmap(i->iobase); |
696 | list_del(&i->list); | 708 | list_del(&i->list); |
697 | tpm_remove_hardware(chip->dev); | ||
698 | } | 709 | } |
699 | spin_unlock(&tis_lock); | 710 | spin_unlock(&tis_lock); |
711 | |||
700 | if (force) { | 712 | if (force) { |
701 | platform_device_unregister(pdev); | 713 | platform_device_unregister(pdev); |
702 | driver_unregister(&tis_drv); | 714 | driver_unregister(&tis_drv); |
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 3582f43345a8..5787249934c8 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c | |||
@@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, | |||
93 | get_task_comm(name, tsk); | 93 | get_task_comm(name, tsk); |
94 | audit_log_untrustedstring(ab, name); | 94 | audit_log_untrustedstring(ab, name); |
95 | audit_log_format(ab, " data="); | 95 | audit_log_format(ab, " data="); |
96 | audit_log_n_untrustedstring(ab, buf->data, buf->valid); | 96 | audit_log_n_hex(ab, buf->data, buf->valid); |
97 | audit_log_end(ab); | 97 | audit_log_end(ab); |
98 | } | 98 | } |
99 | buf->valid = 0; | 99 | buf->valid = 0; |
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c new file mode 100644 index 000000000000..810ee25d66a4 --- /dev/null +++ b/drivers/char/tty_buffer.c | |||
@@ -0,0 +1,511 @@ | |||
1 | /* | ||
2 | * Tty buffer allocation management | ||
3 | */ | ||
4 | |||
5 | #include <linux/types.h> | ||
6 | #include <linux/errno.h> | ||
7 | #include <linux/tty.h> | ||
8 | #include <linux/tty_driver.h> | ||
9 | #include <linux/tty_flip.h> | ||
10 | #include <linux/timer.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/wait.h> | ||
16 | #include <linux/bitops.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/module.h> | ||
19 | |||
20 | /** | ||
21 | * tty_buffer_free_all - free buffers used by a tty | ||
22 | * @tty: tty to free from | ||
23 | * | ||
24 | * Remove all the buffers pending on a tty whether queued with data | ||
25 | * or in the free ring. Must be called when the tty is no longer in use | ||
26 | * | ||
27 | * Locking: none | ||
28 | */ | ||
29 | |||
30 | void tty_buffer_free_all(struct tty_struct *tty) | ||
31 | { | ||
32 | struct tty_buffer *thead; | ||
33 | while ((thead = tty->buf.head) != NULL) { | ||
34 | tty->buf.head = thead->next; | ||
35 | kfree(thead); | ||
36 | } | ||
37 | while ((thead = tty->buf.free) != NULL) { | ||
38 | tty->buf.free = thead->next; | ||
39 | kfree(thead); | ||
40 | } | ||
41 | tty->buf.tail = NULL; | ||
42 | tty->buf.memory_used = 0; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * tty_buffer_alloc - allocate a tty buffer | ||
47 | * @tty: tty device | ||
48 | * @size: desired size (characters) | ||
49 | * | ||
50 | * Allocate a new tty buffer to hold the desired number of characters. | ||
51 | * Return NULL if out of memory or the allocation would exceed the | ||
52 | * per device queue | ||
53 | * | ||
54 | * Locking: Caller must hold tty->buf.lock | ||
55 | */ | ||
56 | |||
57 | static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) | ||
58 | { | ||
59 | struct tty_buffer *p; | ||
60 | |||
61 | if (tty->buf.memory_used + size > 65536) | ||
62 | return NULL; | ||
63 | p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); | ||
64 | if (p == NULL) | ||
65 | return NULL; | ||
66 | p->used = 0; | ||
67 | p->size = size; | ||
68 | p->next = NULL; | ||
69 | p->commit = 0; | ||
70 | p->read = 0; | ||
71 | p->char_buf_ptr = (char *)(p->data); | ||
72 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; | ||
73 | tty->buf.memory_used += size; | ||
74 | return p; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * tty_buffer_free - free a tty buffer | ||
79 | * @tty: tty owning the buffer | ||
80 | * @b: the buffer to free | ||
81 | * | ||
82 | * Free a tty buffer, or add it to the free list according to our | ||
83 | * internal strategy | ||
84 | * | ||
85 | * Locking: Caller must hold tty->buf.lock | ||
86 | */ | ||
87 | |||
88 | static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) | ||
89 | { | ||
90 | /* Dumb strategy for now - should keep some stats */ | ||
91 | tty->buf.memory_used -= b->size; | ||
92 | WARN_ON(tty->buf.memory_used < 0); | ||
93 | |||
94 | if (b->size >= 512) | ||
95 | kfree(b); | ||
96 | else { | ||
97 | b->next = tty->buf.free; | ||
98 | tty->buf.free = b; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * __tty_buffer_flush - flush full tty buffers | ||
104 | * @tty: tty to flush | ||
105 | * | ||
106 | * flush all the buffers containing receive data. Caller must | ||
107 | * hold the buffer lock and must have ensured no parallel flush to | ||
108 | * ldisc is running. | ||
109 | * | ||
110 | * Locking: Caller must hold tty->buf.lock | ||
111 | */ | ||
112 | |||
113 | static void __tty_buffer_flush(struct tty_struct *tty) | ||
114 | { | ||
115 | struct tty_buffer *thead; | ||
116 | |||
117 | while ((thead = tty->buf.head) != NULL) { | ||
118 | tty->buf.head = thead->next; | ||
119 | tty_buffer_free(tty, thead); | ||
120 | } | ||
121 | tty->buf.tail = NULL; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * tty_buffer_flush - flush full tty buffers | ||
126 | * @tty: tty to flush | ||
127 | * | ||
128 | * flush all the buffers containing receive data. If the buffer is | ||
129 | * being processed by flush_to_ldisc then we defer the processing | ||
130 | * to that function | ||
131 | * | ||
132 | * Locking: none | ||
133 | */ | ||
134 | |||
135 | void tty_buffer_flush(struct tty_struct *tty) | ||
136 | { | ||
137 | unsigned long flags; | ||
138 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
139 | |||
140 | /* If the data is being pushed to the tty layer then we can't | ||
141 | process it here. Instead set a flag and the flush_to_ldisc | ||
142 | path will process the flush request before it exits */ | ||
143 | if (test_bit(TTY_FLUSHING, &tty->flags)) { | ||
144 | set_bit(TTY_FLUSHPENDING, &tty->flags); | ||
145 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
146 | wait_event(tty->read_wait, | ||
147 | test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); | ||
148 | return; | ||
149 | } else | ||
150 | __tty_buffer_flush(tty); | ||
151 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * tty_buffer_find - find a free tty buffer | ||
156 | * @tty: tty owning the buffer | ||
157 | * @size: characters wanted | ||
158 | * | ||
159 | * Locate an existing suitable tty buffer or if we are lacking one then | ||
160 | * allocate a new one. We round our buffers off in 256 character chunks | ||
161 | * to get better allocation behaviour. | ||
162 | * | ||
163 | * Locking: Caller must hold tty->buf.lock | ||
164 | */ | ||
165 | |||
166 | static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | ||
167 | { | ||
168 | struct tty_buffer **tbh = &tty->buf.free; | ||
169 | while ((*tbh) != NULL) { | ||
170 | struct tty_buffer *t = *tbh; | ||
171 | if (t->size >= size) { | ||
172 | *tbh = t->next; | ||
173 | t->next = NULL; | ||
174 | t->used = 0; | ||
175 | t->commit = 0; | ||
176 | t->read = 0; | ||
177 | tty->buf.memory_used += t->size; | ||
178 | return t; | ||
179 | } | ||
180 | tbh = &((*tbh)->next); | ||
181 | } | ||
182 | /* Round the buffer size out */ | ||
183 | size = (size + 0xFF) & ~0xFF; | ||
184 | return tty_buffer_alloc(tty, size); | ||
185 | /* Should possibly check if this fails for the largest buffer we | ||
186 | have queued and recycle that ? */ | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * tty_buffer_request_room - grow tty buffer if needed | ||
191 | * @tty: tty structure | ||
192 | * @size: size desired | ||
193 | * | ||
194 | * Make at least size bytes of linear space available for the tty | ||
195 | * buffer. If we fail return the size we managed to find. | ||
196 | * | ||
197 | * Locking: Takes tty->buf.lock | ||
198 | */ | ||
199 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | ||
200 | { | ||
201 | struct tty_buffer *b, *n; | ||
202 | int left; | ||
203 | unsigned long flags; | ||
204 | |||
205 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
206 | |||
207 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | ||
208 | remove this conditional if its worth it. This would be invisible | ||
209 | to the callers */ | ||
210 | if ((b = tty->buf.tail) != NULL) | ||
211 | left = b->size - b->used; | ||
212 | else | ||
213 | left = 0; | ||
214 | |||
215 | if (left < size) { | ||
216 | /* This is the slow path - looking for new buffers to use */ | ||
217 | if ((n = tty_buffer_find(tty, size)) != NULL) { | ||
218 | if (b != NULL) { | ||
219 | b->next = n; | ||
220 | b->commit = b->used; | ||
221 | } else | ||
222 | tty->buf.head = n; | ||
223 | tty->buf.tail = n; | ||
224 | } else | ||
225 | size = left; | ||
226 | } | ||
227 | |||
228 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
229 | return size; | ||
230 | } | ||
231 | EXPORT_SYMBOL_GPL(tty_buffer_request_room); | ||
232 | |||
233 | /** | ||
234 | * tty_insert_flip_string - Add characters to the tty buffer | ||
235 | * @tty: tty structure | ||
236 | * @chars: characters | ||
237 | * @size: size | ||
238 | * | ||
239 | * Queue a series of bytes to the tty buffering. All the characters | ||
240 | * passed are marked as without error. Returns the number added. | ||
241 | * | ||
242 | * Locking: Called functions may take tty->buf.lock | ||
243 | */ | ||
244 | |||
245 | int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, | ||
246 | size_t size) | ||
247 | { | ||
248 | int copied = 0; | ||
249 | do { | ||
250 | int space = tty_buffer_request_room(tty, size - copied); | ||
251 | struct tty_buffer *tb = tty->buf.tail; | ||
252 | /* If there is no space then tb may be NULL */ | ||
253 | if (unlikely(space == 0)) | ||
254 | break; | ||
255 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | ||
256 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | ||
257 | tb->used += space; | ||
258 | copied += space; | ||
259 | chars += space; | ||
260 | /* There is a small chance that we need to split the data over | ||
261 | several buffers. If this is the case we must loop */ | ||
262 | } while (unlikely(size > copied)); | ||
263 | return copied; | ||
264 | } | ||
265 | EXPORT_SYMBOL(tty_insert_flip_string); | ||
266 | |||
267 | /** | ||
268 | * tty_insert_flip_string_flags - Add characters to the tty buffer | ||
269 | * @tty: tty structure | ||
270 | * @chars: characters | ||
271 | * @flags: flag bytes | ||
272 | * @size: size | ||
273 | * | ||
274 | * Queue a series of bytes to the tty buffering. For each character | ||
275 | * the flags array indicates the status of the character. Returns the | ||
276 | * number added. | ||
277 | * | ||
278 | * Locking: Called functions may take tty->buf.lock | ||
279 | */ | ||
280 | |||
281 | int tty_insert_flip_string_flags(struct tty_struct *tty, | ||
282 | const unsigned char *chars, const char *flags, size_t size) | ||
283 | { | ||
284 | int copied = 0; | ||
285 | do { | ||
286 | int space = tty_buffer_request_room(tty, size - copied); | ||
287 | struct tty_buffer *tb = tty->buf.tail; | ||
288 | /* If there is no space then tb may be NULL */ | ||
289 | if (unlikely(space == 0)) | ||
290 | break; | ||
291 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | ||
292 | memcpy(tb->flag_buf_ptr + tb->used, flags, space); | ||
293 | tb->used += space; | ||
294 | copied += space; | ||
295 | chars += space; | ||
296 | flags += space; | ||
297 | /* There is a small chance that we need to split the data over | ||
298 | several buffers. If this is the case we must loop */ | ||
299 | } while (unlikely(size > copied)); | ||
300 | return copied; | ||
301 | } | ||
302 | EXPORT_SYMBOL(tty_insert_flip_string_flags); | ||
303 | |||
304 | /** | ||
305 | * tty_schedule_flip - push characters to ldisc | ||
306 | * @tty: tty to push from | ||
307 | * | ||
308 | * Takes any pending buffers and transfers their ownership to the | ||
309 | * ldisc side of the queue. It then schedules those characters for | ||
310 | * processing by the line discipline. | ||
311 | * | ||
312 | * Locking: Takes tty->buf.lock | ||
313 | */ | ||
314 | |||
315 | void tty_schedule_flip(struct tty_struct *tty) | ||
316 | { | ||
317 | unsigned long flags; | ||
318 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
319 | if (tty->buf.tail != NULL) | ||
320 | tty->buf.tail->commit = tty->buf.tail->used; | ||
321 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
322 | schedule_delayed_work(&tty->buf.work, 1); | ||
323 | } | ||
324 | EXPORT_SYMBOL(tty_schedule_flip); | ||
325 | |||
326 | /** | ||
327 | * tty_prepare_flip_string - make room for characters | ||
328 | * @tty: tty | ||
329 | * @chars: return pointer for character write area | ||
330 | * @size: desired size | ||
331 | * | ||
332 | * Prepare a block of space in the buffer for data. Returns the length | ||
333 | * available and buffer pointer to the space which is now allocated and | ||
334 | * accounted for as ready for normal characters. This is used for drivers | ||
335 | * that need their own block copy routines into the buffer. There is no | ||
336 | * guarantee the buffer is a DMA target! | ||
337 | * | ||
338 | * Locking: May call functions taking tty->buf.lock | ||
339 | */ | ||
340 | |||
341 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, | ||
342 | size_t size) | ||
343 | { | ||
344 | int space = tty_buffer_request_room(tty, size); | ||
345 | if (likely(space)) { | ||
346 | struct tty_buffer *tb = tty->buf.tail; | ||
347 | *chars = tb->char_buf_ptr + tb->used; | ||
348 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | ||
349 | tb->used += space; | ||
350 | } | ||
351 | return space; | ||
352 | } | ||
353 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | ||
354 | |||
355 | /** | ||
356 | * tty_prepare_flip_string_flags - make room for characters | ||
357 | * @tty: tty | ||
358 | * @chars: return pointer for character write area | ||
359 | * @flags: return pointer for status flag write area | ||
360 | * @size: desired size | ||
361 | * | ||
362 | * Prepare a block of space in the buffer for data. Returns the length | ||
363 | * available and buffer pointer to the space which is now allocated and | ||
364 | * accounted for as ready for characters. This is used for drivers | ||
365 | * that need their own block copy routines into the buffer. There is no | ||
366 | * guarantee the buffer is a DMA target! | ||
367 | * | ||
368 | * Locking: May call functions taking tty->buf.lock | ||
369 | */ | ||
370 | |||
371 | int tty_prepare_flip_string_flags(struct tty_struct *tty, | ||
372 | unsigned char **chars, char **flags, size_t size) | ||
373 | { | ||
374 | int space = tty_buffer_request_room(tty, size); | ||
375 | if (likely(space)) { | ||
376 | struct tty_buffer *tb = tty->buf.tail; | ||
377 | *chars = tb->char_buf_ptr + tb->used; | ||
378 | *flags = tb->flag_buf_ptr + tb->used; | ||
379 | tb->used += space; | ||
380 | } | ||
381 | return space; | ||
382 | } | ||
383 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); | ||
384 | |||
385 | |||
386 | |||
387 | /** | ||
388 | * flush_to_ldisc | ||
389 | * @work: tty structure passed from work queue. | ||
390 | * | ||
391 | * This routine is called out of the software interrupt to flush data | ||
392 | * from the buffer chain to the line discipline. | ||
393 | * | ||
394 | * Locking: holds tty->buf.lock to guard buffer list. Drops the lock | ||
395 | * while invoking the line discipline receive_buf method. The | ||
396 | * receive_buf method is single threaded for each tty instance. | ||
397 | */ | ||
398 | |||
399 | static void flush_to_ldisc(struct work_struct *work) | ||
400 | { | ||
401 | struct tty_struct *tty = | ||
402 | container_of(work, struct tty_struct, buf.work.work); | ||
403 | unsigned long flags; | ||
404 | struct tty_ldisc *disc; | ||
405 | struct tty_buffer *tbuf, *head; | ||
406 | char *char_buf; | ||
407 | unsigned char *flag_buf; | ||
408 | |||
409 | disc = tty_ldisc_ref(tty); | ||
410 | if (disc == NULL) /* !TTY_LDISC */ | ||
411 | return; | ||
412 | |||
413 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
414 | /* So we know a flush is running */ | ||
415 | set_bit(TTY_FLUSHING, &tty->flags); | ||
416 | head = tty->buf.head; | ||
417 | if (head != NULL) { | ||
418 | tty->buf.head = NULL; | ||
419 | for (;;) { | ||
420 | int count = head->commit - head->read; | ||
421 | if (!count) { | ||
422 | if (head->next == NULL) | ||
423 | break; | ||
424 | tbuf = head; | ||
425 | head = head->next; | ||
426 | tty_buffer_free(tty, tbuf); | ||
427 | continue; | ||
428 | } | ||
429 | /* Ldisc or user is trying to flush the buffers | ||
430 | we are feeding to the ldisc, stop feeding the | ||
431 | line discipline as we want to empty the queue */ | ||
432 | if (test_bit(TTY_FLUSHPENDING, &tty->flags)) | ||
433 | break; | ||
434 | if (!tty->receive_room) { | ||
435 | schedule_delayed_work(&tty->buf.work, 1); | ||
436 | break; | ||
437 | } | ||
438 | if (count > tty->receive_room) | ||
439 | count = tty->receive_room; | ||
440 | char_buf = head->char_buf_ptr + head->read; | ||
441 | flag_buf = head->flag_buf_ptr + head->read; | ||
442 | head->read += count; | ||
443 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
444 | disc->ops->receive_buf(tty, char_buf, | ||
445 | flag_buf, count); | ||
446 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
447 | } | ||
448 | /* Restore the queue head */ | ||
449 | tty->buf.head = head; | ||
450 | } | ||
451 | /* We may have a deferred request to flush the input buffer, | ||
452 | if so pull the chain under the lock and empty the queue */ | ||
453 | if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { | ||
454 | __tty_buffer_flush(tty); | ||
455 | clear_bit(TTY_FLUSHPENDING, &tty->flags); | ||
456 | wake_up(&tty->read_wait); | ||
457 | } | ||
458 | clear_bit(TTY_FLUSHING, &tty->flags); | ||
459 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
460 | |||
461 | tty_ldisc_deref(disc); | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * tty_flip_buffer_push - terminal | ||
466 | * @tty: tty to push | ||
467 | * | ||
468 | * Queue a push of the terminal flip buffers to the line discipline. This | ||
469 | * function must not be called from IRQ context if tty->low_latency is set. | ||
470 | * | ||
471 | * In the event of the queue being busy for flipping the work will be | ||
472 | * held off and retried later. | ||
473 | * | ||
474 | * Locking: tty buffer lock. Driver locks in low latency mode. | ||
475 | */ | ||
476 | |||
477 | void tty_flip_buffer_push(struct tty_struct *tty) | ||
478 | { | ||
479 | unsigned long flags; | ||
480 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
481 | if (tty->buf.tail != NULL) | ||
482 | tty->buf.tail->commit = tty->buf.tail->used; | ||
483 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
484 | |||
485 | if (tty->low_latency) | ||
486 | flush_to_ldisc(&tty->buf.work.work); | ||
487 | else | ||
488 | schedule_delayed_work(&tty->buf.work, 1); | ||
489 | } | ||
490 | EXPORT_SYMBOL(tty_flip_buffer_push); | ||
491 | |||
492 | /** | ||
493 | * tty_buffer_init - prepare a tty buffer structure | ||
494 | * @tty: tty to initialise | ||
495 | * | ||
496 | * Set up the initial state of the buffer management for a tty device. | ||
497 | * Must be called before the other tty buffer functions are used. | ||
498 | * | ||
499 | * Locking: none | ||
500 | */ | ||
501 | |||
502 | void tty_buffer_init(struct tty_struct *tty) | ||
503 | { | ||
504 | spin_lock_init(&tty->buf.lock); | ||
505 | tty->buf.head = NULL; | ||
506 | tty->buf.tail = NULL; | ||
507 | tty->buf.free = NULL; | ||
508 | tty->buf.memory_used = 0; | ||
509 | INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); | ||
510 | } | ||
511 | |||
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e4dce8709541..7053d6333692 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -49,7 +49,7 @@ | |||
49 | * implement CONFIG_VT and generalize console device interface. | 49 | * implement CONFIG_VT and generalize console device interface. |
50 | * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97 | 50 | * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97 |
51 | * | 51 | * |
52 | * Rewrote init_dev and release_dev to eliminate races. | 52 | * Rewrote tty_init_dev and tty_release_dev to eliminate races. |
53 | * -- Bill Hawes <whawes@star.net>, June 97 | 53 | * -- Bill Hawes <whawes@star.net>, June 97 |
54 | * | 54 | * |
55 | * Added devfs support. | 55 | * Added devfs support. |
@@ -136,13 +136,6 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ | |||
136 | DEFINE_MUTEX(tty_mutex); | 136 | DEFINE_MUTEX(tty_mutex); |
137 | EXPORT_SYMBOL(tty_mutex); | 137 | EXPORT_SYMBOL(tty_mutex); |
138 | 138 | ||
139 | #ifdef CONFIG_UNIX98_PTYS | ||
140 | extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ | ||
141 | static int ptmx_open(struct inode *, struct file *); | ||
142 | #endif | ||
143 | |||
144 | static void initialize_tty_struct(struct tty_struct *tty); | ||
145 | |||
146 | static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); | 139 | static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); |
147 | static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); | 140 | static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); |
148 | ssize_t redirected_tty_write(struct file *, const char __user *, | 141 | ssize_t redirected_tty_write(struct file *, const char __user *, |
@@ -171,13 +164,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); | |||
171 | * Locking: none | 164 | * Locking: none |
172 | */ | 165 | */ |
173 | 166 | ||
174 | static struct tty_struct *alloc_tty_struct(void) | 167 | struct tty_struct *alloc_tty_struct(void) |
175 | { | 168 | { |
176 | return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); | 169 | return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); |
177 | } | 170 | } |
178 | 171 | ||
179 | static void tty_buffer_free_all(struct tty_struct *); | ||
180 | |||
181 | /** | 172 | /** |
182 | * free_tty_struct - free a disused tty | 173 | * free_tty_struct - free a disused tty |
183 | * @tty: tty struct to free | 174 | * @tty: tty struct to free |
@@ -187,7 +178,7 @@ static void tty_buffer_free_all(struct tty_struct *); | |||
187 | * Locking: none. Must be called after tty is definitely unused | 178 | * Locking: none. Must be called after tty is definitely unused |
188 | */ | 179 | */ |
189 | 180 | ||
190 | static inline void free_tty_struct(struct tty_struct *tty) | 181 | void free_tty_struct(struct tty_struct *tty) |
191 | { | 182 | { |
192 | kfree(tty->write_buf); | 183 | kfree(tty->write_buf); |
193 | tty_buffer_free_all(tty); | 184 | tty_buffer_free_all(tty); |
@@ -263,398 +254,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) | |||
263 | return 0; | 254 | return 0; |
264 | } | 255 | } |
265 | 256 | ||
266 | /* | ||
267 | * Tty buffer allocation management | ||
268 | */ | ||
269 | |||
270 | /** | ||
271 | * tty_buffer_free_all - free buffers used by a tty | ||
272 | * @tty: tty to free from | ||
273 | * | ||
274 | * Remove all the buffers pending on a tty whether queued with data | ||
275 | * or in the free ring. Must be called when the tty is no longer in use | ||
276 | * | ||
277 | * Locking: none | ||
278 | */ | ||
279 | |||
280 | static void tty_buffer_free_all(struct tty_struct *tty) | ||
281 | { | ||
282 | struct tty_buffer *thead; | ||
283 | while ((thead = tty->buf.head) != NULL) { | ||
284 | tty->buf.head = thead->next; | ||
285 | kfree(thead); | ||
286 | } | ||
287 | while ((thead = tty->buf.free) != NULL) { | ||
288 | tty->buf.free = thead->next; | ||
289 | kfree(thead); | ||
290 | } | ||
291 | tty->buf.tail = NULL; | ||
292 | tty->buf.memory_used = 0; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * tty_buffer_init - prepare a tty buffer structure | ||
297 | * @tty: tty to initialise | ||
298 | * | ||
299 | * Set up the initial state of the buffer management for a tty device. | ||
300 | * Must be called before the other tty buffer functions are used. | ||
301 | * | ||
302 | * Locking: none | ||
303 | */ | ||
304 | |||
305 | static void tty_buffer_init(struct tty_struct *tty) | ||
306 | { | ||
307 | spin_lock_init(&tty->buf.lock); | ||
308 | tty->buf.head = NULL; | ||
309 | tty->buf.tail = NULL; | ||
310 | tty->buf.free = NULL; | ||
311 | tty->buf.memory_used = 0; | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * tty_buffer_alloc - allocate a tty buffer | ||
316 | * @tty: tty device | ||
317 | * @size: desired size (characters) | ||
318 | * | ||
319 | * Allocate a new tty buffer to hold the desired number of characters. | ||
320 | * Return NULL if out of memory or the allocation would exceed the | ||
321 | * per device queue | ||
322 | * | ||
323 | * Locking: Caller must hold tty->buf.lock | ||
324 | */ | ||
325 | |||
326 | static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) | ||
327 | { | ||
328 | struct tty_buffer *p; | ||
329 | |||
330 | if (tty->buf.memory_used + size > 65536) | ||
331 | return NULL; | ||
332 | p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); | ||
333 | if (p == NULL) | ||
334 | return NULL; | ||
335 | p->used = 0; | ||
336 | p->size = size; | ||
337 | p->next = NULL; | ||
338 | p->commit = 0; | ||
339 | p->read = 0; | ||
340 | p->char_buf_ptr = (char *)(p->data); | ||
341 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; | ||
342 | tty->buf.memory_used += size; | ||
343 | return p; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * tty_buffer_free - free a tty buffer | ||
348 | * @tty: tty owning the buffer | ||
349 | * @b: the buffer to free | ||
350 | * | ||
351 | * Free a tty buffer, or add it to the free list according to our | ||
352 | * internal strategy | ||
353 | * | ||
354 | * Locking: Caller must hold tty->buf.lock | ||
355 | */ | ||
356 | |||
357 | static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) | ||
358 | { | ||
359 | /* Dumb strategy for now - should keep some stats */ | ||
360 | tty->buf.memory_used -= b->size; | ||
361 | WARN_ON(tty->buf.memory_used < 0); | ||
362 | |||
363 | if (b->size >= 512) | ||
364 | kfree(b); | ||
365 | else { | ||
366 | b->next = tty->buf.free; | ||
367 | tty->buf.free = b; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * __tty_buffer_flush - flush full tty buffers | ||
373 | * @tty: tty to flush | ||
374 | * | ||
375 | * flush all the buffers containing receive data. Caller must | ||
376 | * hold the buffer lock and must have ensured no parallel flush to | ||
377 | * ldisc is running. | ||
378 | * | ||
379 | * Locking: Caller must hold tty->buf.lock | ||
380 | */ | ||
381 | |||
382 | static void __tty_buffer_flush(struct tty_struct *tty) | ||
383 | { | ||
384 | struct tty_buffer *thead; | ||
385 | |||
386 | while ((thead = tty->buf.head) != NULL) { | ||
387 | tty->buf.head = thead->next; | ||
388 | tty_buffer_free(tty, thead); | ||
389 | } | ||
390 | tty->buf.tail = NULL; | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * tty_buffer_flush - flush full tty buffers | ||
395 | * @tty: tty to flush | ||
396 | * | ||
397 | * flush all the buffers containing receive data. If the buffer is | ||
398 | * being processed by flush_to_ldisc then we defer the processing | ||
399 | * to that function | ||
400 | * | ||
401 | * Locking: none | ||
402 | */ | ||
403 | |||
404 | static void tty_buffer_flush(struct tty_struct *tty) | ||
405 | { | ||
406 | unsigned long flags; | ||
407 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
408 | |||
409 | /* If the data is being pushed to the tty layer then we can't | ||
410 | process it here. Instead set a flag and the flush_to_ldisc | ||
411 | path will process the flush request before it exits */ | ||
412 | if (test_bit(TTY_FLUSHING, &tty->flags)) { | ||
413 | set_bit(TTY_FLUSHPENDING, &tty->flags); | ||
414 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
415 | wait_event(tty->read_wait, | ||
416 | test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); | ||
417 | return; | ||
418 | } else | ||
419 | __tty_buffer_flush(tty); | ||
420 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * tty_buffer_find - find a free tty buffer | ||
425 | * @tty: tty owning the buffer | ||
426 | * @size: characters wanted | ||
427 | * | ||
428 | * Locate an existing suitable tty buffer or if we are lacking one then | ||
429 | * allocate a new one. We round our buffers off in 256 character chunks | ||
430 | * to get better allocation behaviour. | ||
431 | * | ||
432 | * Locking: Caller must hold tty->buf.lock | ||
433 | */ | ||
434 | |||
435 | static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | ||
436 | { | ||
437 | struct tty_buffer **tbh = &tty->buf.free; | ||
438 | while ((*tbh) != NULL) { | ||
439 | struct tty_buffer *t = *tbh; | ||
440 | if (t->size >= size) { | ||
441 | *tbh = t->next; | ||
442 | t->next = NULL; | ||
443 | t->used = 0; | ||
444 | t->commit = 0; | ||
445 | t->read = 0; | ||
446 | tty->buf.memory_used += t->size; | ||
447 | return t; | ||
448 | } | ||
449 | tbh = &((*tbh)->next); | ||
450 | } | ||
451 | /* Round the buffer size out */ | ||
452 | size = (size + 0xFF) & ~0xFF; | ||
453 | return tty_buffer_alloc(tty, size); | ||
454 | /* Should possibly check if this fails for the largest buffer we | ||
455 | have queued and recycle that ? */ | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * tty_buffer_request_room - grow tty buffer if needed | ||
460 | * @tty: tty structure | ||
461 | * @size: size desired | ||
462 | * | ||
463 | * Make at least size bytes of linear space available for the tty | ||
464 | * buffer. If we fail return the size we managed to find. | ||
465 | * | ||
466 | * Locking: Takes tty->buf.lock | ||
467 | */ | ||
468 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | ||
469 | { | ||
470 | struct tty_buffer *b, *n; | ||
471 | int left; | ||
472 | unsigned long flags; | ||
473 | |||
474 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
475 | |||
476 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | ||
477 | remove this conditional if its worth it. This would be invisible | ||
478 | to the callers */ | ||
479 | if ((b = tty->buf.tail) != NULL) | ||
480 | left = b->size - b->used; | ||
481 | else | ||
482 | left = 0; | ||
483 | |||
484 | if (left < size) { | ||
485 | /* This is the slow path - looking for new buffers to use */ | ||
486 | if ((n = tty_buffer_find(tty, size)) != NULL) { | ||
487 | if (b != NULL) { | ||
488 | b->next = n; | ||
489 | b->commit = b->used; | ||
490 | } else | ||
491 | tty->buf.head = n; | ||
492 | tty->buf.tail = n; | ||
493 | } else | ||
494 | size = left; | ||
495 | } | ||
496 | |||
497 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
498 | return size; | ||
499 | } | ||
500 | EXPORT_SYMBOL_GPL(tty_buffer_request_room); | ||
501 | |||
502 | /** | ||
503 | * tty_insert_flip_string - Add characters to the tty buffer | ||
504 | * @tty: tty structure | ||
505 | * @chars: characters | ||
506 | * @size: size | ||
507 | * | ||
508 | * Queue a series of bytes to the tty buffering. All the characters | ||
509 | * passed are marked as without error. Returns the number added. | ||
510 | * | ||
511 | * Locking: Called functions may take tty->buf.lock | ||
512 | */ | ||
513 | |||
514 | int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, | ||
515 | size_t size) | ||
516 | { | ||
517 | int copied = 0; | ||
518 | do { | ||
519 | int space = tty_buffer_request_room(tty, size - copied); | ||
520 | struct tty_buffer *tb = tty->buf.tail; | ||
521 | /* If there is no space then tb may be NULL */ | ||
522 | if (unlikely(space == 0)) | ||
523 | break; | ||
524 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | ||
525 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | ||
526 | tb->used += space; | ||
527 | copied += space; | ||
528 | chars += space; | ||
529 | /* There is a small chance that we need to split the data over | ||
530 | several buffers. If this is the case we must loop */ | ||
531 | } while (unlikely(size > copied)); | ||
532 | return copied; | ||
533 | } | ||
534 | EXPORT_SYMBOL(tty_insert_flip_string); | ||
535 | |||
536 | /** | ||
537 | * tty_insert_flip_string_flags - Add characters to the tty buffer | ||
538 | * @tty: tty structure | ||
539 | * @chars: characters | ||
540 | * @flags: flag bytes | ||
541 | * @size: size | ||
542 | * | ||
543 | * Queue a series of bytes to the tty buffering. For each character | ||
544 | * the flags array indicates the status of the character. Returns the | ||
545 | * number added. | ||
546 | * | ||
547 | * Locking: Called functions may take tty->buf.lock | ||
548 | */ | ||
549 | |||
550 | int tty_insert_flip_string_flags(struct tty_struct *tty, | ||
551 | const unsigned char *chars, const char *flags, size_t size) | ||
552 | { | ||
553 | int copied = 0; | ||
554 | do { | ||
555 | int space = tty_buffer_request_room(tty, size - copied); | ||
556 | struct tty_buffer *tb = tty->buf.tail; | ||
557 | /* If there is no space then tb may be NULL */ | ||
558 | if (unlikely(space == 0)) | ||
559 | break; | ||
560 | memcpy(tb->char_buf_ptr + tb->used, chars, space); | ||
561 | memcpy(tb->flag_buf_ptr + tb->used, flags, space); | ||
562 | tb->used += space; | ||
563 | copied += space; | ||
564 | chars += space; | ||
565 | flags += space; | ||
566 | /* There is a small chance that we need to split the data over | ||
567 | several buffers. If this is the case we must loop */ | ||
568 | } while (unlikely(size > copied)); | ||
569 | return copied; | ||
570 | } | ||
571 | EXPORT_SYMBOL(tty_insert_flip_string_flags); | ||
572 | |||
573 | /** | ||
574 | * tty_schedule_flip - push characters to ldisc | ||
575 | * @tty: tty to push from | ||
576 | * | ||
577 | * Takes any pending buffers and transfers their ownership to the | ||
578 | * ldisc side of the queue. It then schedules those characters for | ||
579 | * processing by the line discipline. | ||
580 | * | ||
581 | * Locking: Takes tty->buf.lock | ||
582 | */ | ||
583 | |||
584 | void tty_schedule_flip(struct tty_struct *tty) | ||
585 | { | ||
586 | unsigned long flags; | ||
587 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
588 | if (tty->buf.tail != NULL) | ||
589 | tty->buf.tail->commit = tty->buf.tail->used; | ||
590 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
591 | schedule_delayed_work(&tty->buf.work, 1); | ||
592 | } | ||
593 | EXPORT_SYMBOL(tty_schedule_flip); | ||
594 | |||
595 | /** | ||
596 | * tty_prepare_flip_string - make room for characters | ||
597 | * @tty: tty | ||
598 | * @chars: return pointer for character write area | ||
599 | * @size: desired size | ||
600 | * | ||
601 | * Prepare a block of space in the buffer for data. Returns the length | ||
602 | * available and buffer pointer to the space which is now allocated and | ||
603 | * accounted for as ready for normal characters. This is used for drivers | ||
604 | * that need their own block copy routines into the buffer. There is no | ||
605 | * guarantee the buffer is a DMA target! | ||
606 | * | ||
607 | * Locking: May call functions taking tty->buf.lock | ||
608 | */ | ||
609 | |||
610 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, | ||
611 | size_t size) | ||
612 | { | ||
613 | int space = tty_buffer_request_room(tty, size); | ||
614 | if (likely(space)) { | ||
615 | struct tty_buffer *tb = tty->buf.tail; | ||
616 | *chars = tb->char_buf_ptr + tb->used; | ||
617 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | ||
618 | tb->used += space; | ||
619 | } | ||
620 | return space; | ||
621 | } | ||
622 | |||
623 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | ||
624 | |||
625 | /** | ||
626 | * tty_prepare_flip_string_flags - make room for characters | ||
627 | * @tty: tty | ||
628 | * @chars: return pointer for character write area | ||
629 | * @flags: return pointer for status flag write area | ||
630 | * @size: desired size | ||
631 | * | ||
632 | * Prepare a block of space in the buffer for data. Returns the length | ||
633 | * available and buffer pointer to the space which is now allocated and | ||
634 | * accounted for as ready for characters. This is used for drivers | ||
635 | * that need their own block copy routines into the buffer. There is no | ||
636 | * guarantee the buffer is a DMA target! | ||
637 | * | ||
638 | * Locking: May call functions taking tty->buf.lock | ||
639 | */ | ||
640 | |||
641 | int tty_prepare_flip_string_flags(struct tty_struct *tty, | ||
642 | unsigned char **chars, char **flags, size_t size) | ||
643 | { | ||
644 | int space = tty_buffer_request_room(tty, size); | ||
645 | if (likely(space)) { | ||
646 | struct tty_buffer *tb = tty->buf.tail; | ||
647 | *chars = tb->char_buf_ptr + tb->used; | ||
648 | *flags = tb->flag_buf_ptr + tb->used; | ||
649 | tb->used += space; | ||
650 | } | ||
651 | return space; | ||
652 | } | ||
653 | |||
654 | EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); | ||
655 | |||
656 | |||
657 | |||
658 | /** | 257 | /** |
659 | * get_tty_driver - find device of a tty | 258 | * get_tty_driver - find device of a tty |
660 | * @dev_t: device identifier | 259 | * @dev_t: device identifier |
@@ -675,7 +274,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) | |||
675 | if (device < base || device >= base + p->num) | 274 | if (device < base || device >= base + p->num) |
676 | continue; | 275 | continue; |
677 | *index = device - base; | 276 | *index = device - base; |
678 | return p; | 277 | return tty_driver_kref_get(p); |
679 | } | 278 | } |
680 | return NULL; | 279 | return NULL; |
681 | } | 280 | } |
@@ -719,7 +318,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) | |||
719 | 318 | ||
720 | if (tty_line >= 0 && tty_line <= p->num && p->ops && | 319 | if (tty_line >= 0 && tty_line <= p->num && p->ops && |
721 | p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { | 320 | p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { |
722 | res = p; | 321 | res = tty_driver_kref_get(p); |
723 | *line = tty_line; | 322 | *line = tty_line; |
724 | break; | 323 | break; |
725 | } | 324 | } |
@@ -819,20 +418,6 @@ static const struct file_operations tty_fops = { | |||
819 | .fasync = tty_fasync, | 418 | .fasync = tty_fasync, |
820 | }; | 419 | }; |
821 | 420 | ||
822 | #ifdef CONFIG_UNIX98_PTYS | ||
823 | static const struct file_operations ptmx_fops = { | ||
824 | .llseek = no_llseek, | ||
825 | .read = tty_read, | ||
826 | .write = tty_write, | ||
827 | .poll = tty_poll, | ||
828 | .unlocked_ioctl = tty_ioctl, | ||
829 | .compat_ioctl = tty_compat_ioctl, | ||
830 | .open = ptmx_open, | ||
831 | .release = tty_release, | ||
832 | .fasync = tty_fasync, | ||
833 | }; | ||
834 | #endif | ||
835 | |||
836 | static const struct file_operations console_fops = { | 421 | static const struct file_operations console_fops = { |
837 | .llseek = no_llseek, | 422 | .llseek = no_llseek, |
838 | .read = tty_read, | 423 | .read = tty_read, |
@@ -953,6 +538,7 @@ static void do_tty_hangup(struct work_struct *work) | |||
953 | struct tty_ldisc *ld; | 538 | struct tty_ldisc *ld; |
954 | int closecount = 0, n; | 539 | int closecount = 0, n; |
955 | unsigned long flags; | 540 | unsigned long flags; |
541 | int refs = 0; | ||
956 | 542 | ||
957 | if (!tty) | 543 | if (!tty) |
958 | return; | 544 | return; |
@@ -1019,8 +605,12 @@ static void do_tty_hangup(struct work_struct *work) | |||
1019 | if (tty->session) { | 605 | if (tty->session) { |
1020 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { | 606 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { |
1021 | spin_lock_irq(&p->sighand->siglock); | 607 | spin_lock_irq(&p->sighand->siglock); |
1022 | if (p->signal->tty == tty) | 608 | if (p->signal->tty == tty) { |
1023 | p->signal->tty = NULL; | 609 | p->signal->tty = NULL; |
610 | /* We defer the dereferences outside fo | ||
611 | the tasklist lock */ | ||
612 | refs++; | ||
613 | } | ||
1024 | if (!p->signal->leader) { | 614 | if (!p->signal->leader) { |
1025 | spin_unlock_irq(&p->sighand->siglock); | 615 | spin_unlock_irq(&p->sighand->siglock); |
1026 | continue; | 616 | continue; |
@@ -1046,6 +636,10 @@ static void do_tty_hangup(struct work_struct *work) | |||
1046 | tty->ctrl_status = 0; | 636 | tty->ctrl_status = 0; |
1047 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | 637 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
1048 | 638 | ||
639 | /* Account for the p->signal references we killed */ | ||
640 | while (refs--) | ||
641 | tty_kref_put(tty); | ||
642 | |||
1049 | /* | 643 | /* |
1050 | * If one of the devices matches a console pointer, we | 644 | * If one of the devices matches a console pointer, we |
1051 | * cannot just call hangup() because that will cause | 645 | * cannot just call hangup() because that will cause |
@@ -1115,6 +709,23 @@ void tty_vhangup(struct tty_struct *tty) | |||
1115 | EXPORT_SYMBOL(tty_vhangup); | 709 | EXPORT_SYMBOL(tty_vhangup); |
1116 | 710 | ||
1117 | /** | 711 | /** |
712 | * tty_vhangup_self - process vhangup for own ctty | ||
713 | * | ||
714 | * Perform a vhangup on the current controlling tty | ||
715 | */ | ||
716 | |||
717 | void tty_vhangup_self(void) | ||
718 | { | ||
719 | struct tty_struct *tty; | ||
720 | |||
721 | tty = get_current_tty(); | ||
722 | if (tty) { | ||
723 | tty_vhangup(tty); | ||
724 | tty_kref_put(tty); | ||
725 | } | ||
726 | } | ||
727 | |||
728 | /** | ||
1118 | * tty_hung_up_p - was tty hung up | 729 | * tty_hung_up_p - was tty hung up |
1119 | * @filp: file pointer of tty | 730 | * @filp: file pointer of tty |
1120 | * | 731 | * |
@@ -1167,16 +778,14 @@ void disassociate_ctty(int on_exit) | |||
1167 | struct pid *tty_pgrp = NULL; | 778 | struct pid *tty_pgrp = NULL; |
1168 | 779 | ||
1169 | 780 | ||
1170 | mutex_lock(&tty_mutex); | ||
1171 | tty = get_current_tty(); | 781 | tty = get_current_tty(); |
1172 | if (tty) { | 782 | if (tty) { |
1173 | tty_pgrp = get_pid(tty->pgrp); | 783 | tty_pgrp = get_pid(tty->pgrp); |
1174 | lock_kernel(); | 784 | lock_kernel(); |
1175 | mutex_unlock(&tty_mutex); | ||
1176 | /* XXX: here we race, there is nothing protecting tty */ | ||
1177 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) | 785 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) |
1178 | tty_vhangup(tty); | 786 | tty_vhangup(tty); |
1179 | unlock_kernel(); | 787 | unlock_kernel(); |
788 | tty_kref_put(tty); | ||
1180 | } else if (on_exit) { | 789 | } else if (on_exit) { |
1181 | struct pid *old_pgrp; | 790 | struct pid *old_pgrp; |
1182 | spin_lock_irq(¤t->sighand->siglock); | 791 | spin_lock_irq(¤t->sighand->siglock); |
@@ -1188,7 +797,6 @@ void disassociate_ctty(int on_exit) | |||
1188 | kill_pgrp(old_pgrp, SIGCONT, on_exit); | 797 | kill_pgrp(old_pgrp, SIGCONT, on_exit); |
1189 | put_pid(old_pgrp); | 798 | put_pid(old_pgrp); |
1190 | } | 799 | } |
1191 | mutex_unlock(&tty_mutex); | ||
1192 | return; | 800 | return; |
1193 | } | 801 | } |
1194 | if (tty_pgrp) { | 802 | if (tty_pgrp) { |
@@ -1203,8 +811,6 @@ void disassociate_ctty(int on_exit) | |||
1203 | current->signal->tty_old_pgrp = NULL; | 811 | current->signal->tty_old_pgrp = NULL; |
1204 | spin_unlock_irq(¤t->sighand->siglock); | 812 | spin_unlock_irq(¤t->sighand->siglock); |
1205 | 813 | ||
1206 | mutex_lock(&tty_mutex); | ||
1207 | /* It is possible that do_tty_hangup has free'd this tty */ | ||
1208 | tty = get_current_tty(); | 814 | tty = get_current_tty(); |
1209 | if (tty) { | 815 | if (tty) { |
1210 | unsigned long flags; | 816 | unsigned long flags; |
@@ -1214,13 +820,13 @@ void disassociate_ctty(int on_exit) | |||
1214 | tty->session = NULL; | 820 | tty->session = NULL; |
1215 | tty->pgrp = NULL; | 821 | tty->pgrp = NULL; |
1216 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | 822 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
823 | tty_kref_put(tty); | ||
1217 | } else { | 824 | } else { |
1218 | #ifdef TTY_DEBUG_HANGUP | 825 | #ifdef TTY_DEBUG_HANGUP |
1219 | printk(KERN_DEBUG "error attempted to write to tty [0x%p]" | 826 | printk(KERN_DEBUG "error attempted to write to tty [0x%p]" |
1220 | " = NULL", tty); | 827 | " = NULL", tty); |
1221 | #endif | 828 | #endif |
1222 | } | 829 | } |
1223 | mutex_unlock(&tty_mutex); | ||
1224 | 830 | ||
1225 | /* Now clear signal->tty under the lock */ | 831 | /* Now clear signal->tty under the lock */ |
1226 | read_lock(&tasklist_lock); | 832 | read_lock(&tasklist_lock); |
@@ -1420,19 +1026,19 @@ static inline ssize_t do_tty_write( | |||
1420 | 1026 | ||
1421 | /* write_buf/write_cnt is protected by the atomic_write_lock mutex */ | 1027 | /* write_buf/write_cnt is protected by the atomic_write_lock mutex */ |
1422 | if (tty->write_cnt < chunk) { | 1028 | if (tty->write_cnt < chunk) { |
1423 | unsigned char *buf; | 1029 | unsigned char *buf_chunk; |
1424 | 1030 | ||
1425 | if (chunk < 1024) | 1031 | if (chunk < 1024) |
1426 | chunk = 1024; | 1032 | chunk = 1024; |
1427 | 1033 | ||
1428 | buf = kmalloc(chunk, GFP_KERNEL); | 1034 | buf_chunk = kmalloc(chunk, GFP_KERNEL); |
1429 | if (!buf) { | 1035 | if (!buf_chunk) { |
1430 | ret = -ENOMEM; | 1036 | ret = -ENOMEM; |
1431 | goto out; | 1037 | goto out; |
1432 | } | 1038 | } |
1433 | kfree(tty->write_buf); | 1039 | kfree(tty->write_buf); |
1434 | tty->write_cnt = chunk; | 1040 | tty->write_cnt = chunk; |
1435 | tty->write_buf = buf; | 1041 | tty->write_buf = buf_chunk; |
1436 | } | 1042 | } |
1437 | 1043 | ||
1438 | /* Do the write .. */ | 1044 | /* Do the write .. */ |
@@ -1466,6 +1072,31 @@ out: | |||
1466 | return ret; | 1072 | return ret; |
1467 | } | 1073 | } |
1468 | 1074 | ||
1075 | /** | ||
1076 | * tty_write_message - write a message to a certain tty, not just the console. | ||
1077 | * @tty: the destination tty_struct | ||
1078 | * @msg: the message to write | ||
1079 | * | ||
1080 | * This is used for messages that need to be redirected to a specific tty. | ||
1081 | * We don't put it into the syslog queue right now maybe in the future if | ||
1082 | * really needed. | ||
1083 | * | ||
1084 | * We must still hold the BKL and test the CLOSING flag for the moment. | ||
1085 | */ | ||
1086 | |||
1087 | void tty_write_message(struct tty_struct *tty, char *msg) | ||
1088 | { | ||
1089 | lock_kernel(); | ||
1090 | if (tty) { | ||
1091 | mutex_lock(&tty->atomic_write_lock); | ||
1092 | if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) | ||
1093 | tty->ops->write(tty, msg, strlen(msg)); | ||
1094 | tty_write_unlock(tty); | ||
1095 | } | ||
1096 | unlock_kernel(); | ||
1097 | return; | ||
1098 | } | ||
1099 | |||
1469 | 1100 | ||
1470 | /** | 1101 | /** |
1471 | * tty_write - write method for tty device file | 1102 | * tty_write - write method for tty device file |
@@ -1533,42 +1164,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, | |||
1533 | return tty_write(file, buf, count, ppos); | 1164 | return tty_write(file, buf, count, ppos); |
1534 | } | 1165 | } |
1535 | 1166 | ||
1536 | void tty_port_init(struct tty_port *port) | ||
1537 | { | ||
1538 | memset(port, 0, sizeof(*port)); | ||
1539 | init_waitqueue_head(&port->open_wait); | ||
1540 | init_waitqueue_head(&port->close_wait); | ||
1541 | mutex_init(&port->mutex); | ||
1542 | port->close_delay = (50 * HZ) / 100; | ||
1543 | port->closing_wait = (3000 * HZ) / 100; | ||
1544 | } | ||
1545 | EXPORT_SYMBOL(tty_port_init); | ||
1546 | |||
1547 | int tty_port_alloc_xmit_buf(struct tty_port *port) | ||
1548 | { | ||
1549 | /* We may sleep in get_zeroed_page() */ | ||
1550 | mutex_lock(&port->mutex); | ||
1551 | if (port->xmit_buf == NULL) | ||
1552 | port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); | ||
1553 | mutex_unlock(&port->mutex); | ||
1554 | if (port->xmit_buf == NULL) | ||
1555 | return -ENOMEM; | ||
1556 | return 0; | ||
1557 | } | ||
1558 | EXPORT_SYMBOL(tty_port_alloc_xmit_buf); | ||
1559 | |||
1560 | void tty_port_free_xmit_buf(struct tty_port *port) | ||
1561 | { | ||
1562 | mutex_lock(&port->mutex); | ||
1563 | if (port->xmit_buf != NULL) { | ||
1564 | free_page((unsigned long)port->xmit_buf); | ||
1565 | port->xmit_buf = NULL; | ||
1566 | } | ||
1567 | mutex_unlock(&port->mutex); | ||
1568 | } | ||
1569 | EXPORT_SYMBOL(tty_port_free_xmit_buf); | ||
1570 | |||
1571 | |||
1572 | static char ptychar[] = "pqrstuvwxyzabcde"; | 1167 | static char ptychar[] = "pqrstuvwxyzabcde"; |
1573 | 1168 | ||
1574 | /** | 1169 | /** |
@@ -1592,7 +1187,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) | |||
1592 | } | 1187 | } |
1593 | 1188 | ||
1594 | /** | 1189 | /** |
1595 | * pty_line_name - generate name for a tty | 1190 | * tty_line_name - generate name for a tty |
1596 | * @driver: the tty driver in use | 1191 | * @driver: the tty driver in use |
1597 | * @index: the minor number | 1192 | * @index: the minor number |
1598 | * @p: output buffer of at least 7 bytes | 1193 | * @p: output buffer of at least 7 bytes |
@@ -1608,10 +1203,148 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p) | |||
1608 | } | 1203 | } |
1609 | 1204 | ||
1610 | /** | 1205 | /** |
1611 | * init_dev - initialise a tty device | 1206 | * tty_driver_lookup_tty() - find an existing tty, if any |
1207 | * @driver: the driver for the tty | ||
1208 | * @idx: the minor number | ||
1209 | * | ||
1210 | * Return the tty, if found or ERR_PTR() otherwise. | ||
1211 | * | ||
1212 | * Locking: tty_mutex must be held. If tty is found, the mutex must | ||
1213 | * be held until the 'fast-open' is also done. Will change once we | ||
1214 | * have refcounting in the driver and per driver locking | ||
1215 | */ | ||
1216 | struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, | ||
1217 | struct inode *inode, int idx) | ||
1218 | { | ||
1219 | struct tty_struct *tty; | ||
1220 | |||
1221 | if (driver->ops->lookup) | ||
1222 | return driver->ops->lookup(driver, inode, idx); | ||
1223 | |||
1224 | tty = driver->ttys[idx]; | ||
1225 | return tty; | ||
1226 | } | ||
1227 | |||
1228 | /** | ||
1229 | * tty_init_termios - helper for termios setup | ||
1230 | * @tty: the tty to set up | ||
1231 | * | ||
1232 | * Initialise the termios structures for this tty. Thus runs under | ||
1233 | * the tty_mutex currently so we can be relaxed about ordering. | ||
1234 | */ | ||
1235 | |||
1236 | int tty_init_termios(struct tty_struct *tty) | ||
1237 | { | ||
1238 | struct ktermios *tp; | ||
1239 | int idx = tty->index; | ||
1240 | |||
1241 | tp = tty->driver->termios[idx]; | ||
1242 | if (tp == NULL) { | ||
1243 | tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); | ||
1244 | if (tp == NULL) | ||
1245 | return -ENOMEM; | ||
1246 | memcpy(tp, &tty->driver->init_termios, | ||
1247 | sizeof(struct ktermios)); | ||
1248 | tty->driver->termios[idx] = tp; | ||
1249 | } | ||
1250 | tty->termios = tp; | ||
1251 | tty->termios_locked = tp + 1; | ||
1252 | |||
1253 | /* Compatibility until drivers always set this */ | ||
1254 | tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); | ||
1255 | tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); | ||
1256 | return 0; | ||
1257 | } | ||
1258 | |||
1259 | /** | ||
1260 | * tty_driver_install_tty() - install a tty entry in the driver | ||
1261 | * @driver: the driver for the tty | ||
1262 | * @tty: the tty | ||
1263 | * | ||
1264 | * Install a tty object into the driver tables. The tty->index field | ||
1265 | * will be set by the time this is called. This method is responsible | ||
1266 | * for ensuring any need additional structures are allocated and | ||
1267 | * configured. | ||
1268 | * | ||
1269 | * Locking: tty_mutex for now | ||
1270 | */ | ||
1271 | static int tty_driver_install_tty(struct tty_driver *driver, | ||
1272 | struct tty_struct *tty) | ||
1273 | { | ||
1274 | int idx = tty->index; | ||
1275 | |||
1276 | if (driver->ops->install) | ||
1277 | return driver->ops->install(driver, tty); | ||
1278 | |||
1279 | if (tty_init_termios(tty) == 0) { | ||
1280 | tty_driver_kref_get(driver); | ||
1281 | tty->count++; | ||
1282 | driver->ttys[idx] = tty; | ||
1283 | return 0; | ||
1284 | } | ||
1285 | return -ENOMEM; | ||
1286 | } | ||
1287 | |||
1288 | /** | ||
1289 | * tty_driver_remove_tty() - remove a tty from the driver tables | ||
1290 | * @driver: the driver for the tty | ||
1291 | * @idx: the minor number | ||
1292 | * | ||
1293 | * Remvoe a tty object from the driver tables. The tty->index field | ||
1294 | * will be set by the time this is called. | ||
1295 | * | ||
1296 | * Locking: tty_mutex for now | ||
1297 | */ | ||
1298 | static void tty_driver_remove_tty(struct tty_driver *driver, | ||
1299 | struct tty_struct *tty) | ||
1300 | { | ||
1301 | if (driver->ops->remove) | ||
1302 | driver->ops->remove(driver, tty); | ||
1303 | else | ||
1304 | driver->ttys[tty->index] = NULL; | ||
1305 | } | ||
1306 | |||
1307 | /* | ||
1308 | * tty_reopen() - fast re-open of an open tty | ||
1309 | * @tty - the tty to open | ||
1310 | * | ||
1311 | * Return 0 on success, -errno on error. | ||
1312 | * | ||
1313 | * Locking: tty_mutex must be held from the time the tty was found | ||
1314 | * till this open completes. | ||
1315 | */ | ||
1316 | static int tty_reopen(struct tty_struct *tty) | ||
1317 | { | ||
1318 | struct tty_driver *driver = tty->driver; | ||
1319 | |||
1320 | if (test_bit(TTY_CLOSING, &tty->flags)) | ||
1321 | return -EIO; | ||
1322 | |||
1323 | if (driver->type == TTY_DRIVER_TYPE_PTY && | ||
1324 | driver->subtype == PTY_TYPE_MASTER) { | ||
1325 | /* | ||
1326 | * special case for PTY masters: only one open permitted, | ||
1327 | * and the slave side open count is incremented as well. | ||
1328 | */ | ||
1329 | if (tty->count) | ||
1330 | return -EIO; | ||
1331 | |||
1332 | tty->link->count++; | ||
1333 | } | ||
1334 | tty->count++; | ||
1335 | tty->driver = driver; /* N.B. why do this every time?? */ | ||
1336 | |||
1337 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); | ||
1338 | |||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | /** | ||
1343 | * tty_init_dev - initialise a tty device | ||
1612 | * @driver: tty driver we are opening a device on | 1344 | * @driver: tty driver we are opening a device on |
1613 | * @idx: device index | 1345 | * @idx: device index |
1614 | * @tty: returned tty structure | 1346 | * @ret_tty: returned tty structure |
1347 | * @first_ok: ok to open a new device (used by ptmx) | ||
1615 | * | 1348 | * |
1616 | * Prepare a tty device. This may not be a "new" clean device but | 1349 | * Prepare a tty device. This may not be a "new" clean device but |
1617 | * could also be an active device. The pty drivers require special | 1350 | * could also be an active device. The pty drivers require special |
@@ -1631,37 +1364,16 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p) | |||
1631 | * relaxed for the (most common) case of reopening a tty. | 1364 | * relaxed for the (most common) case of reopening a tty. |
1632 | */ | 1365 | */ |
1633 | 1366 | ||
1634 | static int init_dev(struct tty_driver *driver, int idx, | 1367 | struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, |
1635 | struct tty_struct **ret_tty) | 1368 | int first_ok) |
1636 | { | 1369 | { |
1637 | struct tty_struct *tty, *o_tty; | 1370 | struct tty_struct *tty; |
1638 | struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc; | 1371 | int retval; |
1639 | struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; | ||
1640 | int retval = 0; | ||
1641 | 1372 | ||
1642 | /* check whether we're reopening an existing tty */ | 1373 | /* Check if pty master is being opened multiple times */ |
1643 | if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { | 1374 | if (driver->subtype == PTY_TYPE_MASTER && |
1644 | tty = devpts_get_tty(idx); | 1375 | (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) |
1645 | /* | 1376 | return ERR_PTR(-EIO); |
1646 | * If we don't have a tty here on a slave open, it's because | ||
1647 | * the master already started the close process and there's | ||
1648 | * no relation between devpts file and tty anymore. | ||
1649 | */ | ||
1650 | if (!tty && driver->subtype == PTY_TYPE_SLAVE) { | ||
1651 | retval = -EIO; | ||
1652 | goto end_init; | ||
1653 | } | ||
1654 | /* | ||
1655 | * It's safe from now on because init_dev() is called with | ||
1656 | * tty_mutex held and release_dev() won't change tty->count | ||
1657 | * or tty->flags without having to grab tty_mutex | ||
1658 | */ | ||
1659 | if (tty && driver->subtype == PTY_TYPE_MASTER) | ||
1660 | tty = tty->link; | ||
1661 | } else { | ||
1662 | tty = driver->ttys[idx]; | ||
1663 | } | ||
1664 | if (tty) goto fast_track; | ||
1665 | 1377 | ||
1666 | /* | 1378 | /* |
1667 | * First time open is complex, especially for PTY devices. | 1379 | * First time open is complex, especially for PTY devices. |
@@ -1671,189 +1383,69 @@ static int init_dev(struct tty_driver *driver, int idx, | |||
1671 | * and locked termios may be retained.) | 1383 | * and locked termios may be retained.) |
1672 | */ | 1384 | */ |
1673 | 1385 | ||
1674 | if (!try_module_get(driver->owner)) { | 1386 | if (!try_module_get(driver->owner)) |
1675 | retval = -ENODEV; | 1387 | return ERR_PTR(-ENODEV); |
1676 | goto end_init; | ||
1677 | } | ||
1678 | |||
1679 | o_tty = NULL; | ||
1680 | tp = o_tp = NULL; | ||
1681 | ltp = o_ltp = NULL; | ||
1682 | 1388 | ||
1683 | tty = alloc_tty_struct(); | 1389 | tty = alloc_tty_struct(); |
1684 | if (!tty) | 1390 | if (!tty) |
1685 | goto fail_no_mem; | 1391 | goto fail_no_mem; |
1686 | initialize_tty_struct(tty); | 1392 | initialize_tty_struct(tty, driver, idx); |
1687 | tty->driver = driver; | ||
1688 | tty->ops = driver->ops; | ||
1689 | tty->index = idx; | ||
1690 | tty_line_name(driver, idx, tty->name); | ||
1691 | |||
1692 | if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { | ||
1693 | tp_loc = &tty->termios; | ||
1694 | ltp_loc = &tty->termios_locked; | ||
1695 | } else { | ||
1696 | tp_loc = &driver->termios[idx]; | ||
1697 | ltp_loc = &driver->termios_locked[idx]; | ||
1698 | } | ||
1699 | |||
1700 | if (!*tp_loc) { | ||
1701 | tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); | ||
1702 | if (!tp) | ||
1703 | goto free_mem_out; | ||
1704 | *tp = driver->init_termios; | ||
1705 | } | ||
1706 | |||
1707 | if (!*ltp_loc) { | ||
1708 | ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); | ||
1709 | if (!ltp) | ||
1710 | goto free_mem_out; | ||
1711 | } | ||
1712 | |||
1713 | if (driver->type == TTY_DRIVER_TYPE_PTY) { | ||
1714 | o_tty = alloc_tty_struct(); | ||
1715 | if (!o_tty) | ||
1716 | goto free_mem_out; | ||
1717 | initialize_tty_struct(o_tty); | ||
1718 | o_tty->driver = driver->other; | ||
1719 | o_tty->ops = driver->ops; | ||
1720 | o_tty->index = idx; | ||
1721 | tty_line_name(driver->other, idx, o_tty->name); | ||
1722 | 1393 | ||
1723 | if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { | 1394 | retval = tty_driver_install_tty(driver, tty); |
1724 | o_tp_loc = &o_tty->termios; | 1395 | if (retval < 0) { |
1725 | o_ltp_loc = &o_tty->termios_locked; | 1396 | free_tty_struct(tty); |
1726 | } else { | 1397 | module_put(driver->owner); |
1727 | o_tp_loc = &driver->other->termios[idx]; | 1398 | return ERR_PTR(retval); |
1728 | o_ltp_loc = &driver->other->termios_locked[idx]; | ||
1729 | } | ||
1730 | |||
1731 | if (!*o_tp_loc) { | ||
1732 | o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); | ||
1733 | if (!o_tp) | ||
1734 | goto free_mem_out; | ||
1735 | *o_tp = driver->other->init_termios; | ||
1736 | } | ||
1737 | |||
1738 | if (!*o_ltp_loc) { | ||
1739 | o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); | ||
1740 | if (!o_ltp) | ||
1741 | goto free_mem_out; | ||
1742 | } | ||
1743 | |||
1744 | /* | ||
1745 | * Everything allocated ... set up the o_tty structure. | ||
1746 | */ | ||
1747 | if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) | ||
1748 | driver->other->ttys[idx] = o_tty; | ||
1749 | if (!*o_tp_loc) | ||
1750 | *o_tp_loc = o_tp; | ||
1751 | if (!*o_ltp_loc) | ||
1752 | *o_ltp_loc = o_ltp; | ||
1753 | o_tty->termios = *o_tp_loc; | ||
1754 | o_tty->termios_locked = *o_ltp_loc; | ||
1755 | driver->other->refcount++; | ||
1756 | if (driver->subtype == PTY_TYPE_MASTER) | ||
1757 | o_tty->count++; | ||
1758 | |||
1759 | /* Establish the links in both directions */ | ||
1760 | tty->link = o_tty; | ||
1761 | o_tty->link = tty; | ||
1762 | } | 1399 | } |
1763 | 1400 | ||
1764 | /* | 1401 | /* |
1765 | * All structures have been allocated, so now we install them. | ||
1766 | * Failures after this point use release_tty to clean up, so | ||
1767 | * there's no need to null out the local pointers. | ||
1768 | */ | ||
1769 | if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) | ||
1770 | driver->ttys[idx] = tty; | ||
1771 | |||
1772 | if (!*tp_loc) | ||
1773 | *tp_loc = tp; | ||
1774 | if (!*ltp_loc) | ||
1775 | *ltp_loc = ltp; | ||
1776 | tty->termios = *tp_loc; | ||
1777 | tty->termios_locked = *ltp_loc; | ||
1778 | /* Compatibility until drivers always set this */ | ||
1779 | tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); | ||
1780 | tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); | ||
1781 | driver->refcount++; | ||
1782 | tty->count++; | ||
1783 | |||
1784 | /* | ||
1785 | * Structures all installed ... call the ldisc open routines. | 1402 | * Structures all installed ... call the ldisc open routines. |
1786 | * If we fail here just call release_tty to clean up. No need | 1403 | * If we fail here just call release_tty to clean up. No need |
1787 | * to decrement the use counts, as release_tty doesn't care. | 1404 | * to decrement the use counts, as release_tty doesn't care. |
1788 | */ | 1405 | */ |
1789 | 1406 | ||
1790 | retval = tty_ldisc_setup(tty, o_tty); | 1407 | retval = tty_ldisc_setup(tty, tty->link); |
1791 | |||
1792 | if (retval) | 1408 | if (retval) |
1793 | goto release_mem_out; | 1409 | goto release_mem_out; |
1794 | goto success; | 1410 | return tty; |
1795 | |||
1796 | /* | ||
1797 | * This fast open can be used if the tty is already open. | ||
1798 | * No memory is allocated, and the only failures are from | ||
1799 | * attempting to open a closing tty or attempting multiple | ||
1800 | * opens on a pty master. | ||
1801 | */ | ||
1802 | fast_track: | ||
1803 | if (test_bit(TTY_CLOSING, &tty->flags)) { | ||
1804 | retval = -EIO; | ||
1805 | goto end_init; | ||
1806 | } | ||
1807 | if (driver->type == TTY_DRIVER_TYPE_PTY && | ||
1808 | driver->subtype == PTY_TYPE_MASTER) { | ||
1809 | /* | ||
1810 | * special case for PTY masters: only one open permitted, | ||
1811 | * and the slave side open count is incremented as well. | ||
1812 | */ | ||
1813 | if (tty->count) { | ||
1814 | retval = -EIO; | ||
1815 | goto end_init; | ||
1816 | } | ||
1817 | tty->link->count++; | ||
1818 | } | ||
1819 | tty->count++; | ||
1820 | tty->driver = driver; /* N.B. why do this every time?? */ | ||
1821 | |||
1822 | /* FIXME */ | ||
1823 | if (!test_bit(TTY_LDISC, &tty->flags)) | ||
1824 | printk(KERN_ERR "init_dev but no ldisc\n"); | ||
1825 | success: | ||
1826 | *ret_tty = tty; | ||
1827 | |||
1828 | /* All paths come through here to release the mutex */ | ||
1829 | end_init: | ||
1830 | return retval; | ||
1831 | |||
1832 | /* Release locally allocated memory ... nothing placed in slots */ | ||
1833 | free_mem_out: | ||
1834 | kfree(o_tp); | ||
1835 | if (o_tty) | ||
1836 | free_tty_struct(o_tty); | ||
1837 | kfree(ltp); | ||
1838 | kfree(tp); | ||
1839 | free_tty_struct(tty); | ||
1840 | 1411 | ||
1841 | fail_no_mem: | 1412 | fail_no_mem: |
1842 | module_put(driver->owner); | 1413 | module_put(driver->owner); |
1843 | retval = -ENOMEM; | 1414 | return ERR_PTR(-ENOMEM); |
1844 | goto end_init; | ||
1845 | 1415 | ||
1846 | /* call the tty release_tty routine to clean out this slot */ | 1416 | /* call the tty release_tty routine to clean out this slot */ |
1847 | release_mem_out: | 1417 | release_mem_out: |
1848 | if (printk_ratelimit()) | 1418 | if (printk_ratelimit()) |
1849 | printk(KERN_INFO "init_dev: ldisc open failed, " | 1419 | printk(KERN_INFO "tty_init_dev: ldisc open failed, " |
1850 | "clearing slot %d\n", idx); | 1420 | "clearing slot %d\n", idx); |
1851 | release_tty(tty, idx); | 1421 | release_tty(tty, idx); |
1852 | goto end_init; | 1422 | return ERR_PTR(retval); |
1853 | } | 1423 | } |
1854 | 1424 | ||
1425 | void tty_free_termios(struct tty_struct *tty) | ||
1426 | { | ||
1427 | struct ktermios *tp; | ||
1428 | int idx = tty->index; | ||
1429 | /* Kill this flag and push into drivers for locking etc */ | ||
1430 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { | ||
1431 | /* FIXME: Locking on ->termios array */ | ||
1432 | tp = tty->termios; | ||
1433 | tty->driver->termios[idx] = NULL; | ||
1434 | kfree(tp); | ||
1435 | } | ||
1436 | } | ||
1437 | EXPORT_SYMBOL(tty_free_termios); | ||
1438 | |||
1439 | void tty_shutdown(struct tty_struct *tty) | ||
1440 | { | ||
1441 | tty_driver_remove_tty(tty->driver, tty); | ||
1442 | tty_free_termios(tty); | ||
1443 | } | ||
1444 | EXPORT_SYMBOL(tty_shutdown); | ||
1445 | |||
1855 | /** | 1446 | /** |
1856 | * release_one_tty - release tty structure memory | 1447 | * release_one_tty - release tty structure memory |
1448 | * @kref: kref of tty we are obliterating | ||
1857 | * | 1449 | * |
1858 | * Releases memory associated with a tty structure, and clears out the | 1450 | * Releases memory associated with a tty structure, and clears out the |
1859 | * driver table slots. This function is called when a device is no longer | 1451 | * driver table slots. This function is called when a device is no longer |
@@ -1863,31 +1455,19 @@ release_mem_out: | |||
1863 | * tty_mutex - sometimes only | 1455 | * tty_mutex - sometimes only |
1864 | * takes the file list lock internally when working on the list | 1456 | * takes the file list lock internally when working on the list |
1865 | * of ttys that the driver keeps. | 1457 | * of ttys that the driver keeps. |
1866 | * FIXME: should we require tty_mutex is held here ?? | ||
1867 | */ | 1458 | */ |
1868 | static void release_one_tty(struct tty_struct *tty, int idx) | 1459 | static void release_one_tty(struct kref *kref) |
1869 | { | 1460 | { |
1870 | int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; | 1461 | struct tty_struct *tty = container_of(kref, struct tty_struct, kref); |
1871 | struct ktermios *tp; | 1462 | struct tty_driver *driver = tty->driver; |
1872 | |||
1873 | if (!devpts) | ||
1874 | tty->driver->ttys[idx] = NULL; | ||
1875 | |||
1876 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { | ||
1877 | tp = tty->termios; | ||
1878 | if (!devpts) | ||
1879 | tty->driver->termios[idx] = NULL; | ||
1880 | kfree(tp); | ||
1881 | |||
1882 | tp = tty->termios_locked; | ||
1883 | if (!devpts) | ||
1884 | tty->driver->termios_locked[idx] = NULL; | ||
1885 | kfree(tp); | ||
1886 | } | ||
1887 | |||
1888 | 1463 | ||
1464 | if (tty->ops->shutdown) | ||
1465 | tty->ops->shutdown(tty); | ||
1466 | else | ||
1467 | tty_shutdown(tty); | ||
1889 | tty->magic = 0; | 1468 | tty->magic = 0; |
1890 | tty->driver->refcount--; | 1469 | tty_driver_kref_put(driver); |
1470 | module_put(driver->owner); | ||
1891 | 1471 | ||
1892 | file_list_lock(); | 1472 | file_list_lock(); |
1893 | list_del_init(&tty->tty_files); | 1473 | list_del_init(&tty->tty_files); |
@@ -1897,6 +1477,21 @@ static void release_one_tty(struct tty_struct *tty, int idx) | |||
1897 | } | 1477 | } |
1898 | 1478 | ||
1899 | /** | 1479 | /** |
1480 | * tty_kref_put - release a tty kref | ||
1481 | * @tty: tty device | ||
1482 | * | ||
1483 | * Release a reference to a tty device and if need be let the kref | ||
1484 | * layer destruct the object for us | ||
1485 | */ | ||
1486 | |||
1487 | void tty_kref_put(struct tty_struct *tty) | ||
1488 | { | ||
1489 | if (tty) | ||
1490 | kref_put(&tty->kref, release_one_tty); | ||
1491 | } | ||
1492 | EXPORT_SYMBOL(tty_kref_put); | ||
1493 | |||
1494 | /** | ||
1900 | * release_tty - release tty structure memory | 1495 | * release_tty - release tty structure memory |
1901 | * | 1496 | * |
1902 | * Release both @tty and a possible linked partner (think pty pair), | 1497 | * Release both @tty and a possible linked partner (think pty pair), |
@@ -1907,15 +1502,16 @@ static void release_one_tty(struct tty_struct *tty, int idx) | |||
1907 | * takes the file list lock internally when working on the list | 1502 | * takes the file list lock internally when working on the list |
1908 | * of ttys that the driver keeps. | 1503 | * of ttys that the driver keeps. |
1909 | * FIXME: should we require tty_mutex is held here ?? | 1504 | * FIXME: should we require tty_mutex is held here ?? |
1505 | * | ||
1910 | */ | 1506 | */ |
1911 | static void release_tty(struct tty_struct *tty, int idx) | 1507 | static void release_tty(struct tty_struct *tty, int idx) |
1912 | { | 1508 | { |
1913 | struct tty_driver *driver = tty->driver; | 1509 | /* This should always be true but check for the moment */ |
1510 | WARN_ON(tty->index != idx); | ||
1914 | 1511 | ||
1915 | if (tty->link) | 1512 | if (tty->link) |
1916 | release_one_tty(tty->link, idx); | 1513 | tty_kref_put(tty->link); |
1917 | release_one_tty(tty, idx); | 1514 | tty_kref_put(tty); |
1918 | module_put(driver->owner); | ||
1919 | } | 1515 | } |
1920 | 1516 | ||
1921 | /* | 1517 | /* |
@@ -1926,20 +1522,21 @@ static void release_tty(struct tty_struct *tty, int idx) | |||
1926 | * WSH 09/09/97: rewritten to avoid some nasty race conditions that could | 1522 | * WSH 09/09/97: rewritten to avoid some nasty race conditions that could |
1927 | * lead to double frees or releasing memory still in use. | 1523 | * lead to double frees or releasing memory still in use. |
1928 | */ | 1524 | */ |
1929 | static void release_dev(struct file *filp) | 1525 | void tty_release_dev(struct file *filp) |
1930 | { | 1526 | { |
1931 | struct tty_struct *tty, *o_tty; | 1527 | struct tty_struct *tty, *o_tty; |
1932 | int pty_master, tty_closing, o_tty_closing, do_sleep; | 1528 | int pty_master, tty_closing, o_tty_closing, do_sleep; |
1933 | int devpts; | 1529 | int devpts; |
1934 | int idx; | 1530 | int idx; |
1935 | char buf[64]; | 1531 | char buf[64]; |
1532 | struct inode *inode; | ||
1936 | 1533 | ||
1534 | inode = filp->f_path.dentry->d_inode; | ||
1937 | tty = (struct tty_struct *)filp->private_data; | 1535 | tty = (struct tty_struct *)filp->private_data; |
1938 | if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, | 1536 | if (tty_paranoia_check(tty, inode, "tty_release_dev")) |
1939 | "release_dev")) | ||
1940 | return; | 1537 | return; |
1941 | 1538 | ||
1942 | check_tty_count(tty, "release_dev"); | 1539 | check_tty_count(tty, "tty_release_dev"); |
1943 | 1540 | ||
1944 | tty_fasync(-1, filp, 0); | 1541 | tty_fasync(-1, filp, 0); |
1945 | 1542 | ||
@@ -1951,33 +1548,27 @@ static void release_dev(struct file *filp) | |||
1951 | 1548 | ||
1952 | #ifdef TTY_PARANOIA_CHECK | 1549 | #ifdef TTY_PARANOIA_CHECK |
1953 | if (idx < 0 || idx >= tty->driver->num) { | 1550 | if (idx < 0 || idx >= tty->driver->num) { |
1954 | printk(KERN_DEBUG "release_dev: bad idx when trying to " | 1551 | printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " |
1955 | "free (%s)\n", tty->name); | 1552 | "free (%s)\n", tty->name); |
1956 | return; | 1553 | return; |
1957 | } | 1554 | } |
1958 | if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { | 1555 | if (!devpts) { |
1959 | if (tty != tty->driver->ttys[idx]) { | 1556 | if (tty != tty->driver->ttys[idx]) { |
1960 | printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " | 1557 | printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " |
1961 | "for (%s)\n", idx, tty->name); | 1558 | "for (%s)\n", idx, tty->name); |
1962 | return; | 1559 | return; |
1963 | } | 1560 | } |
1964 | if (tty->termios != tty->driver->termios[idx]) { | 1561 | if (tty->termios != tty->driver->termios[idx]) { |
1965 | printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " | 1562 | printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " |
1966 | "for (%s)\n", | 1563 | "for (%s)\n", |
1967 | idx, tty->name); | 1564 | idx, tty->name); |
1968 | return; | 1565 | return; |
1969 | } | 1566 | } |
1970 | if (tty->termios_locked != tty->driver->termios_locked[idx]) { | ||
1971 | printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " | ||
1972 | "termios_locked for (%s)\n", | ||
1973 | idx, tty->name); | ||
1974 | return; | ||
1975 | } | ||
1976 | } | 1567 | } |
1977 | #endif | 1568 | #endif |
1978 | 1569 | ||
1979 | #ifdef TTY_DEBUG_HANGUP | 1570 | #ifdef TTY_DEBUG_HANGUP |
1980 | printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", | 1571 | printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...", |
1981 | tty_name(tty, buf), tty->count); | 1572 | tty_name(tty, buf), tty->count); |
1982 | #endif | 1573 | #endif |
1983 | 1574 | ||
@@ -1985,26 +1576,19 @@ static void release_dev(struct file *filp) | |||
1985 | if (tty->driver->other && | 1576 | if (tty->driver->other && |
1986 | !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { | 1577 | !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { |
1987 | if (o_tty != tty->driver->other->ttys[idx]) { | 1578 | if (o_tty != tty->driver->other->ttys[idx]) { |
1988 | printk(KERN_DEBUG "release_dev: other->table[%d] " | 1579 | printk(KERN_DEBUG "tty_release_dev: other->table[%d] " |
1989 | "not o_tty for (%s)\n", | 1580 | "not o_tty for (%s)\n", |
1990 | idx, tty->name); | 1581 | idx, tty->name); |
1991 | return; | 1582 | return; |
1992 | } | 1583 | } |
1993 | if (o_tty->termios != tty->driver->other->termios[idx]) { | 1584 | if (o_tty->termios != tty->driver->other->termios[idx]) { |
1994 | printk(KERN_DEBUG "release_dev: other->termios[%d] " | 1585 | printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " |
1995 | "not o_termios for (%s)\n", | 1586 | "not o_termios for (%s)\n", |
1996 | idx, tty->name); | 1587 | idx, tty->name); |
1997 | return; | 1588 | return; |
1998 | } | 1589 | } |
1999 | if (o_tty->termios_locked != | ||
2000 | tty->driver->other->termios_locked[idx]) { | ||
2001 | printk(KERN_DEBUG "release_dev: other->termios_locked[" | ||
2002 | "%d] not o_termios_locked for (%s)\n", | ||
2003 | idx, tty->name); | ||
2004 | return; | ||
2005 | } | ||
2006 | if (o_tty->link != tty) { | 1590 | if (o_tty->link != tty) { |
2007 | printk(KERN_DEBUG "release_dev: bad pty pointers\n"); | 1591 | printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); |
2008 | return; | 1592 | return; |
2009 | } | 1593 | } |
2010 | } | 1594 | } |
@@ -2062,7 +1646,7 @@ static void release_dev(struct file *filp) | |||
2062 | if (!do_sleep) | 1646 | if (!do_sleep) |
2063 | break; | 1647 | break; |
2064 | 1648 | ||
2065 | printk(KERN_WARNING "release_dev: %s: read/write wait queue " | 1649 | printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " |
2066 | "active!\n", tty_name(tty, buf)); | 1650 | "active!\n", tty_name(tty, buf)); |
2067 | mutex_unlock(&tty_mutex); | 1651 | mutex_unlock(&tty_mutex); |
2068 | schedule(); | 1652 | schedule(); |
@@ -2075,14 +1659,14 @@ static void release_dev(struct file *filp) | |||
2075 | */ | 1659 | */ |
2076 | if (pty_master) { | 1660 | if (pty_master) { |
2077 | if (--o_tty->count < 0) { | 1661 | if (--o_tty->count < 0) { |
2078 | printk(KERN_WARNING "release_dev: bad pty slave count " | 1662 | printk(KERN_WARNING "tty_release_dev: bad pty slave count " |
2079 | "(%d) for %s\n", | 1663 | "(%d) for %s\n", |
2080 | o_tty->count, tty_name(o_tty, buf)); | 1664 | o_tty->count, tty_name(o_tty, buf)); |
2081 | o_tty->count = 0; | 1665 | o_tty->count = 0; |
2082 | } | 1666 | } |
2083 | } | 1667 | } |
2084 | if (--tty->count < 0) { | 1668 | if (--tty->count < 0) { |
2085 | printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", | 1669 | printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n", |
2086 | tty->count, tty_name(tty, buf)); | 1670 | tty->count, tty_name(tty, buf)); |
2087 | tty->count = 0; | 1671 | tty->count = 0; |
2088 | } | 1672 | } |
@@ -2145,11 +1729,11 @@ static void release_dev(struct file *filp) | |||
2145 | 1729 | ||
2146 | /* Make this pty number available for reallocation */ | 1730 | /* Make this pty number available for reallocation */ |
2147 | if (devpts) | 1731 | if (devpts) |
2148 | devpts_kill_index(idx); | 1732 | devpts_kill_index(inode, idx); |
2149 | } | 1733 | } |
2150 | 1734 | ||
2151 | /** | 1735 | /** |
2152 | * tty_open - open a tty device | 1736 | * __tty_open - open a tty device |
2153 | * @inode: inode of device file | 1737 | * @inode: inode of device file |
2154 | * @filp: file pointer to tty | 1738 | * @filp: file pointer to tty |
2155 | * | 1739 | * |
@@ -2164,14 +1748,14 @@ static void release_dev(struct file *filp) | |||
2164 | * The termios state of a pty is reset on first open so that | 1748 | * The termios state of a pty is reset on first open so that |
2165 | * settings don't persist across reuse. | 1749 | * settings don't persist across reuse. |
2166 | * | 1750 | * |
2167 | * Locking: tty_mutex protects tty, get_tty_driver and init_dev work. | 1751 | * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work. |
2168 | * tty->count should protect the rest. | 1752 | * tty->count should protect the rest. |
2169 | * ->siglock protects ->signal/->sighand | 1753 | * ->siglock protects ->signal/->sighand |
2170 | */ | 1754 | */ |
2171 | 1755 | ||
2172 | static int __tty_open(struct inode *inode, struct file *filp) | 1756 | static int __tty_open(struct inode *inode, struct file *filp) |
2173 | { | 1757 | { |
2174 | struct tty_struct *tty; | 1758 | struct tty_struct *tty = NULL; |
2175 | int noctty, retval; | 1759 | int noctty, retval; |
2176 | struct tty_driver *driver; | 1760 | struct tty_driver *driver; |
2177 | int index; | 1761 | int index; |
@@ -2193,23 +1777,25 @@ retry_open: | |||
2193 | mutex_unlock(&tty_mutex); | 1777 | mutex_unlock(&tty_mutex); |
2194 | return -ENXIO; | 1778 | return -ENXIO; |
2195 | } | 1779 | } |
2196 | driver = tty->driver; | 1780 | driver = tty_driver_kref_get(tty->driver); |
2197 | index = tty->index; | 1781 | index = tty->index; |
2198 | filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ | 1782 | filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ |
2199 | /* noctty = 1; */ | 1783 | /* noctty = 1; */ |
1784 | /* FIXME: Should we take a driver reference ? */ | ||
1785 | tty_kref_put(tty); | ||
2200 | goto got_driver; | 1786 | goto got_driver; |
2201 | } | 1787 | } |
2202 | #ifdef CONFIG_VT | 1788 | #ifdef CONFIG_VT |
2203 | if (device == MKDEV(TTY_MAJOR, 0)) { | 1789 | if (device == MKDEV(TTY_MAJOR, 0)) { |
2204 | extern struct tty_driver *console_driver; | 1790 | extern struct tty_driver *console_driver; |
2205 | driver = console_driver; | 1791 | driver = tty_driver_kref_get(console_driver); |
2206 | index = fg_console; | 1792 | index = fg_console; |
2207 | noctty = 1; | 1793 | noctty = 1; |
2208 | goto got_driver; | 1794 | goto got_driver; |
2209 | } | 1795 | } |
2210 | #endif | 1796 | #endif |
2211 | if (device == MKDEV(TTYAUX_MAJOR, 1)) { | 1797 | if (device == MKDEV(TTYAUX_MAJOR, 1)) { |
2212 | driver = console_device(&index); | 1798 | driver = tty_driver_kref_get(console_device(&index)); |
2213 | if (driver) { | 1799 | if (driver) { |
2214 | /* Don't let /dev/console block */ | 1800 | /* Don't let /dev/console block */ |
2215 | filp->f_flags |= O_NONBLOCK; | 1801 | filp->f_flags |= O_NONBLOCK; |
@@ -2226,10 +1812,25 @@ retry_open: | |||
2226 | return -ENODEV; | 1812 | return -ENODEV; |
2227 | } | 1813 | } |
2228 | got_driver: | 1814 | got_driver: |
2229 | retval = init_dev(driver, index, &tty); | 1815 | if (!tty) { |
1816 | /* check whether we're reopening an existing tty */ | ||
1817 | tty = tty_driver_lookup_tty(driver, inode, index); | ||
1818 | |||
1819 | if (IS_ERR(tty)) | ||
1820 | return PTR_ERR(tty); | ||
1821 | } | ||
1822 | |||
1823 | if (tty) { | ||
1824 | retval = tty_reopen(tty); | ||
1825 | if (retval) | ||
1826 | tty = ERR_PTR(retval); | ||
1827 | } else | ||
1828 | tty = tty_init_dev(driver, index, 0); | ||
1829 | |||
2230 | mutex_unlock(&tty_mutex); | 1830 | mutex_unlock(&tty_mutex); |
2231 | if (retval) | 1831 | tty_driver_kref_put(driver); |
2232 | return retval; | 1832 | if (IS_ERR(tty)) |
1833 | return PTR_ERR(tty); | ||
2233 | 1834 | ||
2234 | filp->private_data = tty; | 1835 | filp->private_data = tty; |
2235 | file_move(filp, &tty->tty_files); | 1836 | file_move(filp, &tty->tty_files); |
@@ -2257,7 +1858,7 @@ got_driver: | |||
2257 | printk(KERN_DEBUG "error %d in opening %s...", retval, | 1858 | printk(KERN_DEBUG "error %d in opening %s...", retval, |
2258 | tty->name); | 1859 | tty->name); |
2259 | #endif | 1860 | #endif |
2260 | release_dev(filp); | 1861 | tty_release_dev(filp); |
2261 | if (retval != -ERESTARTSYS) | 1862 | if (retval != -ERESTARTSYS) |
2262 | return retval; | 1863 | return retval; |
2263 | if (signal_pending(current)) | 1864 | if (signal_pending(current)) |
@@ -2296,69 +1897,6 @@ static int tty_open(struct inode *inode, struct file *filp) | |||
2296 | 1897 | ||
2297 | 1898 | ||
2298 | 1899 | ||
2299 | #ifdef CONFIG_UNIX98_PTYS | ||
2300 | /** | ||
2301 | * ptmx_open - open a unix 98 pty master | ||
2302 | * @inode: inode of device file | ||
2303 | * @filp: file pointer to tty | ||
2304 | * | ||
2305 | * Allocate a unix98 pty master device from the ptmx driver. | ||
2306 | * | ||
2307 | * Locking: tty_mutex protects theinit_dev work. tty->count should | ||
2308 | * protect the rest. | ||
2309 | * allocated_ptys_lock handles the list of free pty numbers | ||
2310 | */ | ||
2311 | |||
2312 | static int __ptmx_open(struct inode *inode, struct file *filp) | ||
2313 | { | ||
2314 | struct tty_struct *tty; | ||
2315 | int retval; | ||
2316 | int index; | ||
2317 | |||
2318 | nonseekable_open(inode, filp); | ||
2319 | |||
2320 | /* find a device that is not in use. */ | ||
2321 | index = devpts_new_index(); | ||
2322 | if (index < 0) | ||
2323 | return index; | ||
2324 | |||
2325 | mutex_lock(&tty_mutex); | ||
2326 | retval = init_dev(ptm_driver, index, &tty); | ||
2327 | mutex_unlock(&tty_mutex); | ||
2328 | |||
2329 | if (retval) | ||
2330 | goto out; | ||
2331 | |||
2332 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | ||
2333 | filp->private_data = tty; | ||
2334 | file_move(filp, &tty->tty_files); | ||
2335 | |||
2336 | retval = devpts_pty_new(tty->link); | ||
2337 | if (retval) | ||
2338 | goto out1; | ||
2339 | |||
2340 | check_tty_count(tty, "ptmx_open"); | ||
2341 | retval = ptm_driver->ops->open(tty, filp); | ||
2342 | if (!retval) | ||
2343 | return 0; | ||
2344 | out1: | ||
2345 | release_dev(filp); | ||
2346 | return retval; | ||
2347 | out: | ||
2348 | devpts_kill_index(index); | ||
2349 | return retval; | ||
2350 | } | ||
2351 | |||
2352 | static int ptmx_open(struct inode *inode, struct file *filp) | ||
2353 | { | ||
2354 | int ret; | ||
2355 | |||
2356 | lock_kernel(); | ||
2357 | ret = __ptmx_open(inode, filp); | ||
2358 | unlock_kernel(); | ||
2359 | return ret; | ||
2360 | } | ||
2361 | #endif | ||
2362 | 1900 | ||
2363 | /** | 1901 | /** |
2364 | * tty_release - vfs callback for close | 1902 | * tty_release - vfs callback for close |
@@ -2369,13 +1907,13 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
2369 | * this tty. There may however be several such references. | 1907 | * this tty. There may however be several such references. |
2370 | * | 1908 | * |
2371 | * Locking: | 1909 | * Locking: |
2372 | * Takes bkl. See release_dev | 1910 | * Takes bkl. See tty_release_dev |
2373 | */ | 1911 | */ |
2374 | 1912 | ||
2375 | static int tty_release(struct inode *inode, struct file *filp) | 1913 | static int tty_release(struct inode *inode, struct file *filp) |
2376 | { | 1914 | { |
2377 | lock_kernel(); | 1915 | lock_kernel(); |
2378 | release_dev(filp); | 1916 | tty_release_dev(filp); |
2379 | unlock_kernel(); | 1917 | unlock_kernel(); |
2380 | return 0; | 1918 | return 0; |
2381 | } | 1919 | } |
@@ -2524,7 +2062,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, | |||
2524 | 2062 | ||
2525 | /* For a PTY we need to lock the tty side */ | 2063 | /* For a PTY we need to lock the tty side */ |
2526 | mutex_lock(&real_tty->termios_mutex); | 2064 | mutex_lock(&real_tty->termios_mutex); |
2527 | if (!memcmp(ws, &tty->winsize, sizeof(*ws))) | 2065 | if (!memcmp(ws, &real_tty->winsize, sizeof(*ws))) |
2528 | goto done; | 2066 | goto done; |
2529 | /* Get the PID values and reference them so we can | 2067 | /* Get the PID values and reference them so we can |
2530 | avoid holding the tty ctrl lock while sending signals */ | 2068 | avoid holding the tty ctrl lock while sending signals */ |
@@ -2996,7 +2534,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2996 | case TIOCSTI: | 2534 | case TIOCSTI: |
2997 | return tiocsti(tty, p); | 2535 | return tiocsti(tty, p); |
2998 | case TIOCGWINSZ: | 2536 | case TIOCGWINSZ: |
2999 | return tiocgwinsz(tty, p); | 2537 | return tiocgwinsz(real_tty, p); |
3000 | case TIOCSWINSZ: | 2538 | case TIOCSWINSZ: |
3001 | return tiocswinsz(tty, real_tty, p); | 2539 | return tiocswinsz(tty, real_tty, p); |
3002 | case TIOCCONS: | 2540 | case TIOCCONS: |
@@ -3026,10 +2564,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
3026 | return put_user(tty->ldisc.ops->num, (int __user *)p); | 2564 | return put_user(tty->ldisc.ops->num, (int __user *)p); |
3027 | case TIOCSETD: | 2565 | case TIOCSETD: |
3028 | return tiocsetd(tty, p); | 2566 | return tiocsetd(tty, p); |
3029 | #ifdef CONFIG_VT | ||
3030 | case TIOCLINUX: | ||
3031 | return tioclinux(tty, arg); | ||
3032 | #endif | ||
3033 | /* | 2567 | /* |
3034 | * Break handling | 2568 | * Break handling |
3035 | */ | 2569 | */ |
@@ -3220,113 +2754,6 @@ void do_SAK(struct tty_struct *tty) | |||
3220 | EXPORT_SYMBOL(do_SAK); | 2754 | EXPORT_SYMBOL(do_SAK); |
3221 | 2755 | ||
3222 | /** | 2756 | /** |
3223 | * flush_to_ldisc | ||
3224 | * @work: tty structure passed from work queue. | ||
3225 | * | ||
3226 | * This routine is called out of the software interrupt to flush data | ||
3227 | * from the buffer chain to the line discipline. | ||
3228 | * | ||
3229 | * Locking: holds tty->buf.lock to guard buffer list. Drops the lock | ||
3230 | * while invoking the line discipline receive_buf method. The | ||
3231 | * receive_buf method is single threaded for each tty instance. | ||
3232 | */ | ||
3233 | |||
3234 | static void flush_to_ldisc(struct work_struct *work) | ||
3235 | { | ||
3236 | struct tty_struct *tty = | ||
3237 | container_of(work, struct tty_struct, buf.work.work); | ||
3238 | unsigned long flags; | ||
3239 | struct tty_ldisc *disc; | ||
3240 | struct tty_buffer *tbuf, *head; | ||
3241 | char *char_buf; | ||
3242 | unsigned char *flag_buf; | ||
3243 | |||
3244 | disc = tty_ldisc_ref(tty); | ||
3245 | if (disc == NULL) /* !TTY_LDISC */ | ||
3246 | return; | ||
3247 | |||
3248 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
3249 | /* So we know a flush is running */ | ||
3250 | set_bit(TTY_FLUSHING, &tty->flags); | ||
3251 | head = tty->buf.head; | ||
3252 | if (head != NULL) { | ||
3253 | tty->buf.head = NULL; | ||
3254 | for (;;) { | ||
3255 | int count = head->commit - head->read; | ||
3256 | if (!count) { | ||
3257 | if (head->next == NULL) | ||
3258 | break; | ||
3259 | tbuf = head; | ||
3260 | head = head->next; | ||
3261 | tty_buffer_free(tty, tbuf); | ||
3262 | continue; | ||
3263 | } | ||
3264 | /* Ldisc or user is trying to flush the buffers | ||
3265 | we are feeding to the ldisc, stop feeding the | ||
3266 | line discipline as we want to empty the queue */ | ||
3267 | if (test_bit(TTY_FLUSHPENDING, &tty->flags)) | ||
3268 | break; | ||
3269 | if (!tty->receive_room) { | ||
3270 | schedule_delayed_work(&tty->buf.work, 1); | ||
3271 | break; | ||
3272 | } | ||
3273 | if (count > tty->receive_room) | ||
3274 | count = tty->receive_room; | ||
3275 | char_buf = head->char_buf_ptr + head->read; | ||
3276 | flag_buf = head->flag_buf_ptr + head->read; | ||
3277 | head->read += count; | ||
3278 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
3279 | disc->ops->receive_buf(tty, char_buf, | ||
3280 | flag_buf, count); | ||
3281 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
3282 | } | ||
3283 | /* Restore the queue head */ | ||
3284 | tty->buf.head = head; | ||
3285 | } | ||
3286 | /* We may have a deferred request to flush the input buffer, | ||
3287 | if so pull the chain under the lock and empty the queue */ | ||
3288 | if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { | ||
3289 | __tty_buffer_flush(tty); | ||
3290 | clear_bit(TTY_FLUSHPENDING, &tty->flags); | ||
3291 | wake_up(&tty->read_wait); | ||
3292 | } | ||
3293 | clear_bit(TTY_FLUSHING, &tty->flags); | ||
3294 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
3295 | |||
3296 | tty_ldisc_deref(disc); | ||
3297 | } | ||
3298 | |||
3299 | /** | ||
3300 | * tty_flip_buffer_push - terminal | ||
3301 | * @tty: tty to push | ||
3302 | * | ||
3303 | * Queue a push of the terminal flip buffers to the line discipline. This | ||
3304 | * function must not be called from IRQ context if tty->low_latency is set. | ||
3305 | * | ||
3306 | * In the event of the queue being busy for flipping the work will be | ||
3307 | * held off and retried later. | ||
3308 | * | ||
3309 | * Locking: tty buffer lock. Driver locks in low latency mode. | ||
3310 | */ | ||
3311 | |||
3312 | void tty_flip_buffer_push(struct tty_struct *tty) | ||
3313 | { | ||
3314 | unsigned long flags; | ||
3315 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
3316 | if (tty->buf.tail != NULL) | ||
3317 | tty->buf.tail->commit = tty->buf.tail->used; | ||
3318 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
3319 | |||
3320 | if (tty->low_latency) | ||
3321 | flush_to_ldisc(&tty->buf.work.work); | ||
3322 | else | ||
3323 | schedule_delayed_work(&tty->buf.work, 1); | ||
3324 | } | ||
3325 | |||
3326 | EXPORT_SYMBOL(tty_flip_buffer_push); | ||
3327 | |||
3328 | |||
3329 | /** | ||
3330 | * initialize_tty_struct | 2757 | * initialize_tty_struct |
3331 | * @tty: tty to initialize | 2758 | * @tty: tty to initialize |
3332 | * | 2759 | * |
@@ -3336,9 +2763,11 @@ EXPORT_SYMBOL(tty_flip_buffer_push); | |||
3336 | * Locking: none - tty in question must not be exposed at this point | 2763 | * Locking: none - tty in question must not be exposed at this point |
3337 | */ | 2764 | */ |
3338 | 2765 | ||
3339 | static void initialize_tty_struct(struct tty_struct *tty) | 2766 | void initialize_tty_struct(struct tty_struct *tty, |
2767 | struct tty_driver *driver, int idx) | ||
3340 | { | 2768 | { |
3341 | memset(tty, 0, sizeof(struct tty_struct)); | 2769 | memset(tty, 0, sizeof(struct tty_struct)); |
2770 | kref_init(&tty->kref); | ||
3342 | tty->magic = TTY_MAGIC; | 2771 | tty->magic = TTY_MAGIC; |
3343 | tty_ldisc_init(tty); | 2772 | tty_ldisc_init(tty); |
3344 | tty->session = NULL; | 2773 | tty->session = NULL; |
@@ -3346,7 +2775,6 @@ static void initialize_tty_struct(struct tty_struct *tty) | |||
3346 | tty->overrun_time = jiffies; | 2775 | tty->overrun_time = jiffies; |
3347 | tty->buf.head = tty->buf.tail = NULL; | 2776 | tty->buf.head = tty->buf.tail = NULL; |
3348 | tty_buffer_init(tty); | 2777 | tty_buffer_init(tty); |
3349 | INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); | ||
3350 | mutex_init(&tty->termios_mutex); | 2778 | mutex_init(&tty->termios_mutex); |
3351 | init_waitqueue_head(&tty->write_wait); | 2779 | init_waitqueue_head(&tty->write_wait); |
3352 | init_waitqueue_head(&tty->read_wait); | 2780 | init_waitqueue_head(&tty->read_wait); |
@@ -3357,6 +2785,11 @@ static void initialize_tty_struct(struct tty_struct *tty) | |||
3357 | spin_lock_init(&tty->ctrl_lock); | 2785 | spin_lock_init(&tty->ctrl_lock); |
3358 | INIT_LIST_HEAD(&tty->tty_files); | 2786 | INIT_LIST_HEAD(&tty->tty_files); |
3359 | INIT_WORK(&tty->SAK_work, do_SAK_work); | 2787 | INIT_WORK(&tty->SAK_work, do_SAK_work); |
2788 | |||
2789 | tty->driver = driver; | ||
2790 | tty->ops = driver->ops; | ||
2791 | tty->index = idx; | ||
2792 | tty_line_name(driver, idx, tty->name); | ||
3360 | } | 2793 | } |
3361 | 2794 | ||
3362 | /** | 2795 | /** |
@@ -3377,10 +2810,9 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch) | |||
3377 | return tty->ops->put_char(tty, ch); | 2810 | return tty->ops->put_char(tty, ch); |
3378 | return tty->ops->write(tty, &ch, 1); | 2811 | return tty->ops->write(tty, &ch, 1); |
3379 | } | 2812 | } |
3380 | |||
3381 | EXPORT_SYMBOL_GPL(tty_put_char); | 2813 | EXPORT_SYMBOL_GPL(tty_put_char); |
3382 | 2814 | ||
3383 | static struct class *tty_class; | 2815 | struct class *tty_class; |
3384 | 2816 | ||
3385 | /** | 2817 | /** |
3386 | * tty_register_device - register a tty device | 2818 | * tty_register_device - register a tty device |
@@ -3420,6 +2852,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, | |||
3420 | 2852 | ||
3421 | return device_create_drvdata(tty_class, device, dev, NULL, name); | 2853 | return device_create_drvdata(tty_class, device, dev, NULL, name); |
3422 | } | 2854 | } |
2855 | EXPORT_SYMBOL(tty_register_device); | ||
3423 | 2856 | ||
3424 | /** | 2857 | /** |
3425 | * tty_unregister_device - unregister a tty device | 2858 | * tty_unregister_device - unregister a tty device |
@@ -3437,8 +2870,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) | |||
3437 | device_destroy(tty_class, | 2870 | device_destroy(tty_class, |
3438 | MKDEV(driver->major, driver->minor_start) + index); | 2871 | MKDEV(driver->major, driver->minor_start) + index); |
3439 | } | 2872 | } |
3440 | |||
3441 | EXPORT_SYMBOL(tty_register_device); | ||
3442 | EXPORT_SYMBOL(tty_unregister_device); | 2873 | EXPORT_SYMBOL(tty_unregister_device); |
3443 | 2874 | ||
3444 | struct tty_driver *alloc_tty_driver(int lines) | 2875 | struct tty_driver *alloc_tty_driver(int lines) |
@@ -3447,27 +2878,65 @@ struct tty_driver *alloc_tty_driver(int lines) | |||
3447 | 2878 | ||
3448 | driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); | 2879 | driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); |
3449 | if (driver) { | 2880 | if (driver) { |
2881 | kref_init(&driver->kref); | ||
3450 | driver->magic = TTY_DRIVER_MAGIC; | 2882 | driver->magic = TTY_DRIVER_MAGIC; |
3451 | driver->num = lines; | 2883 | driver->num = lines; |
3452 | /* later we'll move allocation of tables here */ | 2884 | /* later we'll move allocation of tables here */ |
3453 | } | 2885 | } |
3454 | return driver; | 2886 | return driver; |
3455 | } | 2887 | } |
2888 | EXPORT_SYMBOL(alloc_tty_driver); | ||
3456 | 2889 | ||
3457 | void put_tty_driver(struct tty_driver *driver) | 2890 | static void destruct_tty_driver(struct kref *kref) |
3458 | { | 2891 | { |
2892 | struct tty_driver *driver = container_of(kref, struct tty_driver, kref); | ||
2893 | int i; | ||
2894 | struct ktermios *tp; | ||
2895 | void *p; | ||
2896 | |||
2897 | if (driver->flags & TTY_DRIVER_INSTALLED) { | ||
2898 | /* | ||
2899 | * Free the termios and termios_locked structures because | ||
2900 | * we don't want to get memory leaks when modular tty | ||
2901 | * drivers are removed from the kernel. | ||
2902 | */ | ||
2903 | for (i = 0; i < driver->num; i++) { | ||
2904 | tp = driver->termios[i]; | ||
2905 | if (tp) { | ||
2906 | driver->termios[i] = NULL; | ||
2907 | kfree(tp); | ||
2908 | } | ||
2909 | if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) | ||
2910 | tty_unregister_device(driver, i); | ||
2911 | } | ||
2912 | p = driver->ttys; | ||
2913 | proc_tty_unregister_driver(driver); | ||
2914 | driver->ttys = NULL; | ||
2915 | driver->termios = NULL; | ||
2916 | kfree(p); | ||
2917 | cdev_del(&driver->cdev); | ||
2918 | } | ||
3459 | kfree(driver); | 2919 | kfree(driver); |
3460 | } | 2920 | } |
3461 | 2921 | ||
2922 | void tty_driver_kref_put(struct tty_driver *driver) | ||
2923 | { | ||
2924 | kref_put(&driver->kref, destruct_tty_driver); | ||
2925 | } | ||
2926 | EXPORT_SYMBOL(tty_driver_kref_put); | ||
2927 | |||
3462 | void tty_set_operations(struct tty_driver *driver, | 2928 | void tty_set_operations(struct tty_driver *driver, |
3463 | const struct tty_operations *op) | 2929 | const struct tty_operations *op) |
3464 | { | 2930 | { |
3465 | driver->ops = op; | 2931 | driver->ops = op; |
3466 | }; | 2932 | }; |
2933 | EXPORT_SYMBOL(tty_set_operations); | ||
3467 | 2934 | ||
3468 | EXPORT_SYMBOL(alloc_tty_driver); | 2935 | void put_tty_driver(struct tty_driver *d) |
2936 | { | ||
2937 | tty_driver_kref_put(d); | ||
2938 | } | ||
3469 | EXPORT_SYMBOL(put_tty_driver); | 2939 | EXPORT_SYMBOL(put_tty_driver); |
3470 | EXPORT_SYMBOL(tty_set_operations); | ||
3471 | 2940 | ||
3472 | /* | 2941 | /* |
3473 | * Called by a tty driver to register itself. | 2942 | * Called by a tty driver to register itself. |
@@ -3479,11 +2948,8 @@ int tty_register_driver(struct tty_driver *driver) | |||
3479 | dev_t dev; | 2948 | dev_t dev; |
3480 | void **p = NULL; | 2949 | void **p = NULL; |
3481 | 2950 | ||
3482 | if (driver->flags & TTY_DRIVER_INSTALLED) | ||
3483 | return 0; | ||
3484 | |||
3485 | if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { | 2951 | if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { |
3486 | p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); | 2952 | p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); |
3487 | if (!p) | 2953 | if (!p) |
3488 | return -ENOMEM; | 2954 | return -ENOMEM; |
3489 | } | 2955 | } |
@@ -3507,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver) | |||
3507 | if (p) { | 2973 | if (p) { |
3508 | driver->ttys = (struct tty_struct **)p; | 2974 | driver->ttys = (struct tty_struct **)p; |
3509 | driver->termios = (struct ktermios **)(p + driver->num); | 2975 | driver->termios = (struct ktermios **)(p + driver->num); |
3510 | driver->termios_locked = (struct ktermios **) | ||
3511 | (p + driver->num * 2); | ||
3512 | } else { | 2976 | } else { |
3513 | driver->ttys = NULL; | 2977 | driver->ttys = NULL; |
3514 | driver->termios = NULL; | 2978 | driver->termios = NULL; |
3515 | driver->termios_locked = NULL; | ||
3516 | } | 2979 | } |
3517 | 2980 | ||
3518 | cdev_init(&driver->cdev, &tty_fops); | 2981 | cdev_init(&driver->cdev, &tty_fops); |
@@ -3521,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver) | |||
3521 | if (error) { | 2984 | if (error) { |
3522 | unregister_chrdev_region(dev, driver->num); | 2985 | unregister_chrdev_region(dev, driver->num); |
3523 | driver->ttys = NULL; | 2986 | driver->ttys = NULL; |
3524 | driver->termios = driver->termios_locked = NULL; | 2987 | driver->termios = NULL; |
3525 | kfree(p); | 2988 | kfree(p); |
3526 | return error; | 2989 | return error; |
3527 | } | 2990 | } |
@@ -3535,6 +2998,7 @@ int tty_register_driver(struct tty_driver *driver) | |||
3535 | tty_register_device(driver, i, NULL); | 2998 | tty_register_device(driver, i, NULL); |
3536 | } | 2999 | } |
3537 | proc_tty_register_driver(driver); | 3000 | proc_tty_register_driver(driver); |
3001 | driver->flags |= TTY_DRIVER_INSTALLED; | ||
3538 | return 0; | 3002 | return 0; |
3539 | } | 3003 | } |
3540 | 3004 | ||
@@ -3545,46 +3009,19 @@ EXPORT_SYMBOL(tty_register_driver); | |||
3545 | */ | 3009 | */ |
3546 | int tty_unregister_driver(struct tty_driver *driver) | 3010 | int tty_unregister_driver(struct tty_driver *driver) |
3547 | { | 3011 | { |
3548 | int i; | 3012 | #if 0 |
3549 | struct ktermios *tp; | 3013 | /* FIXME */ |
3550 | void *p; | ||
3551 | |||
3552 | if (driver->refcount) | 3014 | if (driver->refcount) |
3553 | return -EBUSY; | 3015 | return -EBUSY; |
3554 | 3016 | #endif | |
3555 | unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), | 3017 | unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), |
3556 | driver->num); | 3018 | driver->num); |
3557 | mutex_lock(&tty_mutex); | 3019 | mutex_lock(&tty_mutex); |
3558 | list_del(&driver->tty_drivers); | 3020 | list_del(&driver->tty_drivers); |
3559 | mutex_unlock(&tty_mutex); | 3021 | mutex_unlock(&tty_mutex); |
3560 | |||
3561 | /* | ||
3562 | * Free the termios and termios_locked structures because | ||
3563 | * we don't want to get memory leaks when modular tty | ||
3564 | * drivers are removed from the kernel. | ||
3565 | */ | ||
3566 | for (i = 0; i < driver->num; i++) { | ||
3567 | tp = driver->termios[i]; | ||
3568 | if (tp) { | ||
3569 | driver->termios[i] = NULL; | ||
3570 | kfree(tp); | ||
3571 | } | ||
3572 | tp = driver->termios_locked[i]; | ||
3573 | if (tp) { | ||
3574 | driver->termios_locked[i] = NULL; | ||
3575 | kfree(tp); | ||
3576 | } | ||
3577 | if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) | ||
3578 | tty_unregister_device(driver, i); | ||
3579 | } | ||
3580 | p = driver->ttys; | ||
3581 | proc_tty_unregister_driver(driver); | ||
3582 | driver->ttys = NULL; | ||
3583 | driver->termios = driver->termios_locked = NULL; | ||
3584 | kfree(p); | ||
3585 | cdev_del(&driver->cdev); | ||
3586 | return 0; | 3022 | return 0; |
3587 | } | 3023 | } |
3024 | |||
3588 | EXPORT_SYMBOL(tty_unregister_driver); | 3025 | EXPORT_SYMBOL(tty_unregister_driver); |
3589 | 3026 | ||
3590 | dev_t tty_devnum(struct tty_struct *tty) | 3027 | dev_t tty_devnum(struct tty_struct *tty) |
@@ -3595,9 +3032,12 @@ EXPORT_SYMBOL(tty_devnum); | |||
3595 | 3032 | ||
3596 | void proc_clear_tty(struct task_struct *p) | 3033 | void proc_clear_tty(struct task_struct *p) |
3597 | { | 3034 | { |
3035 | struct tty_struct *tty; | ||
3598 | spin_lock_irq(&p->sighand->siglock); | 3036 | spin_lock_irq(&p->sighand->siglock); |
3037 | tty = p->signal->tty; | ||
3599 | p->signal->tty = NULL; | 3038 | p->signal->tty = NULL; |
3600 | spin_unlock_irq(&p->sighand->siglock); | 3039 | spin_unlock_irq(&p->sighand->siglock); |
3040 | tty_kref_put(tty); | ||
3601 | } | 3041 | } |
3602 | 3042 | ||
3603 | /* Called under the sighand lock */ | 3043 | /* Called under the sighand lock */ |
@@ -3613,9 +3053,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) | |||
3613 | tty->pgrp = get_pid(task_pgrp(tsk)); | 3053 | tty->pgrp = get_pid(task_pgrp(tsk)); |
3614 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | 3054 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
3615 | tty->session = get_pid(task_session(tsk)); | 3055 | tty->session = get_pid(task_session(tsk)); |
3056 | if (tsk->signal->tty) { | ||
3057 | printk(KERN_DEBUG "tty not NULL!!\n"); | ||
3058 | tty_kref_put(tsk->signal->tty); | ||
3059 | } | ||
3616 | } | 3060 | } |
3617 | put_pid(tsk->signal->tty_old_pgrp); | 3061 | put_pid(tsk->signal->tty_old_pgrp); |
3618 | tsk->signal->tty = tty; | 3062 | tsk->signal->tty = tty_kref_get(tty); |
3619 | tsk->signal->tty_old_pgrp = NULL; | 3063 | tsk->signal->tty_old_pgrp = NULL; |
3620 | } | 3064 | } |
3621 | 3065 | ||
@@ -3629,18 +3073,20 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) | |||
3629 | struct tty_struct *get_current_tty(void) | 3073 | struct tty_struct *get_current_tty(void) |
3630 | { | 3074 | { |
3631 | struct tty_struct *tty; | 3075 | struct tty_struct *tty; |
3632 | WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); | 3076 | unsigned long flags; |
3633 | tty = current->signal->tty; | 3077 | |
3634 | /* | 3078 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
3635 | * session->tty can be changed/cleared from under us, make sure we | 3079 | tty = tty_kref_get(current->signal->tty); |
3636 | * issue the load. The obtained pointer, when not NULL, is valid as | 3080 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
3637 | * long as we hold tty_mutex. | ||
3638 | */ | ||
3639 | barrier(); | ||
3640 | return tty; | 3081 | return tty; |
3641 | } | 3082 | } |
3642 | EXPORT_SYMBOL_GPL(get_current_tty); | 3083 | EXPORT_SYMBOL_GPL(get_current_tty); |
3643 | 3084 | ||
3085 | void tty_default_fops(struct file_operations *fops) | ||
3086 | { | ||
3087 | *fops = tty_fops; | ||
3088 | } | ||
3089 | |||
3644 | /* | 3090 | /* |
3645 | * Initialize the console device. This is called *early*, so | 3091 | * Initialize the console device. This is called *early*, so |
3646 | * we can't necessarily depend on lots of kernel help here. | 3092 | * we can't necessarily depend on lots of kernel help here. |
@@ -3678,12 +3124,6 @@ postcore_initcall(tty_class_init); | |||
3678 | /* 3/2004 jmc: why do these devices exist? */ | 3124 | /* 3/2004 jmc: why do these devices exist? */ |
3679 | 3125 | ||
3680 | static struct cdev tty_cdev, console_cdev; | 3126 | static struct cdev tty_cdev, console_cdev; |
3681 | #ifdef CONFIG_UNIX98_PTYS | ||
3682 | static struct cdev ptmx_cdev; | ||
3683 | #endif | ||
3684 | #ifdef CONFIG_VT | ||
3685 | static struct cdev vc0_cdev; | ||
3686 | #endif | ||
3687 | 3127 | ||
3688 | /* | 3128 | /* |
3689 | * Ok, now we can initialize the rest of the tty devices and can count | 3129 | * Ok, now we can initialize the rest of the tty devices and can count |
@@ -3695,32 +3135,18 @@ static int __init tty_init(void) | |||
3695 | if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || | 3135 | if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || |
3696 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) | 3136 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) |
3697 | panic("Couldn't register /dev/tty driver\n"); | 3137 | panic("Couldn't register /dev/tty driver\n"); |
3698 | device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, | 3138 | device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, |
3699 | "tty"); | 3139 | "tty"); |
3700 | 3140 | ||
3701 | cdev_init(&console_cdev, &console_fops); | 3141 | cdev_init(&console_cdev, &console_fops); |
3702 | if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || | 3142 | if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || |
3703 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) | 3143 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) |
3704 | panic("Couldn't register /dev/console driver\n"); | 3144 | panic("Couldn't register /dev/console driver\n"); |
3705 | device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, | 3145 | device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, |
3706 | "console"); | 3146 | "console"); |
3707 | 3147 | ||
3708 | #ifdef CONFIG_UNIX98_PTYS | ||
3709 | cdev_init(&ptmx_cdev, &ptmx_fops); | ||
3710 | if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || | ||
3711 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) | ||
3712 | panic("Couldn't register /dev/ptmx driver\n"); | ||
3713 | device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); | ||
3714 | #endif | ||
3715 | |||
3716 | #ifdef CONFIG_VT | 3148 | #ifdef CONFIG_VT |
3717 | cdev_init(&vc0_cdev, &console_fops); | 3149 | vty_init(&console_fops); |
3718 | if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || | ||
3719 | register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) | ||
3720 | panic("Couldn't register /dev/tty0 driver\n"); | ||
3721 | device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); | ||
3722 | |||
3723 | vty_init(); | ||
3724 | #endif | 3150 | #endif |
3725 | return 0; | 3151 | return 0; |
3726 | } | 3152 | } |
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index bf34e4597421..a408c8e487ec 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -40,6 +40,15 @@ | |||
40 | #define TERMIOS_OLD 8 | 40 | #define TERMIOS_OLD 8 |
41 | 41 | ||
42 | 42 | ||
43 | /** | ||
44 | * tty_chars_in_buffer - characters pending | ||
45 | * @tty: terminal | ||
46 | * | ||
47 | * Return the number of bytes of data in the device private | ||
48 | * output queue. If no private method is supplied there is assumed | ||
49 | * to be no queue on the device. | ||
50 | */ | ||
51 | |||
43 | int tty_chars_in_buffer(struct tty_struct *tty) | 52 | int tty_chars_in_buffer(struct tty_struct *tty) |
44 | { | 53 | { |
45 | if (tty->ops->chars_in_buffer) | 54 | if (tty->ops->chars_in_buffer) |
@@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty) | |||
47 | else | 56 | else |
48 | return 0; | 57 | return 0; |
49 | } | 58 | } |
50 | |||
51 | EXPORT_SYMBOL(tty_chars_in_buffer); | 59 | EXPORT_SYMBOL(tty_chars_in_buffer); |
52 | 60 | ||
61 | /** | ||
62 | * tty_write_room - write queue space | ||
63 | * @tty: terminal | ||
64 | * | ||
65 | * Return the number of bytes that can be queued to this device | ||
66 | * at the present time. The result should be treated as a guarantee | ||
67 | * and the driver cannot offer a value it later shrinks by more than | ||
68 | * the number of bytes written. If no method is provided 2K is always | ||
69 | * returned and data may be lost as there will be no flow control. | ||
70 | */ | ||
71 | |||
53 | int tty_write_room(struct tty_struct *tty) | 72 | int tty_write_room(struct tty_struct *tty) |
54 | { | 73 | { |
55 | if (tty->ops->write_room) | 74 | if (tty->ops->write_room) |
56 | return tty->ops->write_room(tty); | 75 | return tty->ops->write_room(tty); |
57 | return 2048; | 76 | return 2048; |
58 | } | 77 | } |
59 | |||
60 | EXPORT_SYMBOL(tty_write_room); | 78 | EXPORT_SYMBOL(tty_write_room); |
61 | 79 | ||
80 | /** | ||
81 | * tty_driver_flush_buffer - discard internal buffer | ||
82 | * @tty: terminal | ||
83 | * | ||
84 | * Discard the internal output buffer for this device. If no method | ||
85 | * is provided then either the buffer cannot be hardware flushed or | ||
86 | * there is no buffer driver side. | ||
87 | */ | ||
62 | void tty_driver_flush_buffer(struct tty_struct *tty) | 88 | void tty_driver_flush_buffer(struct tty_struct *tty) |
63 | { | 89 | { |
64 | if (tty->ops->flush_buffer) | 90 | if (tty->ops->flush_buffer) |
65 | tty->ops->flush_buffer(tty); | 91 | tty->ops->flush_buffer(tty); |
66 | } | 92 | } |
67 | |||
68 | EXPORT_SYMBOL(tty_driver_flush_buffer); | 93 | EXPORT_SYMBOL(tty_driver_flush_buffer); |
69 | 94 | ||
95 | /** | ||
96 | * tty_throttle - flow control | ||
97 | * @tty: terminal | ||
98 | * | ||
99 | * Indicate that a tty should stop transmitting data down the stack. | ||
100 | */ | ||
101 | |||
70 | void tty_throttle(struct tty_struct *tty) | 102 | void tty_throttle(struct tty_struct *tty) |
71 | { | 103 | { |
72 | /* check TTY_THROTTLED first so it indicates our state */ | 104 | /* check TTY_THROTTLED first so it indicates our state */ |
@@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty) | |||
76 | } | 108 | } |
77 | EXPORT_SYMBOL(tty_throttle); | 109 | EXPORT_SYMBOL(tty_throttle); |
78 | 110 | ||
111 | /** | ||
112 | * tty_unthrottle - flow control | ||
113 | * @tty: terminal | ||
114 | * | ||
115 | * Indicate that a tty may continue transmitting data down the stack. | ||
116 | */ | ||
117 | |||
79 | void tty_unthrottle(struct tty_struct *tty) | 118 | void tty_unthrottle(struct tty_struct *tty) |
80 | { | 119 | { |
81 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && | 120 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && |
@@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout) | |||
112 | } | 151 | } |
113 | EXPORT_SYMBOL(tty_wait_until_sent); | 152 | EXPORT_SYMBOL(tty_wait_until_sent); |
114 | 153 | ||
154 | |||
155 | /* | ||
156 | * Termios Helper Methods | ||
157 | */ | ||
158 | |||
115 | static void unset_locked_termios(struct ktermios *termios, | 159 | static void unset_locked_termios(struct ktermios *termios, |
116 | struct ktermios *old, | 160 | struct ktermios *old, |
117 | struct ktermios *locked) | 161 | struct ktermios *locked) |
@@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, | |||
346 | } | 390 | } |
347 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); | 391 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); |
348 | 392 | ||
393 | /** | ||
394 | * tty_encode_baud_rate - set baud rate of the tty | ||
395 | * @ibaud: input baud rate | ||
396 | * @obad: output baud rate | ||
397 | * | ||
398 | * Update the current termios data for the tty with the new speed | ||
399 | * settings. The caller must hold the termios_mutex for the tty in | ||
400 | * question. | ||
401 | */ | ||
402 | |||
349 | void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) | 403 | void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) |
350 | { | 404 | { |
351 | tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); | 405 | tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); |
@@ -430,12 +484,11 @@ EXPORT_SYMBOL(tty_termios_hw_change); | |||
430 | * is a bit of layering violation here with n_tty in terms of the | 484 | * is a bit of layering violation here with n_tty in terms of the |
431 | * internal knowledge of this function. | 485 | * internal knowledge of this function. |
432 | * | 486 | * |
433 | * Locking: termios_sem | 487 | * Locking: termios_mutex |
434 | */ | 488 | */ |
435 | 489 | ||
436 | static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | 490 | static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) |
437 | { | 491 | { |
438 | int canon_change; | ||
439 | struct ktermios old_termios; | 492 | struct ktermios old_termios; |
440 | struct tty_ldisc *ld; | 493 | struct tty_ldisc *ld; |
441 | unsigned long flags; | 494 | unsigned long flags; |
@@ -451,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
451 | old_termios = *tty->termios; | 504 | old_termios = *tty->termios; |
452 | *tty->termios = *new_termios; | 505 | *tty->termios = *new_termios; |
453 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); | 506 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); |
454 | canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; | ||
455 | if (canon_change) { | ||
456 | memset(&tty->read_flags, 0, sizeof tty->read_flags); | ||
457 | tty->canon_head = tty->read_tail; | ||
458 | tty->canon_data = 0; | ||
459 | tty->erasing = 0; | ||
460 | } | ||
461 | |||
462 | /* This bit should be in the ldisc code */ | ||
463 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | ||
464 | /* Get characters left over from canonical mode. */ | ||
465 | wake_up_interruptible(&tty->read_wait); | ||
466 | 507 | ||
467 | /* See if packet mode change of state. */ | 508 | /* See if packet mode change of state. */ |
468 | if (tty->link && tty->link->packet) { | 509 | if (tty->link && tty->link->packet) { |
@@ -508,7 +549,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
508 | * functions before using change_termios to do the actual changes. | 549 | * functions before using change_termios to do the actual changes. |
509 | * | 550 | * |
510 | * Locking: | 551 | * Locking: |
511 | * Called functions take ldisc and termios_sem locks | 552 | * Called functions take ldisc and termios_mutex locks |
512 | */ | 553 | */ |
513 | 554 | ||
514 | static int set_termios(struct tty_struct *tty, void __user *arg, int opt) | 555 | static int set_termios(struct tty_struct *tty, void __user *arg, int opt) |
@@ -579,25 +620,51 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio) | |||
579 | return 0; | 620 | return 0; |
580 | } | 621 | } |
581 | 622 | ||
582 | static unsigned long inq_canon(struct tty_struct *tty) | 623 | |
624 | #ifdef TCGETX | ||
625 | |||
626 | /** | ||
627 | * set_termiox - set termiox fields if possible | ||
628 | * @tty: terminal | ||
629 | * @arg: termiox structure from user | ||
630 | * @opt: option flags for ioctl type | ||
631 | * | ||
632 | * Implement the device calling points for the SYS5 termiox ioctl | ||
633 | * interface in Linux | ||
634 | */ | ||
635 | |||
636 | static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) | ||
583 | { | 637 | { |
584 | int nr, head, tail; | 638 | struct termiox tnew; |
639 | struct tty_ldisc *ld; | ||
585 | 640 | ||
586 | if (!tty->canon_data || !tty->read_buf) | 641 | if (tty->termiox == NULL) |
587 | return 0; | 642 | return -EINVAL; |
588 | head = tty->canon_head; | 643 | if (copy_from_user(&tnew, arg, sizeof(struct termiox))) |
589 | tail = tty->read_tail; | 644 | return -EFAULT; |
590 | nr = (head - tail) & (N_TTY_BUF_SIZE-1); | 645 | |
591 | /* Skip EOF-chars.. */ | 646 | ld = tty_ldisc_ref(tty); |
592 | while (head != tail) { | 647 | if (ld != NULL) { |
593 | if (test_bit(tail, tty->read_flags) && | 648 | if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) |
594 | tty->read_buf[tail] == __DISABLED_CHAR) | 649 | ld->ops->flush_buffer(tty); |
595 | nr--; | 650 | tty_ldisc_deref(ld); |
596 | tail = (tail+1) & (N_TTY_BUF_SIZE-1); | ||
597 | } | 651 | } |
598 | return nr; | 652 | if (opt & TERMIOS_WAIT) { |
653 | tty_wait_until_sent(tty, 0); | ||
654 | if (signal_pending(current)) | ||
655 | return -EINTR; | ||
656 | } | ||
657 | |||
658 | mutex_lock(&tty->termios_mutex); | ||
659 | if (tty->ops->set_termiox) | ||
660 | tty->ops->set_termiox(tty, &tnew); | ||
661 | mutex_unlock(&tty->termios_mutex); | ||
662 | return 0; | ||
599 | } | 663 | } |
600 | 664 | ||
665 | #endif | ||
666 | |||
667 | |||
601 | #ifdef TIOCGETP | 668 | #ifdef TIOCGETP |
602 | /* | 669 | /* |
603 | * These are deprecated, but there is limited support.. | 670 | * These are deprecated, but there is limited support.. |
@@ -671,7 +738,7 @@ static void set_sgflags(struct ktermios *termios, int flags) | |||
671 | * Updates a terminal from the legacy BSD style terminal information | 738 | * Updates a terminal from the legacy BSD style terminal information |
672 | * structure. | 739 | * structure. |
673 | * | 740 | * |
674 | * Locking: termios_sem | 741 | * Locking: termios_mutex |
675 | */ | 742 | */ |
676 | 743 | ||
677 | static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) | 744 | static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) |
@@ -849,6 +916,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
849 | { | 916 | { |
850 | struct tty_struct *real_tty; | 917 | struct tty_struct *real_tty; |
851 | void __user *p = (void __user *)arg; | 918 | void __user *p = (void __user *)arg; |
919 | int ret = 0; | ||
852 | 920 | ||
853 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 921 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
854 | tty->driver->subtype == PTY_TYPE_MASTER) | 922 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -884,18 +952,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
884 | return set_termios(real_tty, p, TERMIOS_OLD); | 952 | return set_termios(real_tty, p, TERMIOS_OLD); |
885 | #ifndef TCGETS2 | 953 | #ifndef TCGETS2 |
886 | case TCGETS: | 954 | case TCGETS: |
955 | mutex_lock(&real_tty->termios_mutex); | ||
887 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) | 956 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) |
888 | return -EFAULT; | 957 | ret = -EFAULT; |
889 | return 0; | 958 | mutex_unlock(&real_tty->termios_mutex); |
959 | return ret; | ||
890 | #else | 960 | #else |
891 | case TCGETS: | 961 | case TCGETS: |
962 | mutex_lock(&real_tty->termios_mutex); | ||
892 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) | 963 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) |
893 | return -EFAULT; | 964 | ret = -EFAULT; |
894 | return 0; | 965 | mutex_unlock(&real_tty->termios_mutex); |
966 | return ret; | ||
895 | case TCGETS2: | 967 | case TCGETS2: |
968 | mutex_lock(&real_tty->termios_mutex); | ||
896 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) | 969 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) |
897 | return -EFAULT; | 970 | ret = -EFAULT; |
898 | return 0; | 971 | mutex_unlock(&real_tty->termios_mutex); |
972 | return ret; | ||
899 | case TCSETSF2: | 973 | case TCSETSF2: |
900 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); | 974 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); |
901 | case TCSETSW2: | 975 | case TCSETSW2: |
@@ -913,34 +987,59 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
913 | return set_termios(real_tty, p, TERMIOS_TERMIO); | 987 | return set_termios(real_tty, p, TERMIOS_TERMIO); |
914 | #ifndef TCGETS2 | 988 | #ifndef TCGETS2 |
915 | case TIOCGLCKTRMIOS: | 989 | case TIOCGLCKTRMIOS: |
990 | mutex_lock(&real_tty->termios_mutex); | ||
916 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) | 991 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) |
917 | return -EFAULT; | 992 | ret = -EFAULT; |
918 | return 0; | 993 | mutex_unlock(&real_tty->termios_mutex); |
994 | return ret; | ||
919 | case TIOCSLCKTRMIOS: | 995 | case TIOCSLCKTRMIOS: |
920 | if (!capable(CAP_SYS_ADMIN)) | 996 | if (!capable(CAP_SYS_ADMIN)) |
921 | return -EPERM; | 997 | return -EPERM; |
998 | mutex_lock(&real_tty->termios_mutex); | ||
922 | if (user_termios_to_kernel_termios(real_tty->termios_locked, | 999 | if (user_termios_to_kernel_termios(real_tty->termios_locked, |
923 | (struct termios __user *) arg)) | 1000 | (struct termios __user *) arg)) |
924 | return -EFAULT; | 1001 | ret = -EFAULT; |
925 | return 0; | 1002 | mutex_unlock(&real_tty->termios_mutex); |
1003 | return ret; | ||
926 | #else | 1004 | #else |
927 | case TIOCGLCKTRMIOS: | 1005 | case TIOCGLCKTRMIOS: |
1006 | mutex_lock(&real_tty->termios_mutex); | ||
928 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) | 1007 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) |
929 | return -EFAULT; | 1008 | ret = -EFAULT; |
930 | return 0; | 1009 | mutex_unlock(&real_tty->termios_mutex); |
1010 | return ret; | ||
931 | case TIOCSLCKTRMIOS: | 1011 | case TIOCSLCKTRMIOS: |
932 | if (!capable(CAP_SYS_ADMIN)) | 1012 | if (!capable(CAP_SYS_ADMIN)) |
933 | return -EPERM; | 1013 | ret = -EPERM; |
1014 | mutex_lock(&real_tty->termios_mutex); | ||
934 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, | 1015 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, |
935 | (struct termios __user *) arg)) | 1016 | (struct termios __user *) arg)) |
936 | return -EFAULT; | 1017 | ret = -EFAULT; |
937 | return 0; | 1018 | mutex_unlock(&real_tty->termios_mutex); |
1019 | return ret; | ||
938 | #endif | 1020 | #endif |
1021 | #ifdef TCGETX | ||
1022 | case TCGETX: | ||
1023 | if (real_tty->termiox == NULL) | ||
1024 | return -EINVAL; | ||
1025 | mutex_lock(&real_tty->termios_mutex); | ||
1026 | if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) | ||
1027 | ret = -EFAULT; | ||
1028 | mutex_unlock(&real_tty->termios_mutex); | ||
1029 | return ret; | ||
1030 | case TCSETX: | ||
1031 | return set_termiox(real_tty, p, 0); | ||
1032 | case TCSETXW: | ||
1033 | return set_termiox(real_tty, p, TERMIOS_WAIT); | ||
1034 | case TCSETXF: | ||
1035 | return set_termiox(real_tty, p, TERMIOS_FLUSH); | ||
1036 | #endif | ||
939 | case TIOCGSOFTCAR: | 1037 | case TIOCGSOFTCAR: |
940 | /* FIXME: for correctness we may need to take the termios | 1038 | mutex_lock(&real_tty->termios_mutex); |
941 | lock here - review */ | 1039 | ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, |
942 | return put_user(C_CLOCAL(real_tty) ? 1 : 0, | ||
943 | (int __user *)arg); | 1040 | (int __user *)arg); |
1041 | mutex_unlock(&real_tty->termios_mutex); | ||
1042 | return ret; | ||
944 | case TIOCSSOFTCAR: | 1043 | case TIOCSSOFTCAR: |
945 | if (get_user(arg, (unsigned int __user *) arg)) | 1044 | if (get_user(arg, (unsigned int __user *) arg)) |
946 | return -EFAULT; | 1045 | return -EFAULT; |
@@ -980,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) | |||
980 | } | 1079 | } |
981 | EXPORT_SYMBOL_GPL(tty_perform_flush); | 1080 | EXPORT_SYMBOL_GPL(tty_perform_flush); |
982 | 1081 | ||
983 | int n_tty_ioctl(struct tty_struct *tty, struct file *file, | 1082 | int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, |
984 | unsigned int cmd, unsigned long arg) | 1083 | unsigned int cmd, unsigned long arg) |
985 | { | 1084 | { |
986 | unsigned long flags; | 1085 | unsigned long flags; |
@@ -1018,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
1018 | return 0; | 1117 | return 0; |
1019 | case TCFLSH: | 1118 | case TCFLSH: |
1020 | return tty_perform_flush(tty, arg); | 1119 | return tty_perform_flush(tty, arg); |
1021 | case TIOCOUTQ: | ||
1022 | return put_user(tty_chars_in_buffer(tty), (int __user *) arg); | ||
1023 | case TIOCINQ: | ||
1024 | retval = tty->read_cnt; | ||
1025 | if (L_ICANON(tty)) | ||
1026 | retval = inq_canon(tty); | ||
1027 | return put_user(retval, (unsigned int __user *) arg); | ||
1028 | case TIOCPKT: | 1120 | case TIOCPKT: |
1029 | { | 1121 | { |
1030 | int pktmode; | 1122 | int pktmode; |
@@ -1050,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
1050 | return tty_mode_ioctl(tty, file, cmd, arg); | 1142 | return tty_mode_ioctl(tty, file, cmd, arg); |
1051 | } | 1143 | } |
1052 | } | 1144 | } |
1053 | EXPORT_SYMBOL(n_tty_ioctl); | 1145 | EXPORT_SYMBOL(n_tty_ioctl_helper); |
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c new file mode 100644 index 000000000000..553b0e9d8d17 --- /dev/null +++ b/drivers/char/tty_port.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Tty port functions | ||
3 | */ | ||
4 | |||
5 | #include <linux/types.h> | ||
6 | #include <linux/errno.h> | ||
7 | #include <linux/tty.h> | ||
8 | #include <linux/tty_driver.h> | ||
9 | #include <linux/tty_flip.h> | ||
10 | #include <linux/timer.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/wait.h> | ||
16 | #include <linux/bitops.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/module.h> | ||
19 | |||
20 | void tty_port_init(struct tty_port *port) | ||
21 | { | ||
22 | memset(port, 0, sizeof(*port)); | ||
23 | init_waitqueue_head(&port->open_wait); | ||
24 | init_waitqueue_head(&port->close_wait); | ||
25 | mutex_init(&port->mutex); | ||
26 | spin_lock_init(&port->lock); | ||
27 | port->close_delay = (50 * HZ) / 100; | ||
28 | port->closing_wait = (3000 * HZ) / 100; | ||
29 | } | ||
30 | EXPORT_SYMBOL(tty_port_init); | ||
31 | |||
32 | int tty_port_alloc_xmit_buf(struct tty_port *port) | ||
33 | { | ||
34 | /* We may sleep in get_zeroed_page() */ | ||
35 | mutex_lock(&port->mutex); | ||
36 | if (port->xmit_buf == NULL) | ||
37 | port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); | ||
38 | mutex_unlock(&port->mutex); | ||
39 | if (port->xmit_buf == NULL) | ||
40 | return -ENOMEM; | ||
41 | return 0; | ||
42 | } | ||
43 | EXPORT_SYMBOL(tty_port_alloc_xmit_buf); | ||
44 | |||
45 | void tty_port_free_xmit_buf(struct tty_port *port) | ||
46 | { | ||
47 | mutex_lock(&port->mutex); | ||
48 | if (port->xmit_buf != NULL) { | ||
49 | free_page((unsigned long)port->xmit_buf); | ||
50 | port->xmit_buf = NULL; | ||
51 | } | ||
52 | mutex_unlock(&port->mutex); | ||
53 | } | ||
54 | EXPORT_SYMBOL(tty_port_free_xmit_buf); | ||
55 | |||
56 | |||
57 | /** | ||
58 | * tty_port_tty_get - get a tty reference | ||
59 | * @port: tty port | ||
60 | * | ||
61 | * Return a refcount protected tty instance or NULL if the port is not | ||
62 | * associated with a tty (eg due to close or hangup) | ||
63 | */ | ||
64 | |||
65 | struct tty_struct *tty_port_tty_get(struct tty_port *port) | ||
66 | { | ||
67 | unsigned long flags; | ||
68 | struct tty_struct *tty; | ||
69 | |||
70 | spin_lock_irqsave(&port->lock, flags); | ||
71 | tty = tty_kref_get(port->tty); | ||
72 | spin_unlock_irqrestore(&port->lock, flags); | ||
73 | return tty; | ||
74 | } | ||
75 | EXPORT_SYMBOL(tty_port_tty_get); | ||
76 | |||
77 | /** | ||
78 | * tty_port_tty_set - set the tty of a port | ||
79 | * @port: tty port | ||
80 | * @tty: the tty | ||
81 | * | ||
82 | * Associate the port and tty pair. Manages any internal refcounts. | ||
83 | * Pass NULL to deassociate a port | ||
84 | */ | ||
85 | |||
86 | void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) | ||
87 | { | ||
88 | unsigned long flags; | ||
89 | |||
90 | spin_lock_irqsave(&port->lock, flags); | ||
91 | if (port->tty) | ||
92 | tty_kref_put(port->tty); | ||
93 | port->tty = tty; | ||
94 | spin_unlock_irqrestore(&port->lock, flags); | ||
95 | } | ||
96 | EXPORT_SYMBOL(tty_port_tty_set); | ||
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 60359c360912..57029fefd64a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -100,10 +100,10 @@ | |||
100 | #include <linux/font.h> | 100 | #include <linux/font.h> |
101 | #include <linux/bitops.h> | 101 | #include <linux/bitops.h> |
102 | #include <linux/notifier.h> | 102 | #include <linux/notifier.h> |
103 | 103 | #include <linux/device.h> | |
104 | #include <asm/io.h> | 104 | #include <linux/io.h> |
105 | #include <asm/system.h> | 105 | #include <asm/system.h> |
106 | #include <asm/uaccess.h> | 106 | #include <linux/uaccess.h> |
107 | 107 | ||
108 | #define MAX_NR_CON_DRIVER 16 | 108 | #define MAX_NR_CON_DRIVER 16 |
109 | 109 | ||
@@ -2136,27 +2136,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2136 | release_console_sem(); | 2136 | release_console_sem(); |
2137 | return 0; | 2137 | return 0; |
2138 | } | 2138 | } |
2139 | release_console_sem(); | ||
2140 | |||
2141 | orig_buf = buf; | 2139 | orig_buf = buf; |
2142 | orig_count = count; | 2140 | orig_count = count; |
2143 | 2141 | ||
2144 | /* At this point 'buf' is guaranteed to be a kernel buffer | ||
2145 | * and therefore no access to userspace (and therefore sleeping) | ||
2146 | * will be needed. The con_buf_mtx serializes all tty based | ||
2147 | * console rendering and vcs write/read operations. We hold | ||
2148 | * the console spinlock during the entire write. | ||
2149 | */ | ||
2150 | |||
2151 | acquire_console_sem(); | ||
2152 | |||
2153 | vc = tty->driver_data; | ||
2154 | if (vc == NULL) { | ||
2155 | printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n"); | ||
2156 | release_console_sem(); | ||
2157 | goto out; | ||
2158 | } | ||
2159 | |||
2160 | himask = vc->vc_hi_font_mask; | 2142 | himask = vc->vc_hi_font_mask; |
2161 | charmask = himask ? 0x1ff : 0xff; | 2143 | charmask = himask ? 0x1ff : 0xff; |
2162 | 2144 | ||
@@ -2370,8 +2352,6 @@ rescan_last_byte: | |||
2370 | FLUSH | 2352 | FLUSH |
2371 | console_conditional_schedule(); | 2353 | console_conditional_schedule(); |
2372 | release_console_sem(); | 2354 | release_console_sem(); |
2373 | |||
2374 | out: | ||
2375 | notify_update(vc); | 2355 | notify_update(vc); |
2376 | return n; | 2356 | return n; |
2377 | #undef FLUSH | 2357 | #undef FLUSH |
@@ -2583,8 +2563,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2583 | int lines; | 2563 | int lines; |
2584 | int ret; | 2564 | int ret; |
2585 | 2565 | ||
2586 | if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE) | ||
2587 | return -EINVAL; | ||
2588 | if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) | 2566 | if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) |
2589 | return -EPERM; | 2567 | return -EPERM; |
2590 | if (get_user(type, p)) | 2568 | if (get_user(type, p)) |
@@ -2778,6 +2756,12 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2778 | ret = vc_allocate(currcons); | 2756 | ret = vc_allocate(currcons); |
2779 | if (ret == 0) { | 2757 | if (ret == 0) { |
2780 | struct vc_data *vc = vc_cons[currcons].d; | 2758 | struct vc_data *vc = vc_cons[currcons].d; |
2759 | |||
2760 | /* Still being freed */ | ||
2761 | if (vc->vc_tty) { | ||
2762 | release_console_sem(); | ||
2763 | return -ERESTARTSYS; | ||
2764 | } | ||
2781 | tty->driver_data = vc; | 2765 | tty->driver_data = vc; |
2782 | vc->vc_tty = tty; | 2766 | vc->vc_tty = tty; |
2783 | 2767 | ||
@@ -2798,34 +2782,20 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2798 | return ret; | 2782 | return ret; |
2799 | } | 2783 | } |
2800 | 2784 | ||
2801 | /* | ||
2802 | * We take tty_mutex in here to prevent another thread from coming in via init_dev | ||
2803 | * and taking a ref against the tty while we're in the process of forgetting | ||
2804 | * about it and cleaning things up. | ||
2805 | * | ||
2806 | * This is because vcs_remove_sysfs() can sleep and will drop the BKL. | ||
2807 | */ | ||
2808 | static void con_close(struct tty_struct *tty, struct file *filp) | 2785 | static void con_close(struct tty_struct *tty, struct file *filp) |
2809 | { | 2786 | { |
2810 | mutex_lock(&tty_mutex); | 2787 | /* Nothing to do - we defer to shutdown */ |
2811 | acquire_console_sem(); | 2788 | } |
2812 | if (tty && tty->count == 1) { | ||
2813 | struct vc_data *vc = tty->driver_data; | ||
2814 | 2789 | ||
2815 | if (vc) | 2790 | static void con_shutdown(struct tty_struct *tty) |
2816 | vc->vc_tty = NULL; | 2791 | { |
2817 | tty->driver_data = NULL; | 2792 | struct vc_data *vc = tty->driver_data; |
2818 | vcs_remove_sysfs(tty); | 2793 | BUG_ON(vc == NULL); |
2819 | release_console_sem(); | 2794 | acquire_console_sem(); |
2820 | mutex_unlock(&tty_mutex); | 2795 | vc->vc_tty = NULL; |
2821 | /* | 2796 | vcs_remove_sysfs(tty); |
2822 | * tty_mutex is released, but we still hold BKL, so there is | ||
2823 | * still exclusion against init_dev() | ||
2824 | */ | ||
2825 | return; | ||
2826 | } | ||
2827 | release_console_sem(); | 2797 | release_console_sem(); |
2828 | mutex_unlock(&tty_mutex); | 2798 | tty_shutdown(tty); |
2829 | } | 2799 | } |
2830 | 2800 | ||
2831 | static int default_italic_color = 2; // green (ASCII) | 2801 | static int default_italic_color = 2; // green (ASCII) |
@@ -2950,10 +2920,19 @@ static const struct tty_operations con_ops = { | |||
2950 | .throttle = con_throttle, | 2920 | .throttle = con_throttle, |
2951 | .unthrottle = con_unthrottle, | 2921 | .unthrottle = con_unthrottle, |
2952 | .resize = vt_resize, | 2922 | .resize = vt_resize, |
2923 | .shutdown = con_shutdown | ||
2953 | }; | 2924 | }; |
2954 | 2925 | ||
2955 | int __init vty_init(void) | 2926 | static struct cdev vc0_cdev; |
2927 | |||
2928 | int __init vty_init(const struct file_operations *console_fops) | ||
2956 | { | 2929 | { |
2930 | cdev_init(&vc0_cdev, console_fops); | ||
2931 | if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || | ||
2932 | register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) | ||
2933 | panic("Couldn't register /dev/tty0 driver\n"); | ||
2934 | device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); | ||
2935 | |||
2957 | vcs_init(); | 2936 | vcs_init(); |
2958 | 2937 | ||
2959 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); | 2938 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); |
@@ -2972,7 +2951,6 @@ int __init vty_init(void) | |||
2972 | tty_set_operations(console_driver, &con_ops); | 2951 | tty_set_operations(console_driver, &con_ops); |
2973 | if (tty_register_driver(console_driver)) | 2952 | if (tty_register_driver(console_driver)) |
2974 | panic("Couldn't register console driver\n"); | 2953 | panic("Couldn't register console driver\n"); |
2975 | |||
2976 | kbd_init(); | 2954 | kbd_init(); |
2977 | console_map_init(); | 2955 | console_map_init(); |
2978 | #ifdef CONFIG_PROM_CONSOLE | 2956 | #ifdef CONFIG_PROM_CONSOLE |
@@ -3466,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last) | |||
3466 | if (retval) | 3444 | if (retval) |
3467 | goto err; | 3445 | goto err; |
3468 | 3446 | ||
3469 | con_driver->dev = device_create_drvdata(vtconsole_class, NULL, | 3447 | con_driver->dev = device_create(vtconsole_class, NULL, |
3470 | MKDEV(0, con_driver->node), | 3448 | MKDEV(0, con_driver->node), |
3471 | NULL, "vtcon%i", | 3449 | NULL, "vtcon%i", |
3472 | con_driver->node); | 3450 | con_driver->node); |
@@ -3577,7 +3555,7 @@ static int __init vtconsole_class_init(void) | |||
3577 | struct con_driver *con = ®istered_con_driver[i]; | 3555 | struct con_driver *con = ®istered_con_driver[i]; |
3578 | 3556 | ||
3579 | if (con->con && !con->dev) { | 3557 | if (con->con && !con->dev) { |
3580 | con->dev = device_create_drvdata(vtconsole_class, NULL, | 3558 | con->dev = device_create(vtconsole_class, NULL, |
3581 | MKDEV(0, con->node), | 3559 | MKDEV(0, con->node), |
3582 | NULL, "vtcon%i", | 3560 | NULL, "vtcon%i", |
3583 | con->node); | 3561 | con->node); |
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index c904e9ad4a71..8944ce508e2f 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c | |||
@@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
395 | 395 | ||
396 | kbd = kbd_table + console; | 396 | kbd = kbd_table + console; |
397 | switch (cmd) { | 397 | switch (cmd) { |
398 | case TIOCLINUX: | ||
399 | return tioclinux(tty, arg); | ||
398 | case KIOCSOUND: | 400 | case KIOCSOUND: |
399 | if (!perm) | 401 | if (!perm) |
400 | goto eperm; | 402 | goto eperm; |
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 871b0cbca5e4..798d7f3e42ef 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, | |||
1231 | int error = 0; | 1231 | int error = 0; |
1232 | switch (cmd) { | 1232 | switch (cmd) { |
1233 | default: | 1233 | default: |
1234 | error = n_tty_ioctl (tty, file, cmd, arg); | 1234 | error = n_tty_ioctl_helper(tty, file, cmd, arg); |
1235 | break; | 1235 | break; |
1236 | } | 1236 | } |
1237 | return error; | 1237 | return error; |
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 5e89fa177816..07052ed2a0c5 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c | |||
@@ -571,6 +571,7 @@ gigaset_tty_close(struct tty_struct *tty) | |||
571 | } | 571 | } |
572 | 572 | ||
573 | /* prevent other callers from entering ldisc methods */ | 573 | /* prevent other callers from entering ldisc methods */ |
574 | /* FIXME: should use the tty state flags */ | ||
574 | tty->disc_data = NULL; | 575 | tty->disc_data = NULL; |
575 | 576 | ||
576 | if (!cs->hw.ser) | 577 | if (!cs->hw.ser) |
@@ -642,10 +643,11 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
642 | return -ENXIO; | 643 | return -ENXIO; |
643 | 644 | ||
644 | switch (cmd) { | 645 | switch (cmd) { |
645 | case TCGETS: | 646 | |
646 | case TCGETA: | 647 | case FIONREAD: |
647 | /* pass through to underlying serial device */ | 648 | /* unused, always return zero */ |
648 | rc = n_tty_ioctl(tty, file, cmd, arg); | 649 | val = 0; |
650 | rc = put_user(val, p); | ||
649 | break; | 651 | break; |
650 | 652 | ||
651 | case TCFLSH: | 653 | case TCFLSH: |
@@ -659,20 +661,13 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
659 | flush_send_queue(cs); | 661 | flush_send_queue(cs); |
660 | break; | 662 | break; |
661 | } | 663 | } |
662 | /* flush the serial port's buffer */ | 664 | /* Pass through */ |
663 | rc = n_tty_ioctl(tty, file, cmd, arg); | ||
664 | break; | ||
665 | |||
666 | case FIONREAD: | ||
667 | /* unused, always return zero */ | ||
668 | val = 0; | ||
669 | rc = put_user(val, p); | ||
670 | break; | ||
671 | 665 | ||
672 | default: | 666 | default: |
673 | rc = -ENOIOCTLCMD; | 667 | /* pass through to underlying serial device */ |
668 | rc = n_tty_ioctl_helper(tty, file, cmd, arg); | ||
669 | break; | ||
674 | } | 670 | } |
675 | |||
676 | cs_put(cs); | 671 | cs_put(cs); |
677 | return rc; | 672 | return rc; |
678 | } | 673 | } |
@@ -680,6 +675,8 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
680 | /* | 675 | /* |
681 | * Poll on the tty. | 676 | * Poll on the tty. |
682 | * Unused, always return zero. | 677 | * Unused, always return zero. |
678 | * | ||
679 | * FIXME: should probably return an exception - especially on hangup | ||
683 | */ | 680 | */ |
684 | static unsigned int | 681 | static unsigned int |
685 | gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) | 682 | gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) |
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 5405c30dbb04..08efbe7254ff 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c | |||
@@ -2092,15 +2092,8 @@ static int cafe_pci_probe(struct pci_dev *pdev, | |||
2092 | const struct pci_device_id *id) | 2092 | const struct pci_device_id *id) |
2093 | { | 2093 | { |
2094 | int ret; | 2094 | int ret; |
2095 | u16 classword; | ||
2096 | struct cafe_camera *cam; | 2095 | struct cafe_camera *cam; |
2097 | /* | 2096 | |
2098 | * Make sure we have a camera here - we'll get calls for | ||
2099 | * the other cafe devices as well. | ||
2100 | */ | ||
2101 | pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword); | ||
2102 | if (classword != PCI_CLASS_MULTIMEDIA_VIDEO) | ||
2103 | return -ENODEV; | ||
2104 | /* | 2097 | /* |
2105 | * Start putting together one of our big camera structures. | 2098 | * Start putting together one of our big camera structures. |
2106 | */ | 2099 | */ |
@@ -2288,8 +2281,8 @@ static int cafe_pci_resume(struct pci_dev *pdev) | |||
2288 | 2281 | ||
2289 | 2282 | ||
2290 | static struct pci_device_id cafe_ids[] = { | 2283 | static struct pci_device_id cafe_ids[] = { |
2291 | { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ | 2284 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, |
2292 | { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ | 2285 | PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, |
2293 | { 0, } | 2286 | { 0, } |
2294 | }; | 2287 | }; |
2295 | 2288 | ||
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 0a84f10d719c..9bd7026b0021 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
@@ -327,7 +327,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = { | |||
327 | 327 | ||
328 | { | 328 | { |
329 | .vendor = PCI_VENDOR_ID_MARVELL, | 329 | .vendor = PCI_VENDOR_ID_MARVELL, |
330 | .device = PCI_DEVICE_ID_MARVELL_CAFE_SD, | 330 | .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD, |
331 | .subvendor = PCI_ANY_ID, | 331 | .subvendor = PCI_ANY_ID, |
332 | .subdevice = PCI_ANY_ID, | 332 | .subdevice = PCI_ANY_ID, |
333 | .driver_data = (kernel_ulong_t)&sdhci_cafe, | 333 | .driver_data = (kernel_ulong_t)&sdhci_cafe, |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 95345d051579..b8064bf3aee4 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01 | 2 | * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01 |
3 | * | 3 | * |
4 | * The data sheet for this device can be found at: | ||
5 | * http://www.marvell.com/products/pcconn/88ALP01.jsp | ||
6 | * | ||
4 | * Copyright © 2006 Red Hat, Inc. | 7 | * Copyright © 2006 Red Hat, Inc. |
5 | * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> | 8 | * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> |
6 | */ | 9 | */ |
@@ -842,7 +845,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev) | |||
842 | } | 845 | } |
843 | 846 | ||
844 | static struct pci_device_id cafe_nand_tbl[] = { | 847 | static struct pci_device_id cafe_nand_tbl[] = { |
845 | { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID }, | 848 | { PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND, |
849 | PCI_ANY_ID, PCI_ANY_ID }, | ||
846 | { } | 850 | { } |
847 | }; | 851 | }; |
848 | 852 | ||
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 2ae2ec40015d..21efd99b9294 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig | |||
@@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE | |||
205 | 205 | ||
206 | config PC300 | 206 | config PC300 |
207 | tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" | 207 | tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" |
208 | depends on HDLC && PCI | 208 | depends on HDLC && PCI && BROKEN |
209 | ---help--- | 209 | ---help--- |
210 | Driver for the Cyclades-PC300 synchronous communication boards. | 210 | Driver for the Cyclades-PC300 synchronous communication boards. |
211 | 211 | ||
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 9304c4555079..ed982273fb8b 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * @remark Read the file COPYING | 5 | * @remark Read the file COPYING |
6 | * | 6 | * |
7 | * @author John Levon <levon@movementarian.org> | 7 | * @author John Levon <levon@movementarian.org> |
8 | * @author Barry Kasindorf | ||
8 | * | 9 | * |
9 | * This is the core of the buffer management. Each | 10 | * This is the core of the buffer management. Each |
10 | * CPU buffer is processed and entered into the | 11 | * CPU buffer is processed and entered into the |
@@ -33,7 +34,7 @@ | |||
33 | #include "event_buffer.h" | 34 | #include "event_buffer.h" |
34 | #include "cpu_buffer.h" | 35 | #include "cpu_buffer.h" |
35 | #include "buffer_sync.h" | 36 | #include "buffer_sync.h" |
36 | 37 | ||
37 | static LIST_HEAD(dying_tasks); | 38 | static LIST_HEAD(dying_tasks); |
38 | static LIST_HEAD(dead_tasks); | 39 | static LIST_HEAD(dead_tasks); |
39 | static cpumask_t marked_cpus = CPU_MASK_NONE; | 40 | static cpumask_t marked_cpus = CPU_MASK_NONE; |
@@ -48,10 +49,11 @@ static void process_task_mortuary(void); | |||
48 | * Can be invoked from softirq via RCU callback due to | 49 | * Can be invoked from softirq via RCU callback due to |
49 | * call_rcu() of the task struct, hence the _irqsave. | 50 | * call_rcu() of the task struct, hence the _irqsave. |
50 | */ | 51 | */ |
51 | static int task_free_notify(struct notifier_block * self, unsigned long val, void * data) | 52 | static int |
53 | task_free_notify(struct notifier_block *self, unsigned long val, void *data) | ||
52 | { | 54 | { |
53 | unsigned long flags; | 55 | unsigned long flags; |
54 | struct task_struct * task = data; | 56 | struct task_struct *task = data; |
55 | spin_lock_irqsave(&task_mortuary, flags); | 57 | spin_lock_irqsave(&task_mortuary, flags); |
56 | list_add(&task->tasks, &dying_tasks); | 58 | list_add(&task->tasks, &dying_tasks); |
57 | spin_unlock_irqrestore(&task_mortuary, flags); | 59 | spin_unlock_irqrestore(&task_mortuary, flags); |
@@ -62,13 +64,14 @@ static int task_free_notify(struct notifier_block * self, unsigned long val, voi | |||
62 | /* The task is on its way out. A sync of the buffer means we can catch | 64 | /* The task is on its way out. A sync of the buffer means we can catch |
63 | * any remaining samples for this task. | 65 | * any remaining samples for this task. |
64 | */ | 66 | */ |
65 | static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data) | 67 | static int |
68 | task_exit_notify(struct notifier_block *self, unsigned long val, void *data) | ||
66 | { | 69 | { |
67 | /* To avoid latency problems, we only process the current CPU, | 70 | /* To avoid latency problems, we only process the current CPU, |
68 | * hoping that most samples for the task are on this CPU | 71 | * hoping that most samples for the task are on this CPU |
69 | */ | 72 | */ |
70 | sync_buffer(raw_smp_processor_id()); | 73 | sync_buffer(raw_smp_processor_id()); |
71 | return 0; | 74 | return 0; |
72 | } | 75 | } |
73 | 76 | ||
74 | 77 | ||
@@ -77,11 +80,12 @@ static int task_exit_notify(struct notifier_block * self, unsigned long val, voi | |||
77 | * we don't lose any. This does not have to be exact, it's a QoI issue | 80 | * we don't lose any. This does not have to be exact, it's a QoI issue |
78 | * only. | 81 | * only. |
79 | */ | 82 | */ |
80 | static int munmap_notify(struct notifier_block * self, unsigned long val, void * data) | 83 | static int |
84 | munmap_notify(struct notifier_block *self, unsigned long val, void *data) | ||
81 | { | 85 | { |
82 | unsigned long addr = (unsigned long)data; | 86 | unsigned long addr = (unsigned long)data; |
83 | struct mm_struct * mm = current->mm; | 87 | struct mm_struct *mm = current->mm; |
84 | struct vm_area_struct * mpnt; | 88 | struct vm_area_struct *mpnt; |
85 | 89 | ||
86 | down_read(&mm->mmap_sem); | 90 | down_read(&mm->mmap_sem); |
87 | 91 | ||
@@ -99,11 +103,12 @@ static int munmap_notify(struct notifier_block * self, unsigned long val, void * | |||
99 | return 0; | 103 | return 0; |
100 | } | 104 | } |
101 | 105 | ||
102 | 106 | ||
103 | /* We need to be told about new modules so we don't attribute to a previously | 107 | /* We need to be told about new modules so we don't attribute to a previously |
104 | * loaded module, or drop the samples on the floor. | 108 | * loaded module, or drop the samples on the floor. |
105 | */ | 109 | */ |
106 | static int module_load_notify(struct notifier_block * self, unsigned long val, void * data) | 110 | static int |
111 | module_load_notify(struct notifier_block *self, unsigned long val, void *data) | ||
107 | { | 112 | { |
108 | #ifdef CONFIG_MODULES | 113 | #ifdef CONFIG_MODULES |
109 | if (val != MODULE_STATE_COMING) | 114 | if (val != MODULE_STATE_COMING) |
@@ -118,7 +123,7 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v | |||
118 | return 0; | 123 | return 0; |
119 | } | 124 | } |
120 | 125 | ||
121 | 126 | ||
122 | static struct notifier_block task_free_nb = { | 127 | static struct notifier_block task_free_nb = { |
123 | .notifier_call = task_free_notify, | 128 | .notifier_call = task_free_notify, |
124 | }; | 129 | }; |
@@ -135,7 +140,7 @@ static struct notifier_block module_load_nb = { | |||
135 | .notifier_call = module_load_notify, | 140 | .notifier_call = module_load_notify, |
136 | }; | 141 | }; |
137 | 142 | ||
138 | 143 | ||
139 | static void end_sync(void) | 144 | static void end_sync(void) |
140 | { | 145 | { |
141 | end_cpu_work(); | 146 | end_cpu_work(); |
@@ -208,14 +213,14 @@ static inline unsigned long fast_get_dcookie(struct path *path) | |||
208 | * not strictly necessary but allows oprofile to associate | 213 | * not strictly necessary but allows oprofile to associate |
209 | * shared-library samples with particular applications | 214 | * shared-library samples with particular applications |
210 | */ | 215 | */ |
211 | static unsigned long get_exec_dcookie(struct mm_struct * mm) | 216 | static unsigned long get_exec_dcookie(struct mm_struct *mm) |
212 | { | 217 | { |
213 | unsigned long cookie = NO_COOKIE; | 218 | unsigned long cookie = NO_COOKIE; |
214 | struct vm_area_struct * vma; | 219 | struct vm_area_struct *vma; |
215 | 220 | ||
216 | if (!mm) | 221 | if (!mm) |
217 | goto out; | 222 | goto out; |
218 | 223 | ||
219 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | 224 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
220 | if (!vma->vm_file) | 225 | if (!vma->vm_file) |
221 | continue; | 226 | continue; |
@@ -235,13 +240,14 @@ out: | |||
235 | * sure to do this lookup before a mm->mmap modification happens so | 240 | * sure to do this lookup before a mm->mmap modification happens so |
236 | * we don't lose track. | 241 | * we don't lose track. |
237 | */ | 242 | */ |
238 | static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset) | 243 | static unsigned long |
244 | lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) | ||
239 | { | 245 | { |
240 | unsigned long cookie = NO_COOKIE; | 246 | unsigned long cookie = NO_COOKIE; |
241 | struct vm_area_struct * vma; | 247 | struct vm_area_struct *vma; |
242 | 248 | ||
243 | for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { | 249 | for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { |
244 | 250 | ||
245 | if (addr < vma->vm_start || addr >= vma->vm_end) | 251 | if (addr < vma->vm_start || addr >= vma->vm_end) |
246 | continue; | 252 | continue; |
247 | 253 | ||
@@ -263,9 +269,20 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o | |||
263 | return cookie; | 269 | return cookie; |
264 | } | 270 | } |
265 | 271 | ||
272 | static void increment_tail(struct oprofile_cpu_buffer *b) | ||
273 | { | ||
274 | unsigned long new_tail = b->tail_pos + 1; | ||
275 | |||
276 | rmb(); /* be sure fifo pointers are synchromized */ | ||
277 | |||
278 | if (new_tail < b->buffer_size) | ||
279 | b->tail_pos = new_tail; | ||
280 | else | ||
281 | b->tail_pos = 0; | ||
282 | } | ||
266 | 283 | ||
267 | static unsigned long last_cookie = INVALID_COOKIE; | 284 | static unsigned long last_cookie = INVALID_COOKIE; |
268 | 285 | ||
269 | static void add_cpu_switch(int i) | 286 | static void add_cpu_switch(int i) |
270 | { | 287 | { |
271 | add_event_entry(ESCAPE_CODE); | 288 | add_event_entry(ESCAPE_CODE); |
@@ -278,16 +295,16 @@ static void add_kernel_ctx_switch(unsigned int in_kernel) | |||
278 | { | 295 | { |
279 | add_event_entry(ESCAPE_CODE); | 296 | add_event_entry(ESCAPE_CODE); |
280 | if (in_kernel) | 297 | if (in_kernel) |
281 | add_event_entry(KERNEL_ENTER_SWITCH_CODE); | 298 | add_event_entry(KERNEL_ENTER_SWITCH_CODE); |
282 | else | 299 | else |
283 | add_event_entry(KERNEL_EXIT_SWITCH_CODE); | 300 | add_event_entry(KERNEL_EXIT_SWITCH_CODE); |
284 | } | 301 | } |
285 | 302 | ||
286 | static void | 303 | static void |
287 | add_user_ctx_switch(struct task_struct const * task, unsigned long cookie) | 304 | add_user_ctx_switch(struct task_struct const *task, unsigned long cookie) |
288 | { | 305 | { |
289 | add_event_entry(ESCAPE_CODE); | 306 | add_event_entry(ESCAPE_CODE); |
290 | add_event_entry(CTX_SWITCH_CODE); | 307 | add_event_entry(CTX_SWITCH_CODE); |
291 | add_event_entry(task->pid); | 308 | add_event_entry(task->pid); |
292 | add_event_entry(cookie); | 309 | add_event_entry(cookie); |
293 | /* Another code for daemon back-compat */ | 310 | /* Another code for daemon back-compat */ |
@@ -296,7 +313,7 @@ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie) | |||
296 | add_event_entry(task->tgid); | 313 | add_event_entry(task->tgid); |
297 | } | 314 | } |
298 | 315 | ||
299 | 316 | ||
300 | static void add_cookie_switch(unsigned long cookie) | 317 | static void add_cookie_switch(unsigned long cookie) |
301 | { | 318 | { |
302 | add_event_entry(ESCAPE_CODE); | 319 | add_event_entry(ESCAPE_CODE); |
@@ -304,13 +321,78 @@ static void add_cookie_switch(unsigned long cookie) | |||
304 | add_event_entry(cookie); | 321 | add_event_entry(cookie); |
305 | } | 322 | } |
306 | 323 | ||
307 | 324 | ||
308 | static void add_trace_begin(void) | 325 | static void add_trace_begin(void) |
309 | { | 326 | { |
310 | add_event_entry(ESCAPE_CODE); | 327 | add_event_entry(ESCAPE_CODE); |
311 | add_event_entry(TRACE_BEGIN_CODE); | 328 | add_event_entry(TRACE_BEGIN_CODE); |
312 | } | 329 | } |
313 | 330 | ||
331 | #ifdef CONFIG_OPROFILE_IBS | ||
332 | |||
333 | #define IBS_FETCH_CODE_SIZE 2 | ||
334 | #define IBS_OP_CODE_SIZE 5 | ||
335 | #define IBS_EIP(offset) \ | ||
336 | (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip) | ||
337 | #define IBS_EVENT(offset) \ | ||
338 | (((struct op_sample *)&cpu_buf->buffer[(offset)])->event) | ||
339 | |||
340 | /* | ||
341 | * Add IBS fetch and op entries to event buffer | ||
342 | */ | ||
343 | static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, | ||
344 | int in_kernel, struct mm_struct *mm) | ||
345 | { | ||
346 | unsigned long rip; | ||
347 | int i, count; | ||
348 | unsigned long ibs_cookie = 0; | ||
349 | off_t offset; | ||
350 | |||
351 | increment_tail(cpu_buf); /* move to RIP entry */ | ||
352 | |||
353 | rip = IBS_EIP(cpu_buf->tail_pos); | ||
354 | |||
355 | #ifdef __LP64__ | ||
356 | rip += IBS_EVENT(cpu_buf->tail_pos) << 32; | ||
357 | #endif | ||
358 | |||
359 | if (mm) { | ||
360 | ibs_cookie = lookup_dcookie(mm, rip, &offset); | ||
361 | |||
362 | if (ibs_cookie == NO_COOKIE) | ||
363 | offset = rip; | ||
364 | if (ibs_cookie == INVALID_COOKIE) { | ||
365 | atomic_inc(&oprofile_stats.sample_lost_no_mapping); | ||
366 | offset = rip; | ||
367 | } | ||
368 | if (ibs_cookie != last_cookie) { | ||
369 | add_cookie_switch(ibs_cookie); | ||
370 | last_cookie = ibs_cookie; | ||
371 | } | ||
372 | } else | ||
373 | offset = rip; | ||
374 | |||
375 | add_event_entry(ESCAPE_CODE); | ||
376 | add_event_entry(code); | ||
377 | add_event_entry(offset); /* Offset from Dcookie */ | ||
378 | |||
379 | /* we send the Dcookie offset, but send the raw Linear Add also*/ | ||
380 | add_event_entry(IBS_EIP(cpu_buf->tail_pos)); | ||
381 | add_event_entry(IBS_EVENT(cpu_buf->tail_pos)); | ||
382 | |||
383 | if (code == IBS_FETCH_CODE) | ||
384 | count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ | ||
385 | else | ||
386 | count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ | ||
387 | |||
388 | for (i = 0; i < count; i++) { | ||
389 | increment_tail(cpu_buf); | ||
390 | add_event_entry(IBS_EIP(cpu_buf->tail_pos)); | ||
391 | add_event_entry(IBS_EVENT(cpu_buf->tail_pos)); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | #endif | ||
314 | 396 | ||
315 | static void add_sample_entry(unsigned long offset, unsigned long event) | 397 | static void add_sample_entry(unsigned long offset, unsigned long event) |
316 | { | 398 | { |
@@ -319,13 +401,13 @@ static void add_sample_entry(unsigned long offset, unsigned long event) | |||
319 | } | 401 | } |
320 | 402 | ||
321 | 403 | ||
322 | static int add_us_sample(struct mm_struct * mm, struct op_sample * s) | 404 | static int add_us_sample(struct mm_struct *mm, struct op_sample *s) |
323 | { | 405 | { |
324 | unsigned long cookie; | 406 | unsigned long cookie; |
325 | off_t offset; | 407 | off_t offset; |
326 | 408 | ||
327 | cookie = lookup_dcookie(mm, s->eip, &offset); | 409 | cookie = lookup_dcookie(mm, s->eip, &offset); |
328 | 410 | ||
329 | if (cookie == INVALID_COOKIE) { | 411 | if (cookie == INVALID_COOKIE) { |
330 | atomic_inc(&oprofile_stats.sample_lost_no_mapping); | 412 | atomic_inc(&oprofile_stats.sample_lost_no_mapping); |
331 | return 0; | 413 | return 0; |
@@ -341,13 +423,13 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s) | |||
341 | return 1; | 423 | return 1; |
342 | } | 424 | } |
343 | 425 | ||
344 | 426 | ||
345 | /* Add a sample to the global event buffer. If possible the | 427 | /* Add a sample to the global event buffer. If possible the |
346 | * sample is converted into a persistent dentry/offset pair | 428 | * sample is converted into a persistent dentry/offset pair |
347 | * for later lookup from userspace. | 429 | * for later lookup from userspace. |
348 | */ | 430 | */ |
349 | static int | 431 | static int |
350 | add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel) | 432 | add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) |
351 | { | 433 | { |
352 | if (in_kernel) { | 434 | if (in_kernel) { |
353 | add_sample_entry(s->eip, s->event); | 435 | add_sample_entry(s->eip, s->event); |
@@ -359,9 +441,9 @@ add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel) | |||
359 | } | 441 | } |
360 | return 0; | 442 | return 0; |
361 | } | 443 | } |
362 | |||
363 | 444 | ||
364 | static void release_mm(struct mm_struct * mm) | 445 | |
446 | static void release_mm(struct mm_struct *mm) | ||
365 | { | 447 | { |
366 | if (!mm) | 448 | if (!mm) |
367 | return; | 449 | return; |
@@ -370,9 +452,9 @@ static void release_mm(struct mm_struct * mm) | |||
370 | } | 452 | } |
371 | 453 | ||
372 | 454 | ||
373 | static struct mm_struct * take_tasks_mm(struct task_struct * task) | 455 | static struct mm_struct *take_tasks_mm(struct task_struct *task) |
374 | { | 456 | { |
375 | struct mm_struct * mm = get_task_mm(task); | 457 | struct mm_struct *mm = get_task_mm(task); |
376 | if (mm) | 458 | if (mm) |
377 | down_read(&mm->mmap_sem); | 459 | down_read(&mm->mmap_sem); |
378 | return mm; | 460 | return mm; |
@@ -383,10 +465,10 @@ static inline int is_code(unsigned long val) | |||
383 | { | 465 | { |
384 | return val == ESCAPE_CODE; | 466 | return val == ESCAPE_CODE; |
385 | } | 467 | } |
386 | 468 | ||
387 | 469 | ||
388 | /* "acquire" as many cpu buffer slots as we can */ | 470 | /* "acquire" as many cpu buffer slots as we can */ |
389 | static unsigned long get_slots(struct oprofile_cpu_buffer * b) | 471 | static unsigned long get_slots(struct oprofile_cpu_buffer *b) |
390 | { | 472 | { |
391 | unsigned long head = b->head_pos; | 473 | unsigned long head = b->head_pos; |
392 | unsigned long tail = b->tail_pos; | 474 | unsigned long tail = b->tail_pos; |
@@ -412,19 +494,6 @@ static unsigned long get_slots(struct oprofile_cpu_buffer * b) | |||
412 | } | 494 | } |
413 | 495 | ||
414 | 496 | ||
415 | static void increment_tail(struct oprofile_cpu_buffer * b) | ||
416 | { | ||
417 | unsigned long new_tail = b->tail_pos + 1; | ||
418 | |||
419 | rmb(); | ||
420 | |||
421 | if (new_tail < b->buffer_size) | ||
422 | b->tail_pos = new_tail; | ||
423 | else | ||
424 | b->tail_pos = 0; | ||
425 | } | ||
426 | |||
427 | |||
428 | /* Move tasks along towards death. Any tasks on dead_tasks | 497 | /* Move tasks along towards death. Any tasks on dead_tasks |
429 | * will definitely have no remaining references in any | 498 | * will definitely have no remaining references in any |
430 | * CPU buffers at this point, because we use two lists, | 499 | * CPU buffers at this point, because we use two lists, |
@@ -435,8 +504,8 @@ static void process_task_mortuary(void) | |||
435 | { | 504 | { |
436 | unsigned long flags; | 505 | unsigned long flags; |
437 | LIST_HEAD(local_dead_tasks); | 506 | LIST_HEAD(local_dead_tasks); |
438 | struct task_struct * task; | 507 | struct task_struct *task; |
439 | struct task_struct * ttask; | 508 | struct task_struct *ttask; |
440 | 509 | ||
441 | spin_lock_irqsave(&task_mortuary, flags); | 510 | spin_lock_irqsave(&task_mortuary, flags); |
442 | 511 | ||
@@ -493,7 +562,7 @@ void sync_buffer(int cpu) | |||
493 | { | 562 | { |
494 | struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); | 563 | struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); |
495 | struct mm_struct *mm = NULL; | 564 | struct mm_struct *mm = NULL; |
496 | struct task_struct * new; | 565 | struct task_struct *new; |
497 | unsigned long cookie = 0; | 566 | unsigned long cookie = 0; |
498 | int in_kernel = 1; | 567 | int in_kernel = 1; |
499 | unsigned int i; | 568 | unsigned int i; |
@@ -501,7 +570,7 @@ void sync_buffer(int cpu) | |||
501 | unsigned long available; | 570 | unsigned long available; |
502 | 571 | ||
503 | mutex_lock(&buffer_mutex); | 572 | mutex_lock(&buffer_mutex); |
504 | 573 | ||
505 | add_cpu_switch(cpu); | 574 | add_cpu_switch(cpu); |
506 | 575 | ||
507 | /* Remember, only we can modify tail_pos */ | 576 | /* Remember, only we can modify tail_pos */ |
@@ -509,8 +578,8 @@ void sync_buffer(int cpu) | |||
509 | available = get_slots(cpu_buf); | 578 | available = get_slots(cpu_buf); |
510 | 579 | ||
511 | for (i = 0; i < available; ++i) { | 580 | for (i = 0; i < available; ++i) { |
512 | struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos]; | 581 | struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos]; |
513 | 582 | ||
514 | if (is_code(s->eip)) { | 583 | if (is_code(s->eip)) { |
515 | if (s->event <= CPU_IS_KERNEL) { | 584 | if (s->event <= CPU_IS_KERNEL) { |
516 | /* kernel/userspace switch */ | 585 | /* kernel/userspace switch */ |
@@ -521,8 +590,18 @@ void sync_buffer(int cpu) | |||
521 | } else if (s->event == CPU_TRACE_BEGIN) { | 590 | } else if (s->event == CPU_TRACE_BEGIN) { |
522 | state = sb_bt_start; | 591 | state = sb_bt_start; |
523 | add_trace_begin(); | 592 | add_trace_begin(); |
593 | #ifdef CONFIG_OPROFILE_IBS | ||
594 | } else if (s->event == IBS_FETCH_BEGIN) { | ||
595 | state = sb_bt_start; | ||
596 | add_ibs_begin(cpu_buf, | ||
597 | IBS_FETCH_CODE, in_kernel, mm); | ||
598 | } else if (s->event == IBS_OP_BEGIN) { | ||
599 | state = sb_bt_start; | ||
600 | add_ibs_begin(cpu_buf, | ||
601 | IBS_OP_CODE, in_kernel, mm); | ||
602 | #endif | ||
524 | } else { | 603 | } else { |
525 | struct mm_struct * oldmm = mm; | 604 | struct mm_struct *oldmm = mm; |
526 | 605 | ||
527 | /* userspace context switch */ | 606 | /* userspace context switch */ |
528 | new = (struct task_struct *)s->event; | 607 | new = (struct task_struct *)s->event; |
@@ -533,13 +612,11 @@ void sync_buffer(int cpu) | |||
533 | cookie = get_exec_dcookie(mm); | 612 | cookie = get_exec_dcookie(mm); |
534 | add_user_ctx_switch(new, cookie); | 613 | add_user_ctx_switch(new, cookie); |
535 | } | 614 | } |
536 | } else { | 615 | } else if (state >= sb_bt_start && |
537 | if (state >= sb_bt_start && | 616 | !add_sample(mm, s, in_kernel)) { |
538 | !add_sample(mm, s, in_kernel)) { | 617 | if (state == sb_bt_start) { |
539 | if (state == sb_bt_start) { | 618 | state = sb_bt_ignore; |
540 | state = sb_bt_ignore; | 619 | atomic_inc(&oprofile_stats.bt_lost_no_mapping); |
541 | atomic_inc(&oprofile_stats.bt_lost_no_mapping); | ||
542 | } | ||
543 | } | 620 | } |
544 | } | 621 | } |
545 | 622 | ||
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7ba78e6d210e..e1bd5a937f6c 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * @remark Read the file COPYING | 5 | * @remark Read the file COPYING |
6 | * | 6 | * |
7 | * @author John Levon <levon@movementarian.org> | 7 | * @author John Levon <levon@movementarian.org> |
8 | * @author Barry Kasindorf <barry.kasindorf@amd.com> | ||
8 | * | 9 | * |
9 | * Each CPU has a local buffer that stores PC value/event | 10 | * Each CPU has a local buffer that stores PC value/event |
10 | * pairs. We also log context switches when we notice them. | 11 | * pairs. We also log context switches when we notice them. |
@@ -209,7 +210,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, | |||
209 | return 1; | 210 | return 1; |
210 | } | 211 | } |
211 | 212 | ||
212 | static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) | 213 | static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) |
213 | { | 214 | { |
214 | if (nr_available_slots(cpu_buf) < 4) { | 215 | if (nr_available_slots(cpu_buf) < 4) { |
215 | cpu_buf->sample_lost_overflow++; | 216 | cpu_buf->sample_lost_overflow++; |
@@ -254,6 +255,75 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) | |||
254 | oprofile_add_ext_sample(pc, regs, event, is_kernel); | 255 | oprofile_add_ext_sample(pc, regs, event, is_kernel); |
255 | } | 256 | } |
256 | 257 | ||
258 | #ifdef CONFIG_OPROFILE_IBS | ||
259 | |||
260 | #define MAX_IBS_SAMPLE_SIZE 14 | ||
261 | static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, | ||
262 | unsigned long pc, int is_kernel, unsigned int *ibs, int ibs_code) | ||
263 | { | ||
264 | struct task_struct *task; | ||
265 | |||
266 | cpu_buf->sample_received++; | ||
267 | |||
268 | if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { | ||
269 | cpu_buf->sample_lost_overflow++; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | is_kernel = !!is_kernel; | ||
274 | |||
275 | /* notice a switch from user->kernel or vice versa */ | ||
276 | if (cpu_buf->last_is_kernel != is_kernel) { | ||
277 | cpu_buf->last_is_kernel = is_kernel; | ||
278 | add_code(cpu_buf, is_kernel); | ||
279 | } | ||
280 | |||
281 | /* notice a task switch */ | ||
282 | if (!is_kernel) { | ||
283 | task = current; | ||
284 | |||
285 | if (cpu_buf->last_task != task) { | ||
286 | cpu_buf->last_task = task; | ||
287 | add_code(cpu_buf, (unsigned long)task); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | add_code(cpu_buf, ibs_code); | ||
292 | add_sample(cpu_buf, ibs[0], ibs[1]); | ||
293 | add_sample(cpu_buf, ibs[2], ibs[3]); | ||
294 | add_sample(cpu_buf, ibs[4], ibs[5]); | ||
295 | |||
296 | if (ibs_code == IBS_OP_BEGIN) { | ||
297 | add_sample(cpu_buf, ibs[6], ibs[7]); | ||
298 | add_sample(cpu_buf, ibs[8], ibs[9]); | ||
299 | add_sample(cpu_buf, ibs[10], ibs[11]); | ||
300 | } | ||
301 | |||
302 | return 1; | ||
303 | } | ||
304 | |||
305 | void oprofile_add_ibs_sample(struct pt_regs *const regs, | ||
306 | unsigned int * const ibs_sample, u8 code) | ||
307 | { | ||
308 | int is_kernel = !user_mode(regs); | ||
309 | unsigned long pc = profile_pc(regs); | ||
310 | |||
311 | struct oprofile_cpu_buffer *cpu_buf = | ||
312 | &per_cpu(cpu_buffer, smp_processor_id()); | ||
313 | |||
314 | if (!backtrace_depth) { | ||
315 | log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | /* if log_sample() fails we can't backtrace since we lost the source | ||
320 | * of this event */ | ||
321 | if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code)) | ||
322 | oprofile_ops.backtrace(regs, backtrace_depth); | ||
323 | } | ||
324 | |||
325 | #endif | ||
326 | |||
257 | void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) | 327 | void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) |
258 | { | 328 | { |
259 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); | 329 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); |
@@ -296,7 +366,7 @@ static void wq_sync_buffer(struct work_struct *work) | |||
296 | struct oprofile_cpu_buffer * b = | 366 | struct oprofile_cpu_buffer * b = |
297 | container_of(work, struct oprofile_cpu_buffer, work.work); | 367 | container_of(work, struct oprofile_cpu_buffer, work.work); |
298 | if (b->cpu != smp_processor_id()) { | 368 | if (b->cpu != smp_processor_id()) { |
299 | printk("WQ on CPU%d, prefer CPU%d\n", | 369 | printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", |
300 | smp_processor_id(), b->cpu); | 370 | smp_processor_id(), b->cpu); |
301 | } | 371 | } |
302 | sync_buffer(b->cpu); | 372 | sync_buffer(b->cpu); |
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index c3e366b52261..9c44d004da69 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h | |||
@@ -55,5 +55,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); | |||
55 | /* transient events for the CPU buffer -> event buffer */ | 55 | /* transient events for the CPU buffer -> event buffer */ |
56 | #define CPU_IS_KERNEL 1 | 56 | #define CPU_IS_KERNEL 1 |
57 | #define CPU_TRACE_BEGIN 2 | 57 | #define CPU_TRACE_BEGIN 2 |
58 | #define IBS_FETCH_BEGIN 3 | ||
59 | #define IBS_OP_BEGIN 4 | ||
58 | 60 | ||
59 | #endif /* OPROFILE_CPU_BUFFER_H */ | 61 | #endif /* OPROFILE_CPU_BUFFER_H */ |
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index d18e6d2e0b49..40759c33477d 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c | |||
@@ -418,25 +418,22 @@ fs3270_open(struct inode *inode, struct file *filp) | |||
418 | { | 418 | { |
419 | struct fs3270 *fp; | 419 | struct fs3270 *fp; |
420 | struct idal_buffer *ib; | 420 | struct idal_buffer *ib; |
421 | int minor, rc; | 421 | int minor, rc = 0; |
422 | 422 | ||
423 | if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR) | 423 | if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR) |
424 | return -ENODEV; | 424 | return -ENODEV; |
425 | lock_kernel(); | ||
426 | minor = iminor(filp->f_path.dentry->d_inode); | 425 | minor = iminor(filp->f_path.dentry->d_inode); |
427 | /* Check for minor 0 multiplexer. */ | 426 | /* Check for minor 0 multiplexer. */ |
428 | if (minor == 0) { | 427 | if (minor == 0) { |
429 | struct tty_struct *tty; | 428 | struct tty_struct *tty = get_current_tty(); |
430 | mutex_lock(&tty_mutex); | ||
431 | tty = get_current_tty(); | ||
432 | if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { | 429 | if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { |
433 | mutex_unlock(&tty_mutex); | 430 | tty_kref_put(tty); |
434 | rc = -ENODEV; | 431 | return -ENODEV; |
435 | goto out; | ||
436 | } | 432 | } |
437 | minor = tty->index + RAW3270_FIRSTMINOR; | 433 | minor = tty->index + RAW3270_FIRSTMINOR; |
438 | mutex_unlock(&tty_mutex); | 434 | tty_kref_put(tty); |
439 | } | 435 | } |
436 | lock_kernel(); | ||
440 | /* Check if some other program is already using fullscreen mode. */ | 437 | /* Check if some other program is already using fullscreen mode. */ |
441 | fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); | 438 | fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); |
442 | if (!IS_ERR(fp)) { | 439 | if (!IS_ERR(fp)) { |
@@ -478,7 +475,7 @@ fs3270_open(struct inode *inode, struct file *filp) | |||
478 | filp->private_data = fp; | 475 | filp->private_data = fp; |
479 | out: | 476 | out: |
480 | unlock_kernel(); | 477 | unlock_kernel(); |
481 | return 0; | 478 | return rc; |
482 | } | 479 | } |
483 | 480 | ||
484 | /* | 481 | /* |
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 9ccc563d8730..d4104a3bbe87 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -44,6 +44,10 @@ | |||
44 | 44 | ||
45 | #include "8250.h" | 45 | #include "8250.h" |
46 | 46 | ||
47 | #ifdef CONFIG_SPARC | ||
48 | #include "suncore.h" | ||
49 | #endif | ||
50 | |||
47 | /* | 51 | /* |
48 | * Configuration: | 52 | * Configuration: |
49 | * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option | 53 | * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option |
@@ -53,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; | |||
53 | 57 | ||
54 | static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; | 58 | static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; |
55 | 59 | ||
60 | static struct uart_driver serial8250_reg; | ||
61 | |||
62 | static int serial_index(struct uart_port *port) | ||
63 | { | ||
64 | return (serial8250_reg.minor - 64) + port->line; | ||
65 | } | ||
66 | |||
56 | /* | 67 | /* |
57 | * Debugging. | 68 | * Debugging. |
58 | */ | 69 | */ |
@@ -536,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) | |||
536 | /* | 547 | /* |
537 | * FIFO support. | 548 | * FIFO support. |
538 | */ | 549 | */ |
539 | static inline void serial8250_clear_fifos(struct uart_8250_port *p) | 550 | static void serial8250_clear_fifos(struct uart_8250_port *p) |
540 | { | 551 | { |
541 | if (p->capabilities & UART_CAP_FIFO) { | 552 | if (p->capabilities & UART_CAP_FIFO) { |
542 | serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); | 553 | serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); |
@@ -551,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p) | |||
551 | * capability" bit enabled. Note that on XR16C850s, we need to | 562 | * capability" bit enabled. Note that on XR16C850s, we need to |
552 | * reset LCR to write to IER. | 563 | * reset LCR to write to IER. |
553 | */ | 564 | */ |
554 | static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) | 565 | static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) |
555 | { | 566 | { |
556 | if (p->capabilities & UART_CAP_SLEEP) { | 567 | if (p->capabilities & UART_CAP_SLEEP) { |
557 | if (p->capabilities & UART_CAP_EFR) { | 568 | if (p->capabilities & UART_CAP_EFR) { |
@@ -993,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) | |||
993 | return; | 1004 | return; |
994 | 1005 | ||
995 | DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", | 1006 | DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", |
996 | up->port.line, up->port.iobase, up->port.membase); | 1007 | serial_index(&up->port), up->port.iobase, up->port.membase); |
997 | 1008 | ||
998 | /* | 1009 | /* |
999 | * We really do need global IRQs disabled here - we're going to | 1010 | * We really do need global IRQs disabled here - we're going to |
@@ -1128,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) | |||
1128 | if (up->capabilities != uart_config[up->port.type].flags) { | 1139 | if (up->capabilities != uart_config[up->port.type].flags) { |
1129 | printk(KERN_WARNING | 1140 | printk(KERN_WARNING |
1130 | "ttyS%d: detected caps %08x should be %08x\n", | 1141 | "ttyS%d: detected caps %08x should be %08x\n", |
1131 | up->port.line, up->capabilities, | 1142 | serial_index(&up->port), up->capabilities, |
1132 | uart_config[up->port.type].flags); | 1143 | uart_config[up->port.type].flags); |
1133 | } | 1144 | } |
1134 | 1145 | ||
1135 | up->port.fifosize = uart_config[up->port.type].fifo_size; | 1146 | up->port.fifosize = uart_config[up->port.type].fifo_size; |
@@ -1424,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) | |||
1424 | /* | 1435 | /* |
1425 | * This handles the interrupt from one port. | 1436 | * This handles the interrupt from one port. |
1426 | */ | 1437 | */ |
1427 | static inline void | 1438 | static void serial8250_handle_port(struct uart_8250_port *up) |
1428 | serial8250_handle_port(struct uart_8250_port *up) | ||
1429 | { | 1439 | { |
1430 | unsigned int status; | 1440 | unsigned int status; |
1431 | unsigned long flags; | 1441 | unsigned long flags; |
@@ -1719,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) | |||
1719 | /* | 1729 | /* |
1720 | * Wait for transmitter & holding register to empty | 1730 | * Wait for transmitter & holding register to empty |
1721 | */ | 1731 | */ |
1722 | static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) | 1732 | static void wait_for_xmitr(struct uart_8250_port *up, int bits) |
1723 | { | 1733 | { |
1724 | unsigned int status, tmout = 10000; | 1734 | unsigned int status, tmout = 10000; |
1725 | 1735 | ||
@@ -1854,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port) | |||
1854 | */ | 1864 | */ |
1855 | if (!(up->port.flags & UPF_BUGGY_UART) && | 1865 | if (!(up->port.flags & UPF_BUGGY_UART) && |
1856 | (serial_inp(up, UART_LSR) == 0xff)) { | 1866 | (serial_inp(up, UART_LSR) == 0xff)) { |
1857 | printk("ttyS%d: LSR safety check engaged!\n", up->port.line); | 1867 | printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", |
1868 | serial_index(&up->port)); | ||
1858 | return -ENODEV; | 1869 | return -ENODEV; |
1859 | } | 1870 | } |
1860 | 1871 | ||
@@ -1909,7 +1920,8 @@ static int serial8250_startup(struct uart_port *port) | |||
1909 | */ | 1920 | */ |
1910 | if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { | 1921 | if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { |
1911 | up->bugs |= UART_BUG_THRE; | 1922 | up->bugs |= UART_BUG_THRE; |
1912 | pr_debug("ttyS%d - using backup timer\n", port->line); | 1923 | pr_debug("ttyS%d - using backup timer\n", |
1924 | serial_index(port)); | ||
1913 | } | 1925 | } |
1914 | } | 1926 | } |
1915 | 1927 | ||
@@ -1969,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port) | |||
1969 | if (!(up->bugs & UART_BUG_TXEN)) { | 1981 | if (!(up->bugs & UART_BUG_TXEN)) { |
1970 | up->bugs |= UART_BUG_TXEN; | 1982 | up->bugs |= UART_BUG_TXEN; |
1971 | pr_debug("ttyS%d - enabling bad tx status workarounds\n", | 1983 | pr_debug("ttyS%d - enabling bad tx status workarounds\n", |
1972 | port->line); | 1984 | serial_index(port)); |
1973 | } | 1985 | } |
1974 | } else { | 1986 | } else { |
1975 | up->bugs &= ~UART_BUG_TXEN; | 1987 | up->bugs &= ~UART_BUG_TXEN; |
@@ -2630,7 +2642,6 @@ static int serial8250_console_early_setup(void) | |||
2630 | return serial8250_find_port_for_earlycon(); | 2642 | return serial8250_find_port_for_earlycon(); |
2631 | } | 2643 | } |
2632 | 2644 | ||
2633 | static struct uart_driver serial8250_reg; | ||
2634 | static struct console serial8250_console = { | 2645 | static struct console serial8250_console = { |
2635 | .name = "ttyS", | 2646 | .name = "ttyS", |
2636 | .write = serial8250_console_write, | 2647 | .write = serial8250_console_write, |
@@ -2677,7 +2688,6 @@ static struct uart_driver serial8250_reg = { | |||
2677 | .dev_name = "ttyS", | 2688 | .dev_name = "ttyS", |
2678 | .major = TTY_MAJOR, | 2689 | .major = TTY_MAJOR, |
2679 | .minor = 64, | 2690 | .minor = 64, |
2680 | .nr = UART_NR, | ||
2681 | .cons = SERIAL8250_CONSOLE, | 2691 | .cons = SERIAL8250_CONSOLE, |
2682 | }; | 2692 | }; |
2683 | 2693 | ||
@@ -2959,10 +2969,12 @@ static int __init serial8250_init(void) | |||
2959 | "%d ports, IRQ sharing %sabled\n", nr_uarts, | 2969 | "%d ports, IRQ sharing %sabled\n", nr_uarts, |
2960 | share_irqs ? "en" : "dis"); | 2970 | share_irqs ? "en" : "dis"); |
2961 | 2971 | ||
2962 | for (i = 0; i < NR_IRQS; i++) | 2972 | #ifdef CONFIG_SPARC |
2963 | spin_lock_init(&irq_lists[i].lock); | 2973 | ret = sunserial_register_minors(&serial8250_reg, UART_NR); |
2964 | 2974 | #else | |
2975 | serial8250_reg.nr = UART_NR; | ||
2965 | ret = uart_register_driver(&serial8250_reg); | 2976 | ret = uart_register_driver(&serial8250_reg); |
2977 | #endif | ||
2966 | if (ret) | 2978 | if (ret) |
2967 | goto out; | 2979 | goto out; |
2968 | 2980 | ||
@@ -2987,7 +2999,11 @@ static int __init serial8250_init(void) | |||
2987 | put_dev: | 2999 | put_dev: |
2988 | platform_device_put(serial8250_isa_devs); | 3000 | platform_device_put(serial8250_isa_devs); |
2989 | unreg_uart_drv: | 3001 | unreg_uart_drv: |
3002 | #ifdef CONFIG_SPARC | ||
3003 | sunserial_unregister_minors(&serial8250_reg, UART_NR); | ||
3004 | #else | ||
2990 | uart_unregister_driver(&serial8250_reg); | 3005 | uart_unregister_driver(&serial8250_reg); |
3006 | #endif | ||
2991 | out: | 3007 | out: |
2992 | return ret; | 3008 | return ret; |
2993 | } | 3009 | } |
@@ -3006,7 +3022,11 @@ static void __exit serial8250_exit(void) | |||
3006 | platform_driver_unregister(&serial8250_isa_driver); | 3022 | platform_driver_unregister(&serial8250_isa_driver); |
3007 | platform_device_unregister(isa_dev); | 3023 | platform_device_unregister(isa_dev); |
3008 | 3024 | ||
3025 | #ifdef CONFIG_SPARC | ||
3026 | sunserial_unregister_minors(&serial8250_reg, UART_NR); | ||
3027 | #else | ||
3009 | uart_unregister_driver(&serial8250_reg); | 3028 | uart_unregister_driver(&serial8250_reg); |
3029 | #endif | ||
3010 | } | 3030 | } |
3011 | 3031 | ||
3012 | module_init(serial8250_init); | 3032 | module_init(serial8250_init); |
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index c2f23933155b..c014ffb110e9 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c | |||
@@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev) | |||
2041 | * The device may have been disabled. Re-enable it. | 2041 | * The device may have been disabled. Re-enable it. |
2042 | */ | 2042 | */ |
2043 | err = pci_enable_device(dev); | 2043 | err = pci_enable_device(dev); |
2044 | /* FIXME: We cannot simply error out here */ | ||
2044 | if (err) | 2045 | if (err) |
2045 | return err; | 2046 | printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); |
2046 | |||
2047 | pciserial_resume_ports(priv); | 2047 | pciserial_resume_ports(priv); |
2048 | } | 2048 | } |
2049 | return 0; | 2049 | return 0; |
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 77cb34270fc1..31786b3b0a68 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -9,7 +9,6 @@ menu "Serial drivers" | |||
9 | # The new 8250/16550 serial drivers | 9 | # The new 8250/16550 serial drivers |
10 | config SERIAL_8250 | 10 | config SERIAL_8250 |
11 | tristate "8250/16550 and compatible serial support" | 11 | tristate "8250/16550 and compatible serial support" |
12 | depends on (BROKEN || !SPARC) | ||
13 | select SERIAL_CORE | 12 | select SERIAL_CORE |
14 | ---help--- | 13 | ---help--- |
15 | This selects whether you want to include the driver for the standard | 14 | This selects whether you want to include the driver for the standard |
@@ -994,24 +993,12 @@ config SERIAL_68328_RTS_CTS | |||
994 | bool "Support RTS/CTS on 68328 serial port" | 993 | bool "Support RTS/CTS on 68328 serial port" |
995 | depends on SERIAL_68328 | 994 | depends on SERIAL_68328 |
996 | 995 | ||
997 | config SERIAL_COLDFIRE | ||
998 | bool "ColdFire serial support (DEPRECATED)" | ||
999 | depends on COLDFIRE | ||
1000 | help | ||
1001 | This driver supports the built-in serial ports of the Motorola ColdFire | ||
1002 | family of CPUs. | ||
1003 | This driver is deprecated because it supports only the old interface | ||
1004 | for serial drivers and features like magic keys are not working. | ||
1005 | Please switch to the new style driver because this driver will be | ||
1006 | removed soon. | ||
1007 | |||
1008 | config SERIAL_MCF | 996 | config SERIAL_MCF |
1009 | bool "Coldfire serial support (new style driver)" | 997 | bool "Coldfire serial support" |
1010 | depends on COLDFIRE | 998 | depends on COLDFIRE |
1011 | select SERIAL_CORE | 999 | select SERIAL_CORE |
1012 | help | 1000 | help |
1013 | This new serial driver supports the Freescale Coldfire serial ports | 1001 | This serial driver supports the Freescale Coldfire serial ports. |
1014 | using the new serial driver subsystem. | ||
1015 | 1002 | ||
1016 | config SERIAL_MCF_BAUDRATE | 1003 | config SERIAL_MCF_BAUDRATE |
1017 | int "Default baudrate for Coldfire serial ports" | 1004 | int "Default baudrate for Coldfire serial ports" |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 7e7383e890d8..0c17c8ddb19d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
@@ -4,6 +4,16 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_SERIAL_CORE) += serial_core.o | 5 | obj-$(CONFIG_SERIAL_CORE) += serial_core.o |
6 | obj-$(CONFIG_SERIAL_21285) += 21285.o | 6 | obj-$(CONFIG_SERIAL_21285) += 21285.o |
7 | |||
8 | # These Sparc drivers have to appear before others such as 8250 | ||
9 | # which share ttySx minor node space. Otherwise console device | ||
10 | # names change and other unplesantries. | ||
11 | obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o | ||
12 | obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o | ||
13 | obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o | ||
14 | obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o | ||
15 | obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o | ||
16 | |||
7 | obj-$(CONFIG_SERIAL_8250) += 8250.o | 17 | obj-$(CONFIG_SERIAL_8250) += 8250.o |
8 | obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o | 18 | obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o |
9 | obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o | 19 | obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o |
@@ -31,16 +41,10 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o | |||
31 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o | 41 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o |
32 | obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o | 42 | obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o |
33 | obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o | 43 | obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o |
34 | obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o | ||
35 | obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o | ||
36 | obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o | ||
37 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o | 44 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o |
38 | obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o | ||
39 | obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o | ||
40 | obj-$(CONFIG_SERIAL_MUX) += mux.o | 45 | obj-$(CONFIG_SERIAL_MUX) += mux.o |
41 | obj-$(CONFIG_SERIAL_68328) += 68328serial.o | 46 | obj-$(CONFIG_SERIAL_68328) += 68328serial.o |
42 | obj-$(CONFIG_SERIAL_68360) += 68360serial.o | 47 | obj-$(CONFIG_SERIAL_68360) += 68360serial.o |
43 | obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o | ||
44 | obj-$(CONFIG_SERIAL_MCF) += mcf.o | 48 | obj-$(CONFIG_SERIAL_MCF) += mcf.o |
45 | obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o | 49 | obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o |
46 | obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o | 50 | obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o |
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 4a0d30bed9f1..569f0e2476c6 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Blackfin On-Chip Serial Driver | 2 | * Blackfin On-Chip Serial Driver |
3 | * | 3 | * |
4 | * Copyright 2006-2007 Analog Devices Inc. | 4 | * Copyright 2006-2008 Analog Devices Inc. |
5 | * | 5 | * |
6 | * Enter bugs at http://blackfin.uclinux.org/ | 6 | * Enter bugs at http://blackfin.uclinux.org/ |
7 | * | 7 | * |
@@ -42,6 +42,9 @@ | |||
42 | #define BFIN_SERIAL_MAJOR 204 | 42 | #define BFIN_SERIAL_MAJOR 204 |
43 | #define BFIN_SERIAL_MINOR 64 | 43 | #define BFIN_SERIAL_MINOR 64 |
44 | 44 | ||
45 | static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; | ||
46 | static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); | ||
47 | |||
45 | /* | 48 | /* |
46 | * Setup for console. Argument comes from the menuconfig | 49 | * Setup for console. Argument comes from the menuconfig |
47 | */ | 50 | */ |
@@ -126,13 +129,13 @@ static int kgdb_entry_state; | |||
126 | void kgdb_put_debug_char(int chr) | 129 | void kgdb_put_debug_char(int chr) |
127 | { | 130 | { |
128 | struct bfin_serial_port *uart; | 131 | struct bfin_serial_port *uart; |
129 | 132 | ||
130 | if (CONFIG_KGDB_UART_PORT < 0 | 133 | if (CONFIG_KGDB_UART_PORT < 0 |
131 | || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) | 134 | || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) |
132 | uart = &bfin_serial_ports[0]; | 135 | uart = &bfin_serial_ports[0]; |
133 | else | 136 | else |
134 | uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; | 137 | uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; |
135 | 138 | ||
136 | while (!(UART_GET_LSR(uart) & THRE)) { | 139 | while (!(UART_GET_LSR(uart) & THRE)) { |
137 | SSYNC(); | 140 | SSYNC(); |
138 | } | 141 | } |
@@ -152,7 +155,7 @@ int kgdb_get_debug_char(void) | |||
152 | uart = &bfin_serial_ports[0]; | 155 | uart = &bfin_serial_ports[0]; |
153 | else | 156 | else |
154 | uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; | 157 | uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; |
155 | 158 | ||
156 | while(!(UART_GET_LSR(uart) & DR)) { | 159 | while(!(UART_GET_LSR(uart) & DR)) { |
157 | SSYNC(); | 160 | SSYNC(); |
158 | } | 161 | } |
@@ -298,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) | |||
298 | bfin_serial_mctrl_check(uart); | 301 | bfin_serial_mctrl_check(uart); |
299 | 302 | ||
300 | if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { | 303 | if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { |
301 | bfin_serial_stop_tx(&uart->port); | 304 | #ifdef CONFIG_BF54x |
305 | /* Clear TFI bit */ | ||
306 | UART_PUT_LSR(uart, TFI); | ||
307 | #endif | ||
308 | UART_CLEAR_IER(uart, ETBEI); | ||
302 | return; | 309 | return; |
303 | } | 310 | } |
304 | 311 | ||
@@ -317,9 +324,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) | |||
317 | 324 | ||
318 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 325 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
319 | uart_write_wakeup(&uart->port); | 326 | uart_write_wakeup(&uart->port); |
320 | |||
321 | if (uart_circ_empty(xmit)) | ||
322 | bfin_serial_stop_tx(&uart->port); | ||
323 | } | 327 | } |
324 | 328 | ||
325 | static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) | 329 | static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) |
@@ -645,6 +649,42 @@ static int bfin_serial_startup(struct uart_port *port) | |||
645 | free_irq(uart->port.irq, uart); | 649 | free_irq(uart->port.irq, uart); |
646 | return -EBUSY; | 650 | return -EBUSY; |
647 | } | 651 | } |
652 | |||
653 | # ifdef CONFIG_BF54x | ||
654 | { | ||
655 | unsigned uart_dma_ch_rx, uart_dma_ch_tx; | ||
656 | |||
657 | switch (uart->port.irq) { | ||
658 | case IRQ_UART3_RX: | ||
659 | uart_dma_ch_rx = CH_UART3_RX; | ||
660 | uart_dma_ch_tx = CH_UART3_TX; | ||
661 | break; | ||
662 | case IRQ_UART2_RX: | ||
663 | uart_dma_ch_rx = CH_UART2_RX; | ||
664 | uart_dma_ch_tx = CH_UART2_TX; | ||
665 | break; | ||
666 | default: | ||
667 | uart_dma_ch_rx = uart_dma_ch_tx = 0; | ||
668 | break; | ||
669 | }; | ||
670 | |||
671 | if (uart_dma_ch_rx && | ||
672 | request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { | ||
673 | printk(KERN_NOTICE"Fail to attach UART interrupt\n"); | ||
674 | free_irq(uart->port.irq, uart); | ||
675 | free_irq(uart->port.irq + 1, uart); | ||
676 | return -EBUSY; | ||
677 | } | ||
678 | if (uart_dma_ch_tx && | ||
679 | request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { | ||
680 | printk(KERN_NOTICE "Fail to attach UART interrupt\n"); | ||
681 | free_dma(uart_dma_ch_rx); | ||
682 | free_irq(uart->port.irq, uart); | ||
683 | free_irq(uart->port.irq + 1, uart); | ||
684 | return -EBUSY; | ||
685 | } | ||
686 | } | ||
687 | # endif | ||
648 | #endif | 688 | #endif |
649 | UART_SET_IER(uart, ERBFI); | 689 | UART_SET_IER(uart, ERBFI); |
650 | return 0; | 690 | return 0; |
@@ -662,6 +702,20 @@ static void bfin_serial_shutdown(struct uart_port *port) | |||
662 | del_timer(&(uart->rx_dma_timer)); | 702 | del_timer(&(uart->rx_dma_timer)); |
663 | dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); | 703 | dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); |
664 | #else | 704 | #else |
705 | #ifdef CONFIG_BF54x | ||
706 | switch (uart->port.irq) { | ||
707 | case IRQ_UART3_RX: | ||
708 | free_dma(CH_UART3_RX); | ||
709 | free_dma(CH_UART3_TX); | ||
710 | break; | ||
711 | case IRQ_UART2_RX: | ||
712 | free_dma(CH_UART2_RX); | ||
713 | free_dma(CH_UART2_TX); | ||
714 | break; | ||
715 | default: | ||
716 | break; | ||
717 | }; | ||
718 | #endif | ||
665 | #ifdef CONFIG_KGDB_UART | 719 | #ifdef CONFIG_KGDB_UART |
666 | if (uart->port.line != CONFIG_KGDB_UART_PORT) | 720 | if (uart->port.line != CONFIG_KGDB_UART_PORT) |
667 | #endif | 721 | #endif |
@@ -757,6 +811,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, | |||
757 | val |= UCEN; | 811 | val |= UCEN; |
758 | UART_PUT_GCTL(uart, val); | 812 | UART_PUT_GCTL(uart, val); |
759 | 813 | ||
814 | /* Port speed changed, update the per-port timeout. */ | ||
815 | uart_update_timeout(port, termios->c_cflag, baud); | ||
816 | |||
760 | spin_unlock_irqrestore(&uart->port.lock, flags); | 817 | spin_unlock_irqrestore(&uart->port.lock, flags); |
761 | } | 818 | } |
762 | 819 | ||
@@ -859,8 +916,9 @@ static void __init bfin_serial_init_ports(void) | |||
859 | return; | 916 | return; |
860 | first = 0; | 917 | first = 0; |
861 | 918 | ||
862 | for (i = 0; i < nr_ports; i++) { | 919 | for (i = 0; i < nr_active_ports; i++) { |
863 | bfin_serial_ports[i].port.uartclk = get_sclk(); | 920 | bfin_serial_ports[i].port.uartclk = get_sclk(); |
921 | bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; | ||
864 | bfin_serial_ports[i].port.ops = &bfin_serial_pops; | 922 | bfin_serial_ports[i].port.ops = &bfin_serial_pops; |
865 | bfin_serial_ports[i].port.line = i; | 923 | bfin_serial_ports[i].port.line = i; |
866 | bfin_serial_ports[i].port.iotype = UPIO_MEM; | 924 | bfin_serial_ports[i].port.iotype = UPIO_MEM; |
@@ -961,7 +1019,7 @@ bfin_serial_console_setup(struct console *co, char *options) | |||
961 | * if so, search for the first available port that does have | 1019 | * if so, search for the first available port that does have |
962 | * console support. | 1020 | * console support. |
963 | */ | 1021 | */ |
964 | if (co->index == -1 || co->index >= nr_ports) | 1022 | if (co->index == -1 || co->index >= nr_active_ports) |
965 | co->index = 0; | 1023 | co->index = 0; |
966 | uart = &bfin_serial_ports[co->index]; | 1024 | uart = &bfin_serial_ports[co->index]; |
967 | 1025 | ||
@@ -1056,7 +1114,7 @@ static __init void early_serial_write(struct console *con, const char *s, | |||
1056 | } | 1114 | } |
1057 | } | 1115 | } |
1058 | 1116 | ||
1059 | static struct __init console bfin_early_serial_console = { | 1117 | static struct __initdata console bfin_early_serial_console = { |
1060 | .name = "early_BFuart", | 1118 | .name = "early_BFuart", |
1061 | .write = early_serial_write, | 1119 | .write = early_serial_write, |
1062 | .device = uart_console_device, | 1120 | .device = uart_console_device, |
@@ -1072,7 +1130,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, | |||
1072 | struct bfin_serial_port *uart; | 1130 | struct bfin_serial_port *uart; |
1073 | struct ktermios t; | 1131 | struct ktermios t; |
1074 | 1132 | ||
1075 | if (port == -1 || port >= nr_ports) | 1133 | if (port == -1 || port >= nr_active_ports) |
1076 | port = 0; | 1134 | port = 0; |
1077 | bfin_serial_init_ports(); | 1135 | bfin_serial_init_ports(); |
1078 | bfin_early_serial_console.index = port; | 1136 | bfin_early_serial_console.index = port; |
@@ -1100,20 +1158,26 @@ static struct uart_driver bfin_serial_reg = { | |||
1100 | 1158 | ||
1101 | static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) | 1159 | static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) |
1102 | { | 1160 | { |
1103 | struct bfin_serial_port *uart = platform_get_drvdata(dev); | 1161 | int i; |
1104 | 1162 | ||
1105 | if (uart) | 1163 | for (i = 0; i < nr_active_ports; i++) { |
1106 | uart_suspend_port(&bfin_serial_reg, &uart->port); | 1164 | if (bfin_serial_ports[i].port.dev != &dev->dev) |
1165 | continue; | ||
1166 | uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port); | ||
1167 | } | ||
1107 | 1168 | ||
1108 | return 0; | 1169 | return 0; |
1109 | } | 1170 | } |
1110 | 1171 | ||
1111 | static int bfin_serial_resume(struct platform_device *dev) | 1172 | static int bfin_serial_resume(struct platform_device *dev) |
1112 | { | 1173 | { |
1113 | struct bfin_serial_port *uart = platform_get_drvdata(dev); | 1174 | int i; |
1114 | 1175 | ||
1115 | if (uart) | 1176 | for (i = 0; i < nr_active_ports; i++) { |
1116 | uart_resume_port(&bfin_serial_reg, &uart->port); | 1177 | if (bfin_serial_ports[i].port.dev != &dev->dev) |
1178 | continue; | ||
1179 | uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port); | ||
1180 | } | ||
1117 | 1181 | ||
1118 | return 0; | 1182 | return 0; |
1119 | } | 1183 | } |
@@ -1128,32 +1192,31 @@ static int bfin_serial_probe(struct platform_device *dev) | |||
1128 | break; | 1192 | break; |
1129 | 1193 | ||
1130 | if (i < dev->num_resources) { | 1194 | if (i < dev->num_resources) { |
1131 | for (i = 0; i < nr_ports; i++, res++) { | 1195 | for (i = 0; i < nr_active_ports; i++, res++) { |
1132 | if (bfin_serial_ports[i].port.mapbase != res->start) | 1196 | if (bfin_serial_ports[i].port.mapbase != res->start) |
1133 | continue; | 1197 | continue; |
1134 | bfin_serial_ports[i].port.dev = &dev->dev; | 1198 | bfin_serial_ports[i].port.dev = &dev->dev; |
1135 | uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); | 1199 | uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); |
1136 | platform_set_drvdata(dev, &bfin_serial_ports[i]); | ||
1137 | } | 1200 | } |
1138 | } | 1201 | } |
1139 | 1202 | ||
1140 | return 0; | 1203 | return 0; |
1141 | } | 1204 | } |
1142 | 1205 | ||
1143 | static int bfin_serial_remove(struct platform_device *pdev) | 1206 | static int bfin_serial_remove(struct platform_device *dev) |
1144 | { | 1207 | { |
1145 | struct bfin_serial_port *uart = platform_get_drvdata(pdev); | 1208 | int i; |
1146 | |||
1147 | 1209 | ||
1210 | for (i = 0; i < nr_active_ports; i++) { | ||
1211 | if (bfin_serial_ports[i].port.dev != &dev->dev) | ||
1212 | continue; | ||
1213 | uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); | ||
1214 | bfin_serial_ports[i].port.dev = NULL; | ||
1148 | #ifdef CONFIG_SERIAL_BFIN_CTSRTS | 1215 | #ifdef CONFIG_SERIAL_BFIN_CTSRTS |
1149 | gpio_free(uart->cts_pin); | 1216 | gpio_free(bfin_serial_ports[i].cts_pin); |
1150 | gpio_free(uart->rts_pin); | 1217 | gpio_free(bfin_serial_ports[i].rts_pin); |
1151 | #endif | 1218 | #endif |
1152 | 1219 | } | |
1153 | platform_set_drvdata(pdev, NULL); | ||
1154 | |||
1155 | if (uart) | ||
1156 | uart_remove_one_port(&bfin_serial_reg, &uart->port); | ||
1157 | 1220 | ||
1158 | return 0; | 1221 | return 0; |
1159 | } | 1222 | } |
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index bf94a770bb44..211c21797ce0 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c | |||
@@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = { | |||
457 | #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) | 457 | #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) |
458 | 458 | ||
459 | static struct ktermios *serial_termios[NR_PORTS]; | 459 | static struct ktermios *serial_termios[NR_PORTS]; |
460 | static struct ktermios *serial_termios_locked[NR_PORTS]; | ||
461 | #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER | 460 | #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER |
462 | static struct fast_timer fast_timers[NR_PORTS]; | 461 | static struct fast_timer fast_timers[NR_PORTS]; |
463 | #endif | 462 | #endif |
@@ -4419,6 +4418,7 @@ rs_init(void) | |||
4419 | rs485_pa_bit)) { | 4418 | rs485_pa_bit)) { |
4420 | printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " | 4419 | printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " |
4421 | "RS485 pin\n"); | 4420 | "RS485 pin\n"); |
4421 | put_tty_driver(driver); | ||
4422 | return -EBUSY; | 4422 | return -EBUSY; |
4423 | } | 4423 | } |
4424 | #endif | 4424 | #endif |
@@ -4427,6 +4427,7 @@ rs_init(void) | |||
4427 | rs485_port_g_bit)) { | 4427 | rs485_port_g_bit)) { |
4428 | printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " | 4428 | printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " |
4429 | "RS485 pin\n"); | 4429 | "RS485 pin\n"); |
4430 | put_tty_driver(driver); | ||
4430 | return -EBUSY; | 4431 | return -EBUSY; |
4431 | } | 4432 | } |
4432 | #endif | 4433 | #endif |
@@ -4446,8 +4447,6 @@ rs_init(void) | |||
4446 | driver->init_termios.c_ispeed = 115200; | 4447 | driver->init_termios.c_ispeed = 115200; |
4447 | driver->init_termios.c_ospeed = 115200; | 4448 | driver->init_termios.c_ospeed = 115200; |
4448 | driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 4449 | driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
4449 | driver->termios = serial_termios; | ||
4450 | driver->termios_locked = serial_termios_locked; | ||
4451 | 4450 | ||
4452 | tty_set_operations(driver, &rs_ops); | 4451 | tty_set_operations(driver, &rs_ops); |
4453 | serial_driver = driver; | 4452 | serial_driver = driver; |
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c deleted file mode 100644 index fbe3835f6b77..000000000000 --- a/drivers/serial/mcfserial.c +++ /dev/null | |||
@@ -1,1965 +0,0 @@ | |||
1 | #warning This driver is deprecated. Check Kconfig for details. | ||
2 | /* | ||
3 | * mcfserial.c -- serial driver for ColdFire internal UARTS. | ||
4 | * | ||
5 | * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com> | ||
6 | * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> | ||
7 | * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> | ||
8 | * | ||
9 | * Based on code from 68332serial.c which was: | ||
10 | * | ||
11 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
12 | * Copyright (C) 1998 TSHG | ||
13 | * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> | ||
14 | * | ||
15 | * Changes: | ||
16 | * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it> | ||
17 | * some cleanups in mcfrs_write. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/signal.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/wait.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/tty_flip.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/fcntl.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/serial.h> | ||
35 | #include <linux/serialP.h> | ||
36 | #include <linux/console.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/bitops.h> | ||
39 | #include <linux/delay.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/system.h> | ||
44 | #include <asm/delay.h> | ||
45 | #include <asm/coldfire.h> | ||
46 | #include <asm/mcfsim.h> | ||
47 | #include <asm/mcfuart.h> | ||
48 | #include <asm/nettel.h> | ||
49 | #include <asm/uaccess.h> | ||
50 | #include "mcfserial.h" | ||
51 | |||
52 | struct timer_list mcfrs_timer_struct; | ||
53 | |||
54 | /* | ||
55 | * Default console baud rate, we use this as the default | ||
56 | * for all ports so init can just open /dev/console and | ||
57 | * keep going. Perhaps one day the cflag settings for the | ||
58 | * console can be used instead. | ||
59 | */ | ||
60 | #if defined(CONFIG_HW_FEITH) | ||
61 | #define CONSOLE_BAUD_RATE 38400 | ||
62 | #define DEFAULT_CBAUD B38400 | ||
63 | #elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ | ||
64 | defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) | ||
65 | #define CONSOLE_BAUD_RATE 115200 | ||
66 | #define DEFAULT_CBAUD B115200 | ||
67 | #elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ | ||
68 | defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET) | ||
69 | #define CONSOLE_BAUD_RATE 19200 | ||
70 | #define DEFAULT_CBAUD B19200 | ||
71 | #endif | ||
72 | |||
73 | #ifndef CONSOLE_BAUD_RATE | ||
74 | #define CONSOLE_BAUD_RATE 9600 | ||
75 | #define DEFAULT_CBAUD B9600 | ||
76 | #endif | ||
77 | |||
78 | int mcfrs_console_inited = 0; | ||
79 | int mcfrs_console_port = -1; | ||
80 | int mcfrs_console_baud = CONSOLE_BAUD_RATE; | ||
81 | int mcfrs_console_cbaud = DEFAULT_CBAUD; | ||
82 | |||
83 | /* | ||
84 | * Driver data structures. | ||
85 | */ | ||
86 | static struct tty_driver *mcfrs_serial_driver; | ||
87 | |||
88 | /* number of characters left in xmit buffer before we ask for more */ | ||
89 | #define WAKEUP_CHARS 256 | ||
90 | |||
91 | /* Debugging... | ||
92 | */ | ||
93 | #undef SERIAL_DEBUG_OPEN | ||
94 | #undef SERIAL_DEBUG_FLOW | ||
95 | |||
96 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ | ||
97 | defined(CONFIG_M520x) || defined(CONFIG_M532x) | ||
98 | #define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) | ||
99 | #else | ||
100 | #define IRQBASE 73 | ||
101 | #endif | ||
102 | |||
103 | /* | ||
104 | * Configuration table, UARTs to look for at startup. | ||
105 | */ | ||
106 | static struct mcf_serial mcfrs_table[] = { | ||
107 | { /* ttyS0 */ | ||
108 | .magic = 0, | ||
109 | .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1), | ||
110 | .irq = IRQBASE, | ||
111 | .flags = ASYNC_BOOT_AUTOCONF, | ||
112 | }, | ||
113 | #ifdef MCFUART_BASE2 | ||
114 | { /* ttyS1 */ | ||
115 | .magic = 0, | ||
116 | .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), | ||
117 | .irq = IRQBASE+1, | ||
118 | .flags = ASYNC_BOOT_AUTOCONF, | ||
119 | }, | ||
120 | #endif | ||
121 | #ifdef MCFUART_BASE3 | ||
122 | { /* ttyS2 */ | ||
123 | .magic = 0, | ||
124 | .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), | ||
125 | .irq = IRQBASE+2, | ||
126 | .flags = ASYNC_BOOT_AUTOCONF, | ||
127 | }, | ||
128 | #endif | ||
129 | #ifdef MCFUART_BASE4 | ||
130 | { /* ttyS3 */ | ||
131 | .magic = 0, | ||
132 | .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), | ||
133 | .irq = IRQBASE+3, | ||
134 | .flags = ASYNC_BOOT_AUTOCONF, | ||
135 | }, | ||
136 | #endif | ||
137 | }; | ||
138 | |||
139 | |||
140 | #define NR_PORTS (sizeof(mcfrs_table) / sizeof(struct mcf_serial)) | ||
141 | |||
142 | /* | ||
143 | * This is used to figure out the divisor speeds and the timeouts. | ||
144 | */ | ||
145 | static int mcfrs_baud_table[] = { | ||
146 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, | ||
147 | 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 | ||
148 | }; | ||
149 | #define MCFRS_BAUD_TABLE_SIZE \ | ||
150 | (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0])) | ||
151 | |||
152 | |||
153 | #ifdef CONFIG_MAGIC_SYSRQ | ||
154 | /* | ||
155 | * Magic system request keys. Used for debugging... | ||
156 | */ | ||
157 | extern int magic_sysrq_key(int ch); | ||
158 | #endif | ||
159 | |||
160 | |||
161 | /* | ||
162 | * Forware declarations... | ||
163 | */ | ||
164 | static void mcfrs_change_speed(struct mcf_serial *info); | ||
165 | static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout); | ||
166 | |||
167 | |||
168 | static inline int serial_paranoia_check(struct mcf_serial *info, | ||
169 | char *name, const char *routine) | ||
170 | { | ||
171 | #ifdef SERIAL_PARANOIA_CHECK | ||
172 | static const char badmagic[] = | ||
173 | "MCFRS(warning): bad magic number for serial struct %s in %s\n"; | ||
174 | static const char badinfo[] = | ||
175 | "MCFRS(warning): null mcf_serial for %s in %s\n"; | ||
176 | |||
177 | if (!info) { | ||
178 | printk(badinfo, name, routine); | ||
179 | return 1; | ||
180 | } | ||
181 | if (info->magic != SERIAL_MAGIC) { | ||
182 | printk(badmagic, name, routine); | ||
183 | return 1; | ||
184 | } | ||
185 | #endif | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Sets or clears DTR and RTS on the requested line. | ||
191 | */ | ||
192 | static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts) | ||
193 | { | ||
194 | volatile unsigned char *uartp; | ||
195 | unsigned long flags; | ||
196 | |||
197 | #if 0 | ||
198 | printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n", | ||
199 | __FILE__, __LINE__, info, dtr, rts); | ||
200 | #endif | ||
201 | |||
202 | local_irq_save(flags); | ||
203 | if (dtr >= 0) { | ||
204 | #ifdef MCFPP_DTR0 | ||
205 | if (info->line) | ||
206 | mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1)); | ||
207 | else | ||
208 | mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0)); | ||
209 | #endif | ||
210 | } | ||
211 | if (rts >= 0) { | ||
212 | uartp = info->addr; | ||
213 | if (rts) { | ||
214 | info->sigs |= TIOCM_RTS; | ||
215 | uartp[MCFUART_UOP1] = MCFUART_UOP_RTS; | ||
216 | } else { | ||
217 | info->sigs &= ~TIOCM_RTS; | ||
218 | uartp[MCFUART_UOP0] = MCFUART_UOP_RTS; | ||
219 | } | ||
220 | } | ||
221 | local_irq_restore(flags); | ||
222 | return; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Gets values of serial signals. | ||
227 | */ | ||
228 | static int mcfrs_getsignals(struct mcf_serial *info) | ||
229 | { | ||
230 | volatile unsigned char *uartp; | ||
231 | unsigned long flags; | ||
232 | int sigs; | ||
233 | #if defined(CONFIG_NETtel) && defined(CONFIG_M5307) | ||
234 | unsigned short ppdata; | ||
235 | #endif | ||
236 | |||
237 | #if 0 | ||
238 | printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__); | ||
239 | #endif | ||
240 | |||
241 | local_irq_save(flags); | ||
242 | uartp = info->addr; | ||
243 | sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; | ||
244 | sigs |= (info->sigs & TIOCM_RTS); | ||
245 | |||
246 | #ifdef MCFPP_DCD0 | ||
247 | { | ||
248 | unsigned int ppdata; | ||
249 | ppdata = mcf_getppdata(); | ||
250 | if (info->line == 0) { | ||
251 | sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD; | ||
252 | sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR; | ||
253 | } else if (info->line == 1) { | ||
254 | sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD; | ||
255 | sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR; | ||
256 | } | ||
257 | } | ||
258 | #endif | ||
259 | |||
260 | local_irq_restore(flags); | ||
261 | return(sigs); | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * ------------------------------------------------------------ | ||
266 | * mcfrs_stop() and mcfrs_start() | ||
267 | * | ||
268 | * This routines are called before setting or resetting tty->stopped. | ||
269 | * They enable or disable transmitter interrupts, as necessary. | ||
270 | * ------------------------------------------------------------ | ||
271 | */ | ||
272 | static void mcfrs_stop(struct tty_struct *tty) | ||
273 | { | ||
274 | volatile unsigned char *uartp; | ||
275 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
276 | unsigned long flags; | ||
277 | |||
278 | if (serial_paranoia_check(info, tty->name, "mcfrs_stop")) | ||
279 | return; | ||
280 | |||
281 | local_irq_save(flags); | ||
282 | uartp = info->addr; | ||
283 | info->imr &= ~MCFUART_UIR_TXREADY; | ||
284 | uartp[MCFUART_UIMR] = info->imr; | ||
285 | local_irq_restore(flags); | ||
286 | } | ||
287 | |||
288 | static void mcfrs_start(struct tty_struct *tty) | ||
289 | { | ||
290 | volatile unsigned char *uartp; | ||
291 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
292 | unsigned long flags; | ||
293 | |||
294 | if (serial_paranoia_check(info, tty->name, "mcfrs_start")) | ||
295 | return; | ||
296 | |||
297 | local_irq_save(flags); | ||
298 | if (info->xmit_cnt && info->xmit_buf) { | ||
299 | uartp = info->addr; | ||
300 | info->imr |= MCFUART_UIR_TXREADY; | ||
301 | uartp[MCFUART_UIMR] = info->imr; | ||
302 | } | ||
303 | local_irq_restore(flags); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * ---------------------------------------------------------------------- | ||
308 | * | ||
309 | * Here starts the interrupt handling routines. All of the following | ||
310 | * subroutines are declared as inline and are folded into | ||
311 | * mcfrs_interrupt(). They were separated out for readability's sake. | ||
312 | * | ||
313 | * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it | ||
314 | * runs with interrupts turned off. People who may want to modify | ||
315 | * mcfrs_interrupt() should try to keep the interrupt handler as fast as | ||
316 | * possible. After you are done making modifications, it is not a bad | ||
317 | * idea to do: | ||
318 | * | ||
319 | * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c | ||
320 | * | ||
321 | * and look at the resulting assemble code in serial.s. | ||
322 | * | ||
323 | * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 | ||
324 | * ----------------------------------------------------------------------- | ||
325 | */ | ||
326 | |||
327 | static inline void receive_chars(struct mcf_serial *info) | ||
328 | { | ||
329 | volatile unsigned char *uartp; | ||
330 | struct tty_struct *tty = info->port.tty; | ||
331 | unsigned char status, ch, flag; | ||
332 | |||
333 | if (!tty) | ||
334 | return; | ||
335 | |||
336 | uartp = info->addr; | ||
337 | |||
338 | while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) { | ||
339 | ch = uartp[MCFUART_URB]; | ||
340 | info->stats.rx++; | ||
341 | |||
342 | #ifdef CONFIG_MAGIC_SYSRQ | ||
343 | if (mcfrs_console_inited && (info->line == mcfrs_console_port)) { | ||
344 | if (magic_sysrq_key(ch)) | ||
345 | continue; | ||
346 | } | ||
347 | #endif | ||
348 | |||
349 | flag = TTY_NORMAL; | ||
350 | if (status & MCFUART_USR_RXERR) { | ||
351 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR; | ||
352 | if (status & MCFUART_USR_RXBREAK) { | ||
353 | info->stats.rxbreak++; | ||
354 | flag = TTY_BREAK; | ||
355 | } else if (status & MCFUART_USR_RXPARITY) { | ||
356 | info->stats.rxparity++; | ||
357 | flag = TTY_PARITY; | ||
358 | } else if (status & MCFUART_USR_RXOVERRUN) { | ||
359 | info->stats.rxoverrun++; | ||
360 | flag = TTY_OVERRUN; | ||
361 | } else if (status & MCFUART_USR_RXFRAMING) { | ||
362 | info->stats.rxframing++; | ||
363 | flag = TTY_FRAME; | ||
364 | } | ||
365 | } | ||
366 | tty_insert_flip_char(tty, ch, flag); | ||
367 | } | ||
368 | tty_schedule_flip(tty); | ||
369 | return; | ||
370 | } | ||
371 | |||
372 | static inline void transmit_chars(struct mcf_serial *info) | ||
373 | { | ||
374 | volatile unsigned char *uartp; | ||
375 | |||
376 | uartp = info->addr; | ||
377 | |||
378 | if (info->x_char) { | ||
379 | /* Send special char - probably flow control */ | ||
380 | uartp[MCFUART_UTB] = info->x_char; | ||
381 | info->x_char = 0; | ||
382 | info->stats.tx++; | ||
383 | } | ||
384 | |||
385 | if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { | ||
386 | info->imr &= ~MCFUART_UIR_TXREADY; | ||
387 | uartp[MCFUART_UIMR] = info->imr; | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) { | ||
392 | uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++]; | ||
393 | info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); | ||
394 | info->stats.tx++; | ||
395 | if (--info->xmit_cnt <= 0) | ||
396 | break; | ||
397 | } | ||
398 | |||
399 | if (info->xmit_cnt < WAKEUP_CHARS) | ||
400 | schedule_work(&info->tqueue); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * This is the serial driver's generic interrupt routine | ||
406 | */ | ||
407 | irqreturn_t mcfrs_interrupt(int irq, void *dev_id) | ||
408 | { | ||
409 | struct mcf_serial *info; | ||
410 | unsigned char isr; | ||
411 | |||
412 | info = &mcfrs_table[(irq - IRQBASE)]; | ||
413 | isr = info->addr[MCFUART_UISR] & info->imr; | ||
414 | |||
415 | if (isr & MCFUART_UIR_RXREADY) | ||
416 | receive_chars(info); | ||
417 | if (isr & MCFUART_UIR_TXREADY) | ||
418 | transmit_chars(info); | ||
419 | return IRQ_HANDLED; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * ------------------------------------------------------------------- | ||
424 | * Here ends the serial interrupt routines. | ||
425 | * ------------------------------------------------------------------- | ||
426 | */ | ||
427 | |||
428 | static void mcfrs_offintr(struct work_struct *work) | ||
429 | { | ||
430 | struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue); | ||
431 | struct tty_struct *tty = info->port.tty; | ||
432 | |||
433 | if (tty) | ||
434 | tty_wakeup(tty); | ||
435 | } | ||
436 | |||
437 | |||
438 | /* | ||
439 | * Change of state on a DCD line. | ||
440 | */ | ||
441 | void mcfrs_modem_change(struct mcf_serial *info, int dcd) | ||
442 | { | ||
443 | if (info->count == 0) | ||
444 | return; | ||
445 | |||
446 | if (info->flags & ASYNC_CHECK_CD) { | ||
447 | if (dcd) | ||
448 | wake_up_interruptible(&info->open_wait); | ||
449 | else | ||
450 | schedule_work(&info->tqueue_hangup); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | |||
455 | #ifdef MCFPP_DCD0 | ||
456 | |||
457 | unsigned short mcfrs_ppstatus; | ||
458 | |||
459 | /* | ||
460 | * This subroutine is called when the RS_TIMER goes off. It is used | ||
461 | * to monitor the state of the DCD lines - since they have no edge | ||
462 | * sensors and interrupt generators. | ||
463 | */ | ||
464 | static void mcfrs_timer(void) | ||
465 | { | ||
466 | unsigned int ppstatus, dcdval, i; | ||
467 | |||
468 | ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); | ||
469 | |||
470 | if (ppstatus != mcfrs_ppstatus) { | ||
471 | for (i = 0; (i < 2); i++) { | ||
472 | dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0); | ||
473 | if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) { | ||
474 | mcfrs_modem_change(&mcfrs_table[i], | ||
475 | ((ppstatus & dcdval) ? 0 : 1)); | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | mcfrs_ppstatus = ppstatus; | ||
480 | |||
481 | /* Re-arm timer */ | ||
482 | mcfrs_timer_struct.expires = jiffies + HZ/25; | ||
483 | add_timer(&mcfrs_timer_struct); | ||
484 | } | ||
485 | |||
486 | #endif /* MCFPP_DCD0 */ | ||
487 | |||
488 | |||
489 | /* | ||
490 | * This routine is called from the scheduler tqueue when the interrupt | ||
491 | * routine has signalled that a hangup has occurred. The path of | ||
492 | * hangup processing is: | ||
493 | * | ||
494 | * serial interrupt routine -> (scheduler tqueue) -> | ||
495 | * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup() | ||
496 | * | ||
497 | */ | ||
498 | static void do_serial_hangup(struct work_struct *work) | ||
499 | { | ||
500 | struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup); | ||
501 | struct tty_struct *tty = info->port.tty; | ||
502 | |||
503 | if (tty) | ||
504 | tty_hangup(tty); | ||
505 | } | ||
506 | |||
507 | static int startup(struct mcf_serial * info) | ||
508 | { | ||
509 | volatile unsigned char *uartp; | ||
510 | unsigned long flags; | ||
511 | |||
512 | if (info->flags & ASYNC_INITIALIZED) | ||
513 | return 0; | ||
514 | |||
515 | if (!info->xmit_buf) { | ||
516 | info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); | ||
517 | if (!info->xmit_buf) | ||
518 | return -ENOMEM; | ||
519 | } | ||
520 | |||
521 | local_irq_save(flags); | ||
522 | |||
523 | #ifdef SERIAL_DEBUG_OPEN | ||
524 | printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); | ||
525 | #endif | ||
526 | |||
527 | /* | ||
528 | * Reset UART, get it into known state... | ||
529 | */ | ||
530 | uartp = info->addr; | ||
531 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ | ||
532 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ | ||
533 | mcfrs_setsignals(info, 1, 1); | ||
534 | |||
535 | if (info->port.tty) | ||
536 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
537 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
538 | |||
539 | /* | ||
540 | * and set the speed of the serial port | ||
541 | */ | ||
542 | mcfrs_change_speed(info); | ||
543 | |||
544 | /* | ||
545 | * Lastly enable the UART transmitter and receiver, and | ||
546 | * interrupt enables. | ||
547 | */ | ||
548 | info->imr = MCFUART_UIR_RXREADY; | ||
549 | uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; | ||
550 | uartp[MCFUART_UIMR] = info->imr; | ||
551 | |||
552 | info->flags |= ASYNC_INITIALIZED; | ||
553 | local_irq_restore(flags); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * This routine will shutdown a serial port; interrupts are disabled, and | ||
559 | * DTR is dropped if the hangup on close termio flag is on. | ||
560 | */ | ||
561 | static void shutdown(struct mcf_serial * info) | ||
562 | { | ||
563 | volatile unsigned char *uartp; | ||
564 | unsigned long flags; | ||
565 | |||
566 | if (!(info->flags & ASYNC_INITIALIZED)) | ||
567 | return; | ||
568 | |||
569 | #ifdef SERIAL_DEBUG_OPEN | ||
570 | printk("Shutting down serial port %d (irq %d)....\n", info->line, | ||
571 | info->irq); | ||
572 | #endif | ||
573 | |||
574 | local_irq_save(flags); | ||
575 | |||
576 | uartp = info->addr; | ||
577 | uartp[MCFUART_UIMR] = 0; /* mask all interrupts */ | ||
578 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ | ||
579 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ | ||
580 | |||
581 | if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) | ||
582 | mcfrs_setsignals(info, 0, 0); | ||
583 | |||
584 | if (info->xmit_buf) { | ||
585 | free_page((unsigned long) info->xmit_buf); | ||
586 | info->xmit_buf = 0; | ||
587 | } | ||
588 | |||
589 | if (info->port.tty) | ||
590 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
591 | |||
592 | info->flags &= ~ASYNC_INITIALIZED; | ||
593 | local_irq_restore(flags); | ||
594 | } | ||
595 | |||
596 | |||
597 | /* | ||
598 | * This routine is called to set the UART divisor registers to match | ||
599 | * the specified baud rate for a serial port. | ||
600 | */ | ||
601 | static void mcfrs_change_speed(struct mcf_serial *info) | ||
602 | { | ||
603 | volatile unsigned char *uartp; | ||
604 | unsigned int baudclk, cflag; | ||
605 | unsigned long flags; | ||
606 | unsigned char mr1, mr2; | ||
607 | int i; | ||
608 | #ifdef CONFIG_M5272 | ||
609 | unsigned int fraction; | ||
610 | #endif | ||
611 | |||
612 | if (!info->port.tty || !info->port.tty->termios) | ||
613 | return; | ||
614 | cflag = info->port.tty->termios->c_cflag; | ||
615 | if (info->addr == 0) | ||
616 | return; | ||
617 | |||
618 | #if 0 | ||
619 | printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__); | ||
620 | #endif | ||
621 | |||
622 | i = cflag & CBAUD; | ||
623 | if (i & CBAUDEX) { | ||
624 | i &= ~CBAUDEX; | ||
625 | if (i < 1 || i > 4) | ||
626 | info->port.tty->termios->c_cflag &= ~CBAUDEX; | ||
627 | else | ||
628 | i += 15; | ||
629 | } | ||
630 | if (i == 0) { | ||
631 | mcfrs_setsignals(info, 0, -1); | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | /* compute the baudrate clock */ | ||
636 | #ifdef CONFIG_M5272 | ||
637 | /* | ||
638 | * For the MCF5272, also compute the baudrate fraction. | ||
639 | */ | ||
640 | baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32; | ||
641 | fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]); | ||
642 | fraction *= 16; | ||
643 | fraction /= (32 * mcfrs_baud_table[i]); | ||
644 | #else | ||
645 | baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32; | ||
646 | #endif | ||
647 | |||
648 | info->baud = mcfrs_baud_table[i]; | ||
649 | |||
650 | mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; | ||
651 | mr2 = 0; | ||
652 | |||
653 | switch (cflag & CSIZE) { | ||
654 | case CS5: mr1 |= MCFUART_MR1_CS5; break; | ||
655 | case CS6: mr1 |= MCFUART_MR1_CS6; break; | ||
656 | case CS7: mr1 |= MCFUART_MR1_CS7; break; | ||
657 | case CS8: | ||
658 | default: mr1 |= MCFUART_MR1_CS8; break; | ||
659 | } | ||
660 | |||
661 | if (cflag & PARENB) { | ||
662 | if (cflag & CMSPAR) { | ||
663 | if (cflag & PARODD) | ||
664 | mr1 |= MCFUART_MR1_PARITYMARK; | ||
665 | else | ||
666 | mr1 |= MCFUART_MR1_PARITYSPACE; | ||
667 | } else { | ||
668 | if (cflag & PARODD) | ||
669 | mr1 |= MCFUART_MR1_PARITYODD; | ||
670 | else | ||
671 | mr1 |= MCFUART_MR1_PARITYEVEN; | ||
672 | } | ||
673 | } else { | ||
674 | mr1 |= MCFUART_MR1_PARITYNONE; | ||
675 | } | ||
676 | |||
677 | if (cflag & CSTOPB) | ||
678 | mr2 |= MCFUART_MR2_STOP2; | ||
679 | else | ||
680 | mr2 |= MCFUART_MR2_STOP1; | ||
681 | |||
682 | if (cflag & CRTSCTS) { | ||
683 | mr1 |= MCFUART_MR1_RXRTS; | ||
684 | mr2 |= MCFUART_MR2_TXCTS; | ||
685 | } | ||
686 | |||
687 | if (cflag & CLOCAL) | ||
688 | info->flags &= ~ASYNC_CHECK_CD; | ||
689 | else | ||
690 | info->flags |= ASYNC_CHECK_CD; | ||
691 | |||
692 | uartp = info->addr; | ||
693 | |||
694 | local_irq_save(flags); | ||
695 | #if 0 | ||
696 | printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__, | ||
697 | mr1, mr2, baudclk); | ||
698 | #endif | ||
699 | /* | ||
700 | Note: pg 12-16 of MCF5206e User's Manual states that a | ||
701 | software reset should be performed prior to changing | ||
702 | UMR1,2, UCSR, UACR, bit 7 | ||
703 | */ | ||
704 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ | ||
705 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ | ||
706 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ | ||
707 | uartp[MCFUART_UMR] = mr1; | ||
708 | uartp[MCFUART_UMR] = mr2; | ||
709 | uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */ | ||
710 | uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */ | ||
711 | #ifdef CONFIG_M5272 | ||
712 | uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ | ||
713 | #endif | ||
714 | uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; | ||
715 | uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; | ||
716 | mcfrs_setsignals(info, 1, -1); | ||
717 | local_irq_restore(flags); | ||
718 | return; | ||
719 | } | ||
720 | |||
721 | static void mcfrs_flush_chars(struct tty_struct *tty) | ||
722 | { | ||
723 | volatile unsigned char *uartp; | ||
724 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
725 | unsigned long flags; | ||
726 | |||
727 | if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars")) | ||
728 | return; | ||
729 | |||
730 | uartp = (volatile unsigned char *) info->addr; | ||
731 | |||
732 | /* | ||
733 | * re-enable receiver interrupt | ||
734 | */ | ||
735 | local_irq_save(flags); | ||
736 | if ((!(info->imr & MCFUART_UIR_RXREADY)) && | ||
737 | (info->flags & ASYNC_INITIALIZED) ) { | ||
738 | info->imr |= MCFUART_UIR_RXREADY; | ||
739 | uartp[MCFUART_UIMR] = info->imr; | ||
740 | } | ||
741 | local_irq_restore(flags); | ||
742 | |||
743 | if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || | ||
744 | !info->xmit_buf) | ||
745 | return; | ||
746 | |||
747 | /* Enable transmitter */ | ||
748 | local_irq_save(flags); | ||
749 | info->imr |= MCFUART_UIR_TXREADY; | ||
750 | uartp[MCFUART_UIMR] = info->imr; | ||
751 | local_irq_restore(flags); | ||
752 | } | ||
753 | |||
754 | static int mcfrs_write(struct tty_struct * tty, | ||
755 | const unsigned char *buf, int count) | ||
756 | { | ||
757 | volatile unsigned char *uartp; | ||
758 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
759 | unsigned long flags; | ||
760 | int c, total = 0; | ||
761 | |||
762 | #if 0 | ||
763 | printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n", | ||
764 | __FILE__, __LINE__, (int)tty, (int)buf, count); | ||
765 | #endif | ||
766 | |||
767 | if (serial_paranoia_check(info, tty->name, "mcfrs_write")) | ||
768 | return 0; | ||
769 | |||
770 | if (!tty || !info->xmit_buf) | ||
771 | return 0; | ||
772 | |||
773 | local_save_flags(flags); | ||
774 | while (1) { | ||
775 | local_irq_disable(); | ||
776 | c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1, | ||
777 | ((int)SERIAL_XMIT_SIZE) - info->xmit_head)); | ||
778 | local_irq_restore(flags); | ||
779 | |||
780 | if (c <= 0) | ||
781 | break; | ||
782 | |||
783 | memcpy(info->xmit_buf + info->xmit_head, buf, c); | ||
784 | |||
785 | local_irq_disable(); | ||
786 | info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); | ||
787 | info->xmit_cnt += c; | ||
788 | local_irq_restore(flags); | ||
789 | |||
790 | buf += c; | ||
791 | count -= c; | ||
792 | total += c; | ||
793 | } | ||
794 | |||
795 | local_irq_disable(); | ||
796 | uartp = info->addr; | ||
797 | info->imr |= MCFUART_UIR_TXREADY; | ||
798 | uartp[MCFUART_UIMR] = info->imr; | ||
799 | local_irq_restore(flags); | ||
800 | |||
801 | return total; | ||
802 | } | ||
803 | |||
804 | static int mcfrs_write_room(struct tty_struct *tty) | ||
805 | { | ||
806 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
807 | int ret; | ||
808 | |||
809 | if (serial_paranoia_check(info, tty->name, "mcfrs_write_room")) | ||
810 | return 0; | ||
811 | ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; | ||
812 | if (ret < 0) | ||
813 | ret = 0; | ||
814 | return ret; | ||
815 | } | ||
816 | |||
817 | static int mcfrs_chars_in_buffer(struct tty_struct *tty) | ||
818 | { | ||
819 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
820 | |||
821 | if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer")) | ||
822 | return 0; | ||
823 | return info->xmit_cnt; | ||
824 | } | ||
825 | |||
826 | static void mcfrs_flush_buffer(struct tty_struct *tty) | ||
827 | { | ||
828 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
829 | unsigned long flags; | ||
830 | |||
831 | if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer")) | ||
832 | return; | ||
833 | |||
834 | local_irq_save(flags); | ||
835 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
836 | local_irq_restore(flags); | ||
837 | |||
838 | tty_wakeup(tty); | ||
839 | } | ||
840 | |||
841 | /* | ||
842 | * ------------------------------------------------------------ | ||
843 | * mcfrs_throttle() | ||
844 | * | ||
845 | * This routine is called by the upper-layer tty layer to signal that | ||
846 | * incoming characters should be throttled. | ||
847 | * ------------------------------------------------------------ | ||
848 | */ | ||
849 | static void mcfrs_throttle(struct tty_struct * tty) | ||
850 | { | ||
851 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
852 | #ifdef SERIAL_DEBUG_THROTTLE | ||
853 | char buf[64]; | ||
854 | |||
855 | printk("throttle %s: %d....\n", tty_name(tty, buf), | ||
856 | tty->ldisc.chars_in_buffer(tty)); | ||
857 | #endif | ||
858 | |||
859 | if (serial_paranoia_check(info, tty->name, "mcfrs_throttle")) | ||
860 | return; | ||
861 | |||
862 | if (I_IXOFF(tty)) | ||
863 | info->x_char = STOP_CHAR(tty); | ||
864 | |||
865 | /* Turn off RTS line (do this atomic) */ | ||
866 | } | ||
867 | |||
868 | static void mcfrs_unthrottle(struct tty_struct * tty) | ||
869 | { | ||
870 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
871 | #ifdef SERIAL_DEBUG_THROTTLE | ||
872 | char buf[64]; | ||
873 | |||
874 | printk("unthrottle %s: %d....\n", tty_name(tty, buf), | ||
875 | tty->ldisc.chars_in_buffer(tty)); | ||
876 | #endif | ||
877 | |||
878 | if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle")) | ||
879 | return; | ||
880 | |||
881 | if (I_IXOFF(tty)) { | ||
882 | if (info->x_char) | ||
883 | info->x_char = 0; | ||
884 | else | ||
885 | info->x_char = START_CHAR(tty); | ||
886 | } | ||
887 | |||
888 | /* Assert RTS line (do this atomic) */ | ||
889 | } | ||
890 | |||
891 | /* | ||
892 | * ------------------------------------------------------------ | ||
893 | * mcfrs_ioctl() and friends | ||
894 | * ------------------------------------------------------------ | ||
895 | */ | ||
896 | |||
897 | static int get_serial_info(struct mcf_serial * info, | ||
898 | struct serial_struct * retinfo) | ||
899 | { | ||
900 | struct serial_struct tmp; | ||
901 | |||
902 | if (!retinfo) | ||
903 | return -EFAULT; | ||
904 | memset(&tmp, 0, sizeof(tmp)); | ||
905 | tmp.type = info->type; | ||
906 | tmp.line = info->line; | ||
907 | tmp.port = (unsigned int) info->addr; | ||
908 | tmp.irq = info->irq; | ||
909 | tmp.flags = info->flags; | ||
910 | tmp.baud_base = info->baud_base; | ||
911 | tmp.close_delay = info->close_delay; | ||
912 | tmp.closing_wait = info->closing_wait; | ||
913 | tmp.custom_divisor = info->custom_divisor; | ||
914 | return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0; | ||
915 | } | ||
916 | |||
917 | static int set_serial_info(struct mcf_serial * info, | ||
918 | struct serial_struct * new_info) | ||
919 | { | ||
920 | struct serial_struct new_serial; | ||
921 | struct mcf_serial old_info; | ||
922 | int retval = 0; | ||
923 | |||
924 | if (!new_info) | ||
925 | return -EFAULT; | ||
926 | if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) | ||
927 | return -EFAULT; | ||
928 | old_info = *info; | ||
929 | |||
930 | if (!capable(CAP_SYS_ADMIN)) { | ||
931 | if ((new_serial.baud_base != info->baud_base) || | ||
932 | (new_serial.type != info->type) || | ||
933 | (new_serial.close_delay != info->close_delay) || | ||
934 | ((new_serial.flags & ~ASYNC_USR_MASK) != | ||
935 | (info->flags & ~ASYNC_USR_MASK))) | ||
936 | return -EPERM; | ||
937 | info->flags = ((info->flags & ~ASYNC_USR_MASK) | | ||
938 | (new_serial.flags & ASYNC_USR_MASK)); | ||
939 | info->custom_divisor = new_serial.custom_divisor; | ||
940 | goto check_and_exit; | ||
941 | } | ||
942 | |||
943 | if (info->count > 1) | ||
944 | return -EBUSY; | ||
945 | |||
946 | /* | ||
947 | * OK, past this point, all the error checking has been done. | ||
948 | * At this point, we start making changes..... | ||
949 | */ | ||
950 | |||
951 | info->baud_base = new_serial.baud_base; | ||
952 | info->flags = ((info->flags & ~ASYNC_FLAGS) | | ||
953 | (new_serial.flags & ASYNC_FLAGS)); | ||
954 | info->type = new_serial.type; | ||
955 | info->close_delay = new_serial.close_delay; | ||
956 | info->closing_wait = new_serial.closing_wait; | ||
957 | |||
958 | check_and_exit: | ||
959 | retval = startup(info); | ||
960 | return retval; | ||
961 | } | ||
962 | |||
963 | /* | ||
964 | * get_lsr_info - get line status register info | ||
965 | * | ||
966 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
967 | * is emptied. On bus types like RS485, the transmitter must | ||
968 | * release the bus after transmitting. This must be done when | ||
969 | * the transmit shift register is empty, not be done when the | ||
970 | * transmit holding register is empty. This functionality | ||
971 | * allows an RS485 driver to be written in user space. | ||
972 | */ | ||
973 | static int get_lsr_info(struct mcf_serial * info, unsigned int *value) | ||
974 | { | ||
975 | volatile unsigned char *uartp; | ||
976 | unsigned long flags; | ||
977 | unsigned char status; | ||
978 | |||
979 | local_irq_save(flags); | ||
980 | uartp = info->addr; | ||
981 | status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0; | ||
982 | local_irq_restore(flags); | ||
983 | |||
984 | return put_user(status,value); | ||
985 | } | ||
986 | |||
987 | /* | ||
988 | * This routine sends a break character out the serial port. | ||
989 | */ | ||
990 | static void send_break( struct mcf_serial * info, int duration) | ||
991 | { | ||
992 | volatile unsigned char *uartp; | ||
993 | unsigned long flags; | ||
994 | |||
995 | if (!info->addr) | ||
996 | return; | ||
997 | set_current_state(TASK_INTERRUPTIBLE); | ||
998 | uartp = info->addr; | ||
999 | |||
1000 | local_irq_save(flags); | ||
1001 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART; | ||
1002 | schedule_timeout(duration); | ||
1003 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP; | ||
1004 | local_irq_restore(flags); | ||
1005 | } | ||
1006 | |||
1007 | static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file) | ||
1008 | { | ||
1009 | struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; | ||
1010 | |||
1011 | if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) | ||
1012 | return -ENODEV; | ||
1013 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1014 | return -EIO; | ||
1015 | |||
1016 | return mcfrs_getsignals(info); | ||
1017 | } | ||
1018 | |||
1019 | static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file, | ||
1020 | unsigned int set, unsigned int clear) | ||
1021 | { | ||
1022 | struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; | ||
1023 | int rts = -1, dtr = -1; | ||
1024 | |||
1025 | if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) | ||
1026 | return -ENODEV; | ||
1027 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1028 | return -EIO; | ||
1029 | |||
1030 | if (set & TIOCM_RTS) | ||
1031 | rts = 1; | ||
1032 | if (set & TIOCM_DTR) | ||
1033 | dtr = 1; | ||
1034 | if (clear & TIOCM_RTS) | ||
1035 | rts = 0; | ||
1036 | if (clear & TIOCM_DTR) | ||
1037 | dtr = 0; | ||
1038 | |||
1039 | mcfrs_setsignals(info, dtr, rts); | ||
1040 | |||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, | ||
1045 | unsigned int cmd, unsigned long arg) | ||
1046 | { | ||
1047 | struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; | ||
1048 | int retval, error; | ||
1049 | |||
1050 | if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) | ||
1051 | return -ENODEV; | ||
1052 | |||
1053 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||
1054 | (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && | ||
1055 | (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { | ||
1056 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1057 | return -EIO; | ||
1058 | } | ||
1059 | |||
1060 | switch (cmd) { | ||
1061 | case TCSBRK: /* SVID version: non-zero arg --> no break */ | ||
1062 | retval = tty_check_change(tty); | ||
1063 | if (retval) | ||
1064 | return retval; | ||
1065 | tty_wait_until_sent(tty, 0); | ||
1066 | if (!arg) | ||
1067 | send_break(info, HZ/4); /* 1/4 second */ | ||
1068 | return 0; | ||
1069 | case TCSBRKP: /* support for POSIX tcsendbreak() */ | ||
1070 | retval = tty_check_change(tty); | ||
1071 | if (retval) | ||
1072 | return retval; | ||
1073 | tty_wait_until_sent(tty, 0); | ||
1074 | send_break(info, arg ? arg*(HZ/10) : HZ/4); | ||
1075 | return 0; | ||
1076 | case TIOCGSERIAL: | ||
1077 | if (access_ok(VERIFY_WRITE, (void *) arg, | ||
1078 | sizeof(struct serial_struct))) | ||
1079 | return get_serial_info(info, | ||
1080 | (struct serial_struct *) arg); | ||
1081 | return -EFAULT; | ||
1082 | case TIOCSSERIAL: | ||
1083 | return set_serial_info(info, | ||
1084 | (struct serial_struct *) arg); | ||
1085 | case TIOCSERGETLSR: /* Get line status register */ | ||
1086 | if (access_ok(VERIFY_WRITE, (void *) arg, | ||
1087 | sizeof(unsigned int))) | ||
1088 | return get_lsr_info(info, (unsigned int *) arg); | ||
1089 | return -EFAULT; | ||
1090 | case TIOCSERGSTRUCT: | ||
1091 | error = copy_to_user((struct mcf_serial *) arg, | ||
1092 | info, sizeof(struct mcf_serial)); | ||
1093 | if (error) | ||
1094 | return -EFAULT; | ||
1095 | return 0; | ||
1096 | |||
1097 | #ifdef TIOCSET422 | ||
1098 | case TIOCSET422: { | ||
1099 | unsigned int val; | ||
1100 | get_user(val, (unsigned int *) arg); | ||
1101 | mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11)); | ||
1102 | break; | ||
1103 | } | ||
1104 | case TIOCGET422: { | ||
1105 | unsigned int val; | ||
1106 | val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1; | ||
1107 | put_user(val, (unsigned int *) arg); | ||
1108 | break; | ||
1109 | } | ||
1110 | #endif | ||
1111 | |||
1112 | default: | ||
1113 | return -ENOIOCTLCMD; | ||
1114 | } | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
1119 | { | ||
1120 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
1121 | |||
1122 | if (tty->termios->c_cflag == old_termios->c_cflag) | ||
1123 | return; | ||
1124 | |||
1125 | mcfrs_change_speed(info); | ||
1126 | |||
1127 | if ((old_termios->c_cflag & CRTSCTS) && | ||
1128 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
1129 | tty->hw_stopped = 0; | ||
1130 | mcfrs_setsignals(info, -1, 1); | ||
1131 | #if 0 | ||
1132 | mcfrs_start(tty); | ||
1133 | #endif | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | /* | ||
1138 | * ------------------------------------------------------------ | ||
1139 | * mcfrs_close() | ||
1140 | * | ||
1141 | * This routine is called when the serial port gets closed. First, we | ||
1142 | * wait for the last remaining data to be sent. Then, we unlink its | ||
1143 | * S structure from the interrupt chain if necessary, and we free | ||
1144 | * that IRQ if nothing is left in the chain. | ||
1145 | * ------------------------------------------------------------ | ||
1146 | */ | ||
1147 | static void mcfrs_close(struct tty_struct *tty, struct file * filp) | ||
1148 | { | ||
1149 | volatile unsigned char *uartp; | ||
1150 | struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; | ||
1151 | unsigned long flags; | ||
1152 | |||
1153 | if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close")) | ||
1154 | return; | ||
1155 | |||
1156 | local_irq_save(flags); | ||
1157 | |||
1158 | if (tty_hung_up_p(filp)) { | ||
1159 | local_irq_restore(flags); | ||
1160 | return; | ||
1161 | } | ||
1162 | |||
1163 | #ifdef SERIAL_DEBUG_OPEN | ||
1164 | printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count); | ||
1165 | #endif | ||
1166 | if ((tty->count == 1) && (info->count != 1)) { | ||
1167 | /* | ||
1168 | * Uh, oh. tty->count is 1, which means that the tty | ||
1169 | * structure will be freed. Info->count should always | ||
1170 | * be one in these conditions. If it's greater than | ||
1171 | * one, we've got real problems, since it means the | ||
1172 | * serial port won't be shutdown. | ||
1173 | */ | ||
1174 | printk("MCFRS: bad serial port count; tty->count is 1, " | ||
1175 | "info->count is %d\n", info->count); | ||
1176 | info->count = 1; | ||
1177 | } | ||
1178 | if (--info->count < 0) { | ||
1179 | printk("MCFRS: bad serial port count for ttyS%d: %d\n", | ||
1180 | info->line, info->count); | ||
1181 | info->count = 0; | ||
1182 | } | ||
1183 | if (info->count) { | ||
1184 | local_irq_restore(flags); | ||
1185 | return; | ||
1186 | } | ||
1187 | info->flags |= ASYNC_CLOSING; | ||
1188 | |||
1189 | /* | ||
1190 | * Now we wait for the transmit buffer to clear; and we notify | ||
1191 | * the line discipline to only process XON/XOFF characters. | ||
1192 | */ | ||
1193 | tty->closing = 1; | ||
1194 | if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) | ||
1195 | tty_wait_until_sent(tty, info->closing_wait); | ||
1196 | |||
1197 | /* | ||
1198 | * At this point we stop accepting input. To do this, we | ||
1199 | * disable the receive line status interrupts, and tell the | ||
1200 | * interrupt driver to stop checking the data ready bit in the | ||
1201 | * line status register. | ||
1202 | */ | ||
1203 | info->imr &= ~MCFUART_UIR_RXREADY; | ||
1204 | uartp = info->addr; | ||
1205 | uartp[MCFUART_UIMR] = info->imr; | ||
1206 | |||
1207 | #if 0 | ||
1208 | /* FIXME: do we need to keep this enabled for console?? */ | ||
1209 | if (mcfrs_console_inited && (mcfrs_console_port == info->line)) { | ||
1210 | /* Do not disable the UART */ ; | ||
1211 | } else | ||
1212 | #endif | ||
1213 | shutdown(info); | ||
1214 | mcfrs_flush_buffer(tty); | ||
1215 | tty_ldisc_flush(tty); | ||
1216 | |||
1217 | tty->closing = 0; | ||
1218 | info->event = 0; | ||
1219 | info->port.tty = NULL; | ||
1220 | #if 0 | ||
1221 | if (tty->ldisc.num != ldiscs[N_TTY].num) { | ||
1222 | if (tty->ldisc.close) | ||
1223 | (tty->ldisc.close)(tty); | ||
1224 | tty->ldisc = ldiscs[N_TTY]; | ||
1225 | tty->termios->c_line = N_TTY; | ||
1226 | if (tty->ldisc.open) | ||
1227 | (tty->ldisc.open)(tty); | ||
1228 | } | ||
1229 | #endif | ||
1230 | if (info->blocked_open) { | ||
1231 | if (info->close_delay) { | ||
1232 | msleep_interruptible(jiffies_to_msecs(info->close_delay)); | ||
1233 | } | ||
1234 | wake_up_interruptible(&info->open_wait); | ||
1235 | } | ||
1236 | info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); | ||
1237 | wake_up_interruptible(&info->close_wait); | ||
1238 | local_irq_restore(flags); | ||
1239 | } | ||
1240 | |||
1241 | /* | ||
1242 | * mcfrs_wait_until_sent() --- wait until the transmitter is empty | ||
1243 | */ | ||
1244 | static void | ||
1245 | mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) | ||
1246 | { | ||
1247 | #ifdef CONFIG_M5272 | ||
1248 | #define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */ | ||
1249 | |||
1250 | struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; | ||
1251 | volatile unsigned char *uartp; | ||
1252 | unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt; | ||
1253 | |||
1254 | if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent")) | ||
1255 | return; | ||
1256 | |||
1257 | orig_jiffies = jiffies; | ||
1258 | |||
1259 | /* | ||
1260 | * Set the check interval to be 1/5 of the approximate time | ||
1261 | * to send the entire fifo, and make it at least 1. The check | ||
1262 | * interval should also be less than the timeout. | ||
1263 | * | ||
1264 | * Note: we have to use pretty tight timings here to satisfy | ||
1265 | * the NIST-PCTS. | ||
1266 | */ | ||
1267 | lock_kernel(); | ||
1268 | |||
1269 | fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud; | ||
1270 | char_time = fifo_time / 5; | ||
1271 | if (char_time == 0) | ||
1272 | char_time = 1; | ||
1273 | if (timeout && timeout < char_time) | ||
1274 | char_time = timeout; | ||
1275 | |||
1276 | /* | ||
1277 | * Clamp the timeout period at 2 * the time to empty the | ||
1278 | * fifo. Just to be safe, set the minimum at .5 seconds. | ||
1279 | */ | ||
1280 | fifo_time *= 2; | ||
1281 | if (fifo_time < (HZ/2)) | ||
1282 | fifo_time = HZ/2; | ||
1283 | if (!timeout || timeout > fifo_time) | ||
1284 | timeout = fifo_time; | ||
1285 | |||
1286 | /* | ||
1287 | * Account for the number of bytes in the UART | ||
1288 | * transmitter FIFO plus any byte being shifted out. | ||
1289 | */ | ||
1290 | uartp = (volatile unsigned char *) info->addr; | ||
1291 | for (;;) { | ||
1292 | fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB); | ||
1293 | if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY| | ||
1294 | MCFUART_USR_TXEMPTY)) == | ||
1295 | MCFUART_USR_TXREADY) | ||
1296 | fifo_cnt++; | ||
1297 | if (fifo_cnt == 0) | ||
1298 | break; | ||
1299 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
1300 | if (signal_pending(current)) | ||
1301 | break; | ||
1302 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
1303 | break; | ||
1304 | } | ||
1305 | unlock_kernel(); | ||
1306 | #else | ||
1307 | /* | ||
1308 | * For the other coldfire models, assume all data has been sent | ||
1309 | */ | ||
1310 | #endif | ||
1311 | } | ||
1312 | |||
1313 | /* | ||
1314 | * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled. | ||
1315 | */ | ||
1316 | void mcfrs_hangup(struct tty_struct *tty) | ||
1317 | { | ||
1318 | struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; | ||
1319 | |||
1320 | if (serial_paranoia_check(info, tty->name, "mcfrs_hangup")) | ||
1321 | return; | ||
1322 | |||
1323 | mcfrs_flush_buffer(tty); | ||
1324 | shutdown(info); | ||
1325 | info->event = 0; | ||
1326 | info->count = 0; | ||
1327 | info->flags &= ~ASYNC_NORMAL_ACTIVE; | ||
1328 | info->port.tty = NULL; | ||
1329 | wake_up_interruptible(&info->open_wait); | ||
1330 | } | ||
1331 | |||
1332 | /* | ||
1333 | * ------------------------------------------------------------ | ||
1334 | * mcfrs_open() and friends | ||
1335 | * ------------------------------------------------------------ | ||
1336 | */ | ||
1337 | static int block_til_ready(struct tty_struct *tty, struct file * filp, | ||
1338 | struct mcf_serial *info) | ||
1339 | { | ||
1340 | DECLARE_WAITQUEUE(wait, current); | ||
1341 | int retval; | ||
1342 | int do_clocal = 0; | ||
1343 | |||
1344 | /* | ||
1345 | * If the device is in the middle of being closed, then block | ||
1346 | * until it's done, and then try again. | ||
1347 | */ | ||
1348 | if (info->flags & ASYNC_CLOSING) { | ||
1349 | interruptible_sleep_on(&info->close_wait); | ||
1350 | #ifdef SERIAL_DO_RESTART | ||
1351 | if (info->flags & ASYNC_HUP_NOTIFY) | ||
1352 | return -EAGAIN; | ||
1353 | else | ||
1354 | return -ERESTARTSYS; | ||
1355 | #else | ||
1356 | return -EAGAIN; | ||
1357 | #endif | ||
1358 | } | ||
1359 | |||
1360 | /* | ||
1361 | * If non-blocking mode is set, or the port is not enabled, | ||
1362 | * then make the check up front and then exit. | ||
1363 | */ | ||
1364 | if ((filp->f_flags & O_NONBLOCK) || | ||
1365 | (tty->flags & (1 << TTY_IO_ERROR))) { | ||
1366 | info->flags |= ASYNC_NORMAL_ACTIVE; | ||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | if (tty->termios->c_cflag & CLOCAL) | ||
1371 | do_clocal = 1; | ||
1372 | |||
1373 | /* | ||
1374 | * Block waiting for the carrier detect and the line to become | ||
1375 | * free (i.e., not in use by the callout). While we are in | ||
1376 | * this loop, info->count is dropped by one, so that | ||
1377 | * mcfrs_close() knows when to free things. We restore it upon | ||
1378 | * exit, either normal or abnormal. | ||
1379 | */ | ||
1380 | retval = 0; | ||
1381 | add_wait_queue(&info->open_wait, &wait); | ||
1382 | #ifdef SERIAL_DEBUG_OPEN | ||
1383 | printk("block_til_ready before block: ttyS%d, count = %d\n", | ||
1384 | info->line, info->count); | ||
1385 | #endif | ||
1386 | info->count--; | ||
1387 | info->blocked_open++; | ||
1388 | while (1) { | ||
1389 | local_irq_disable(); | ||
1390 | mcfrs_setsignals(info, 1, 1); | ||
1391 | local_irq_enable(); | ||
1392 | current->state = TASK_INTERRUPTIBLE; | ||
1393 | if (tty_hung_up_p(filp) || | ||
1394 | !(info->flags & ASYNC_INITIALIZED)) { | ||
1395 | #ifdef SERIAL_DO_RESTART | ||
1396 | if (info->flags & ASYNC_HUP_NOTIFY) | ||
1397 | retval = -EAGAIN; | ||
1398 | else | ||
1399 | retval = -ERESTARTSYS; | ||
1400 | #else | ||
1401 | retval = -EAGAIN; | ||
1402 | #endif | ||
1403 | break; | ||
1404 | } | ||
1405 | if (!(info->flags & ASYNC_CLOSING) && | ||
1406 | (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD))) | ||
1407 | break; | ||
1408 | if (signal_pending(current)) { | ||
1409 | retval = -ERESTARTSYS; | ||
1410 | break; | ||
1411 | } | ||
1412 | #ifdef SERIAL_DEBUG_OPEN | ||
1413 | printk("block_til_ready blocking: ttyS%d, count = %d\n", | ||
1414 | info->line, info->count); | ||
1415 | #endif | ||
1416 | schedule(); | ||
1417 | } | ||
1418 | current->state = TASK_RUNNING; | ||
1419 | remove_wait_queue(&info->open_wait, &wait); | ||
1420 | if (!tty_hung_up_p(filp)) | ||
1421 | info->count++; | ||
1422 | info->blocked_open--; | ||
1423 | #ifdef SERIAL_DEBUG_OPEN | ||
1424 | printk("block_til_ready after blocking: ttyS%d, count = %d\n", | ||
1425 | info->line, info->count); | ||
1426 | #endif | ||
1427 | if (retval) | ||
1428 | return retval; | ||
1429 | info->flags |= ASYNC_NORMAL_ACTIVE; | ||
1430 | return 0; | ||
1431 | } | ||
1432 | |||
1433 | /* | ||
1434 | * This routine is called whenever a serial port is opened. It | ||
1435 | * enables interrupts for a serial port, linking in its structure into | ||
1436 | * the IRQ chain. It also performs the serial-specific | ||
1437 | * initialization for the tty structure. | ||
1438 | */ | ||
1439 | int mcfrs_open(struct tty_struct *tty, struct file * filp) | ||
1440 | { | ||
1441 | struct mcf_serial *info; | ||
1442 | int retval, line; | ||
1443 | |||
1444 | line = tty->index; | ||
1445 | if ((line < 0) || (line >= NR_PORTS)) | ||
1446 | return -ENODEV; | ||
1447 | info = mcfrs_table + line; | ||
1448 | if (serial_paranoia_check(info, tty->name, "mcfrs_open")) | ||
1449 | return -ENODEV; | ||
1450 | #ifdef SERIAL_DEBUG_OPEN | ||
1451 | printk("mcfrs_open %s, count = %d\n", tty->name, info->count); | ||
1452 | #endif | ||
1453 | info->count++; | ||
1454 | tty->driver_data = info; | ||
1455 | info->port.tty = tty; | ||
1456 | |||
1457 | /* | ||
1458 | * Start up serial port | ||
1459 | */ | ||
1460 | retval = startup(info); | ||
1461 | if (retval) | ||
1462 | return retval; | ||
1463 | |||
1464 | retval = block_til_ready(tty, filp, info); | ||
1465 | if (retval) { | ||
1466 | #ifdef SERIAL_DEBUG_OPEN | ||
1467 | printk("mcfrs_open returning after block_til_ready with %d\n", | ||
1468 | retval); | ||
1469 | #endif | ||
1470 | return retval; | ||
1471 | } | ||
1472 | |||
1473 | #ifdef SERIAL_DEBUG_OPEN | ||
1474 | printk("mcfrs_open %s successful...\n", tty->name); | ||
1475 | #endif | ||
1476 | return 0; | ||
1477 | } | ||
1478 | |||
1479 | /* | ||
1480 | * Based on the line number set up the internal interrupt stuff. | ||
1481 | */ | ||
1482 | static void mcfrs_irqinit(struct mcf_serial *info) | ||
1483 | { | ||
1484 | #if defined(CONFIG_M5272) | ||
1485 | volatile unsigned long *icrp; | ||
1486 | volatile unsigned long *portp; | ||
1487 | volatile unsigned char *uartp; | ||
1488 | |||
1489 | uartp = info->addr; | ||
1490 | icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); | ||
1491 | |||
1492 | switch (info->line) { | ||
1493 | case 0: | ||
1494 | *icrp = 0xe0000000; | ||
1495 | break; | ||
1496 | case 1: | ||
1497 | *icrp = 0x0e000000; | ||
1498 | break; | ||
1499 | default: | ||
1500 | printk("MCFRS: don't know how to handle UART %d interrupt?\n", | ||
1501 | info->line); | ||
1502 | return; | ||
1503 | } | ||
1504 | |||
1505 | /* Enable the output lines for the serial ports */ | ||
1506 | portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT); | ||
1507 | *portp = (*portp & ~0x000000ff) | 0x00000055; | ||
1508 | portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); | ||
1509 | *portp = (*portp & ~0x000003fc) | 0x000002a8; | ||
1510 | #elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) | ||
1511 | volatile unsigned char *icrp, *uartp; | ||
1512 | volatile unsigned long *imrp; | ||
1513 | |||
1514 | uartp = info->addr; | ||
1515 | |||
1516 | icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + | ||
1517 | MCFINTC_ICR0 + MCFINT_UART0 + info->line); | ||
1518 | *icrp = 0x30 + info->line; /* level 6, line based priority */ | ||
1519 | |||
1520 | imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + | ||
1521 | MCFINTC_IMRL); | ||
1522 | *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); | ||
1523 | #if defined(CONFIG_M527x) | ||
1524 | { | ||
1525 | /* | ||
1526 | * External Pin Mask Setting & Enable External Pin for Interface | ||
1527 | * mrcbis@aliceposta.it | ||
1528 | */ | ||
1529 | u16 *serpin_enable_mask; | ||
1530 | serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART); | ||
1531 | if (info->line == 0) | ||
1532 | *serpin_enable_mask |= UART0_ENABLE_MASK; | ||
1533 | else if (info->line == 1) | ||
1534 | *serpin_enable_mask |= UART1_ENABLE_MASK; | ||
1535 | else if (info->line == 2) | ||
1536 | *serpin_enable_mask |= UART2_ENABLE_MASK; | ||
1537 | } | ||
1538 | #endif | ||
1539 | #if defined(CONFIG_M528x) | ||
1540 | /* make sure PUAPAR is set for UART0 and UART1 */ | ||
1541 | if (info->line < 2) { | ||
1542 | volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR); | ||
1543 | *portp |= (0x03 << (info->line * 2)); | ||
1544 | } | ||
1545 | #endif | ||
1546 | #elif defined(CONFIG_M520x) | ||
1547 | volatile unsigned char *icrp, *uartp; | ||
1548 | volatile unsigned long *imrp; | ||
1549 | |||
1550 | uartp = info->addr; | ||
1551 | |||
1552 | icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + | ||
1553 | MCFINTC_ICR0 + MCFINT_UART0 + info->line); | ||
1554 | *icrp = 0x03; | ||
1555 | |||
1556 | imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + | ||
1557 | MCFINTC_IMRL); | ||
1558 | *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); | ||
1559 | if (info->line < 2) { | ||
1560 | unsigned short *uart_par; | ||
1561 | uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART); | ||
1562 | if (info->line == 0) | ||
1563 | *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | ||
1564 | | MCF_GPIO_PAR_UART_PAR_URXD0; | ||
1565 | else if (info->line == 1) | ||
1566 | *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | ||
1567 | | MCF_GPIO_PAR_UART_PAR_URXD1; | ||
1568 | } else if (info->line == 2) { | ||
1569 | unsigned char *feci2c_par; | ||
1570 | feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); | ||
1571 | *feci2c_par &= ~0x0F; | ||
1572 | *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | ||
1573 | | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; | ||
1574 | } | ||
1575 | #elif defined(CONFIG_M532x) | ||
1576 | volatile unsigned char *uartp; | ||
1577 | uartp = info->addr; | ||
1578 | switch (info->line) { | ||
1579 | case 0: | ||
1580 | MCF_INTC0_ICR26 = 0x3; | ||
1581 | MCF_INTC0_CIMR = 26; | ||
1582 | /* GPIO initialization */ | ||
1583 | MCF_GPIO_PAR_UART |= 0x000F; | ||
1584 | break; | ||
1585 | case 1: | ||
1586 | MCF_INTC0_ICR27 = 0x3; | ||
1587 | MCF_INTC0_CIMR = 27; | ||
1588 | /* GPIO initialization */ | ||
1589 | MCF_GPIO_PAR_UART |= 0x0FF0; | ||
1590 | break; | ||
1591 | case 2: | ||
1592 | MCF_INTC0_ICR28 = 0x3; | ||
1593 | MCF_INTC0_CIMR = 28; | ||
1594 | /* GPIOs also must be initalized, depends on board */ | ||
1595 | break; | ||
1596 | } | ||
1597 | #else | ||
1598 | volatile unsigned char *icrp, *uartp; | ||
1599 | |||
1600 | switch (info->line) { | ||
1601 | case 0: | ||
1602 | icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR); | ||
1603 | *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | | ||
1604 | MCFSIM_ICR_PRI1; | ||
1605 | mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); | ||
1606 | break; | ||
1607 | case 1: | ||
1608 | icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR); | ||
1609 | *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | | ||
1610 | MCFSIM_ICR_PRI2; | ||
1611 | mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); | ||
1612 | break; | ||
1613 | default: | ||
1614 | printk("MCFRS: don't know how to handle UART %d interrupt?\n", | ||
1615 | info->line); | ||
1616 | return; | ||
1617 | } | ||
1618 | |||
1619 | uartp = info->addr; | ||
1620 | uartp[MCFUART_UIVR] = info->irq; | ||
1621 | #endif | ||
1622 | |||
1623 | /* Clear mask, so no surprise interrupts. */ | ||
1624 | uartp[MCFUART_UIMR] = 0; | ||
1625 | |||
1626 | if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED, | ||
1627 | "ColdFire UART", NULL)) { | ||
1628 | printk("MCFRS: Unable to attach ColdFire UART %d interrupt " | ||
1629 | "vector=%d\n", info->line, info->irq); | ||
1630 | } | ||
1631 | |||
1632 | return; | ||
1633 | } | ||
1634 | |||
1635 | |||
1636 | char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n"; | ||
1637 | |||
1638 | |||
1639 | /* | ||
1640 | * Serial stats reporting... | ||
1641 | */ | ||
1642 | int mcfrs_readproc(char *page, char **start, off_t off, int count, | ||
1643 | int *eof, void *data) | ||
1644 | { | ||
1645 | struct mcf_serial *info; | ||
1646 | char str[20]; | ||
1647 | int len, sigs, i; | ||
1648 | |||
1649 | len = sprintf(page, mcfrs_drivername); | ||
1650 | for (i = 0; (i < NR_PORTS); i++) { | ||
1651 | info = &mcfrs_table[i]; | ||
1652 | len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ", | ||
1653 | i, (unsigned int) info->addr, info->irq, info->baud); | ||
1654 | if (info->stats.rx || info->stats.tx) | ||
1655 | len += sprintf((page + len), "tx:%d rx:%d ", | ||
1656 | info->stats.tx, info->stats.rx); | ||
1657 | if (info->stats.rxframing) | ||
1658 | len += sprintf((page + len), "fe:%d ", | ||
1659 | info->stats.rxframing); | ||
1660 | if (info->stats.rxparity) | ||
1661 | len += sprintf((page + len), "pe:%d ", | ||
1662 | info->stats.rxparity); | ||
1663 | if (info->stats.rxbreak) | ||
1664 | len += sprintf((page + len), "brk:%d ", | ||
1665 | info->stats.rxbreak); | ||
1666 | if (info->stats.rxoverrun) | ||
1667 | len += sprintf((page + len), "oe:%d ", | ||
1668 | info->stats.rxoverrun); | ||
1669 | |||
1670 | str[0] = str[1] = 0; | ||
1671 | if ((sigs = mcfrs_getsignals(info))) { | ||
1672 | if (sigs & TIOCM_RTS) | ||
1673 | strcat(str, "|RTS"); | ||
1674 | if (sigs & TIOCM_CTS) | ||
1675 | strcat(str, "|CTS"); | ||
1676 | if (sigs & TIOCM_DTR) | ||
1677 | strcat(str, "|DTR"); | ||
1678 | if (sigs & TIOCM_CD) | ||
1679 | strcat(str, "|CD"); | ||
1680 | } | ||
1681 | |||
1682 | len += sprintf((page + len), "%s\n", &str[1]); | ||
1683 | } | ||
1684 | |||
1685 | return(len); | ||
1686 | } | ||
1687 | |||
1688 | |||
1689 | /* Finally, routines used to initialize the serial driver. */ | ||
1690 | |||
1691 | static void show_serial_version(void) | ||
1692 | { | ||
1693 | printk(mcfrs_drivername); | ||
1694 | } | ||
1695 | |||
1696 | static const struct tty_operations mcfrs_ops = { | ||
1697 | .open = mcfrs_open, | ||
1698 | .close = mcfrs_close, | ||
1699 | .write = mcfrs_write, | ||
1700 | .flush_chars = mcfrs_flush_chars, | ||
1701 | .write_room = mcfrs_write_room, | ||
1702 | .chars_in_buffer = mcfrs_chars_in_buffer, | ||
1703 | .flush_buffer = mcfrs_flush_buffer, | ||
1704 | .ioctl = mcfrs_ioctl, | ||
1705 | .throttle = mcfrs_throttle, | ||
1706 | .unthrottle = mcfrs_unthrottle, | ||
1707 | .set_termios = mcfrs_set_termios, | ||
1708 | .stop = mcfrs_stop, | ||
1709 | .start = mcfrs_start, | ||
1710 | .hangup = mcfrs_hangup, | ||
1711 | .read_proc = mcfrs_readproc, | ||
1712 | .wait_until_sent = mcfrs_wait_until_sent, | ||
1713 | .tiocmget = mcfrs_tiocmget, | ||
1714 | .tiocmset = mcfrs_tiocmset, | ||
1715 | }; | ||
1716 | |||
1717 | /* mcfrs_init inits the driver */ | ||
1718 | static int __init | ||
1719 | mcfrs_init(void) | ||
1720 | { | ||
1721 | struct mcf_serial *info; | ||
1722 | unsigned long flags; | ||
1723 | int i; | ||
1724 | |||
1725 | /* Setup base handler, and timer table. */ | ||
1726 | #ifdef MCFPP_DCD0 | ||
1727 | init_timer(&mcfrs_timer_struct); | ||
1728 | mcfrs_timer_struct.function = mcfrs_timer; | ||
1729 | mcfrs_timer_struct.data = 0; | ||
1730 | mcfrs_timer_struct.expires = jiffies + HZ/25; | ||
1731 | add_timer(&mcfrs_timer_struct); | ||
1732 | mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); | ||
1733 | #endif | ||
1734 | mcfrs_serial_driver = alloc_tty_driver(NR_PORTS); | ||
1735 | if (!mcfrs_serial_driver) | ||
1736 | return -ENOMEM; | ||
1737 | |||
1738 | show_serial_version(); | ||
1739 | |||
1740 | /* Initialize the tty_driver structure */ | ||
1741 | mcfrs_serial_driver->owner = THIS_MODULE; | ||
1742 | mcfrs_serial_driver->name = "ttyS"; | ||
1743 | mcfrs_serial_driver->driver_name = "mcfserial"; | ||
1744 | mcfrs_serial_driver->major = TTY_MAJOR; | ||
1745 | mcfrs_serial_driver->minor_start = 64; | ||
1746 | mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
1747 | mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL; | ||
1748 | mcfrs_serial_driver->init_termios = tty_std_termios; | ||
1749 | |||
1750 | mcfrs_serial_driver->init_termios.c_cflag = | ||
1751 | mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; | ||
1752 | mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW; | ||
1753 | |||
1754 | tty_set_operations(mcfrs_serial_driver, &mcfrs_ops); | ||
1755 | |||
1756 | if (tty_register_driver(mcfrs_serial_driver)) { | ||
1757 | printk("MCFRS: Couldn't register serial driver\n"); | ||
1758 | put_tty_driver(mcfrs_serial_driver); | ||
1759 | return(-EBUSY); | ||
1760 | } | ||
1761 | |||
1762 | local_irq_save(flags); | ||
1763 | |||
1764 | /* | ||
1765 | * Configure all the attached serial ports. | ||
1766 | */ | ||
1767 | for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { | ||
1768 | info->magic = SERIAL_MAGIC; | ||
1769 | info->line = i; | ||
1770 | info->port.tty = NULL; | ||
1771 | info->custom_divisor = 16; | ||
1772 | info->close_delay = 50; | ||
1773 | info->closing_wait = 3000; | ||
1774 | info->x_char = 0; | ||
1775 | info->event = 0; | ||
1776 | info->count = 0; | ||
1777 | info->blocked_open = 0; | ||
1778 | INIT_WORK(&info->tqueue, mcfrs_offintr); | ||
1779 | INIT_WORK(&info->tqueue_hangup, do_serial_hangup); | ||
1780 | init_waitqueue_head(&info->open_wait); | ||
1781 | init_waitqueue_head(&info->close_wait); | ||
1782 | |||
1783 | info->imr = 0; | ||
1784 | mcfrs_setsignals(info, 0, 0); | ||
1785 | mcfrs_irqinit(info); | ||
1786 | |||
1787 | printk("ttyS%d at 0x%04x (irq = %d)", info->line, | ||
1788 | (unsigned int) info->addr, info->irq); | ||
1789 | printk(" is a builtin ColdFire UART\n"); | ||
1790 | } | ||
1791 | |||
1792 | local_irq_restore(flags); | ||
1793 | return 0; | ||
1794 | } | ||
1795 | |||
1796 | module_init(mcfrs_init); | ||
1797 | |||
1798 | /****************************************************************************/ | ||
1799 | /* Serial Console */ | ||
1800 | /****************************************************************************/ | ||
1801 | |||
1802 | /* | ||
1803 | * Quick and dirty UART initialization, for console output. | ||
1804 | */ | ||
1805 | |||
1806 | void mcfrs_init_console(void) | ||
1807 | { | ||
1808 | volatile unsigned char *uartp; | ||
1809 | unsigned int clk; | ||
1810 | |||
1811 | /* | ||
1812 | * Reset UART, get it into known state... | ||
1813 | */ | ||
1814 | uartp = (volatile unsigned char *) (MCF_MBAR + | ||
1815 | (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); | ||
1816 | |||
1817 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ | ||
1818 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ | ||
1819 | uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ | ||
1820 | |||
1821 | /* | ||
1822 | * Set port for defined baud , 8 data bits, 1 stop bit, no parity. | ||
1823 | */ | ||
1824 | uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; | ||
1825 | uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; | ||
1826 | |||
1827 | #ifdef CONFIG_M5272 | ||
1828 | { | ||
1829 | /* | ||
1830 | * For the MCF5272, also compute the baudrate fraction. | ||
1831 | */ | ||
1832 | int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud); | ||
1833 | fraction *= 16; | ||
1834 | fraction /= (32 * mcfrs_console_baud); | ||
1835 | uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ | ||
1836 | clk = (MCF_BUSCLK / mcfrs_console_baud) / 32; | ||
1837 | } | ||
1838 | #else | ||
1839 | clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ | ||
1840 | #endif | ||
1841 | |||
1842 | uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ | ||
1843 | uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ | ||
1844 | uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; | ||
1845 | uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; | ||
1846 | |||
1847 | mcfrs_console_inited++; | ||
1848 | return; | ||
1849 | } | ||
1850 | |||
1851 | |||
1852 | /* | ||
1853 | * Setup for console. Argument comes from the boot command line. | ||
1854 | */ | ||
1855 | |||
1856 | int mcfrs_console_setup(struct console *cp, char *arg) | ||
1857 | { | ||
1858 | int i, n = CONSOLE_BAUD_RATE; | ||
1859 | |||
1860 | if (!cp) | ||
1861 | return(-1); | ||
1862 | |||
1863 | if (!strncmp(cp->name, "ttyS", 4)) | ||
1864 | mcfrs_console_port = cp->index; | ||
1865 | else if (!strncmp(cp->name, "cua", 3)) | ||
1866 | mcfrs_console_port = cp->index; | ||
1867 | else | ||
1868 | return(-1); | ||
1869 | |||
1870 | if (arg) | ||
1871 | n = simple_strtoul(arg,NULL,0); | ||
1872 | for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++) | ||
1873 | if (mcfrs_baud_table[i] == n) | ||
1874 | break; | ||
1875 | if (i < MCFRS_BAUD_TABLE_SIZE) { | ||
1876 | mcfrs_console_baud = n; | ||
1877 | mcfrs_console_cbaud = 0; | ||
1878 | if (i > 15) { | ||
1879 | mcfrs_console_cbaud |= CBAUDEX; | ||
1880 | i -= 15; | ||
1881 | } | ||
1882 | mcfrs_console_cbaud |= i; | ||
1883 | } | ||
1884 | mcfrs_init_console(); /* make sure baud rate changes */ | ||
1885 | return(0); | ||
1886 | } | ||
1887 | |||
1888 | |||
1889 | static struct tty_driver *mcfrs_console_device(struct console *c, int *index) | ||
1890 | { | ||
1891 | *index = c->index; | ||
1892 | return mcfrs_serial_driver; | ||
1893 | } | ||
1894 | |||
1895 | |||
1896 | /* | ||
1897 | * Output a single character, using UART polled mode. | ||
1898 | * This is used for console output. | ||
1899 | */ | ||
1900 | |||
1901 | int mcfrs_put_char(char ch) | ||
1902 | { | ||
1903 | volatile unsigned char *uartp; | ||
1904 | unsigned long flags; | ||
1905 | int i; | ||
1906 | |||
1907 | uartp = (volatile unsigned char *) (MCF_MBAR + | ||
1908 | (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); | ||
1909 | |||
1910 | local_irq_save(flags); | ||
1911 | for (i = 0; (i < 0x10000); i++) { | ||
1912 | if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) | ||
1913 | break; | ||
1914 | } | ||
1915 | if (i < 0x10000) { | ||
1916 | uartp[MCFUART_UTB] = ch; | ||
1917 | for (i = 0; (i < 0x10000); i++) | ||
1918 | if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) | ||
1919 | break; | ||
1920 | } | ||
1921 | if (i >= 0x10000) | ||
1922 | mcfrs_init_console(); /* try and get it back */ | ||
1923 | local_irq_restore(flags); | ||
1924 | |||
1925 | return 1; | ||
1926 | } | ||
1927 | |||
1928 | |||
1929 | /* | ||
1930 | * rs_console_write is registered for printk output. | ||
1931 | */ | ||
1932 | |||
1933 | void mcfrs_console_write(struct console *cp, const char *p, unsigned len) | ||
1934 | { | ||
1935 | if (!mcfrs_console_inited) | ||
1936 | mcfrs_init_console(); | ||
1937 | while (len-- > 0) { | ||
1938 | if (*p == '\n') | ||
1939 | mcfrs_put_char('\r'); | ||
1940 | mcfrs_put_char(*p++); | ||
1941 | } | ||
1942 | } | ||
1943 | |||
1944 | /* | ||
1945 | * declare our consoles | ||
1946 | */ | ||
1947 | |||
1948 | struct console mcfrs_console = { | ||
1949 | .name = "ttyS", | ||
1950 | .write = mcfrs_console_write, | ||
1951 | .device = mcfrs_console_device, | ||
1952 | .setup = mcfrs_console_setup, | ||
1953 | .flags = CON_PRINTBUFFER, | ||
1954 | .index = -1, | ||
1955 | }; | ||
1956 | |||
1957 | static int __init mcfrs_console_init(void) | ||
1958 | { | ||
1959 | register_console(&mcfrs_console); | ||
1960 | return 0; | ||
1961 | } | ||
1962 | |||
1963 | console_initcall(mcfrs_console_init); | ||
1964 | |||
1965 | /****************************************************************************/ | ||
diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h deleted file mode 100644 index 56420e2cb110..000000000000 --- a/drivers/serial/mcfserial.h +++ /dev/null | |||
@@ -1,74 +0,0 @@ | |||
1 | /* | ||
2 | * mcfserial.c -- serial driver for ColdFire internal UARTS. | ||
3 | * | ||
4 | * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com> | ||
5 | * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> | ||
6 | * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com> | ||
7 | * | ||
8 | * Based on code from 68332serial.c which was: | ||
9 | * | ||
10 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
11 | * Copyright (C) 1998 TSHG | ||
12 | * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> | ||
13 | */ | ||
14 | #ifndef _MCF_SERIAL_H | ||
15 | #define _MCF_SERIAL_H | ||
16 | |||
17 | #include <linux/serial.h> | ||
18 | |||
19 | #ifdef __KERNEL__ | ||
20 | |||
21 | /* | ||
22 | * Define a local serial stats structure. | ||
23 | */ | ||
24 | |||
25 | struct mcf_stats { | ||
26 | unsigned int rx; | ||
27 | unsigned int tx; | ||
28 | unsigned int rxbreak; | ||
29 | unsigned int rxframing; | ||
30 | unsigned int rxparity; | ||
31 | unsigned int rxoverrun; | ||
32 | }; | ||
33 | |||
34 | |||
35 | /* | ||
36 | * This is our internal structure for each serial port's state. | ||
37 | * Each serial port has one of these structures associated with it. | ||
38 | */ | ||
39 | |||
40 | struct mcf_serial { | ||
41 | int magic; | ||
42 | volatile unsigned char *addr; /* UART memory address */ | ||
43 | int irq; | ||
44 | int flags; /* defined in tty.h */ | ||
45 | int type; /* UART type */ | ||
46 | struct tty_struct *tty; | ||
47 | unsigned char imr; /* Software imr register */ | ||
48 | unsigned int baud; | ||
49 | int sigs; | ||
50 | int custom_divisor; | ||
51 | int x_char; /* xon/xoff character */ | ||
52 | int baud_base; | ||
53 | int close_delay; | ||
54 | unsigned short closing_wait; | ||
55 | unsigned short closing_wait2; | ||
56 | unsigned long event; | ||
57 | int line; | ||
58 | int count; /* # of fd on device */ | ||
59 | int blocked_open; /* # of blocked opens */ | ||
60 | unsigned char *xmit_buf; | ||
61 | int xmit_head; | ||
62 | int xmit_tail; | ||
63 | int xmit_cnt; | ||
64 | struct mcf_stats stats; | ||
65 | struct work_struct tqueue; | ||
66 | struct work_struct tqueue_hangup; | ||
67 | wait_queue_head_t open_wait; | ||
68 | wait_queue_head_t close_wait; | ||
69 | |||
70 | }; | ||
71 | |||
72 | #endif /* __KERNEL__ */ | ||
73 | |||
74 | #endif /* _MCF_SERIAL_H */ | ||
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index f977c98cfa95..6bdf3362e3b1 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
@@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) | |||
2051 | "transmitter\n", | 2051 | "transmitter\n", |
2052 | port->dev ? port->dev->bus_id : "", | 2052 | port->dev ? port->dev->bus_id : "", |
2053 | port->dev ? ": " : "", | 2053 | port->dev ? ": " : "", |
2054 | drv->dev_name, port->line); | 2054 | drv->dev_name, |
2055 | drv->tty_driver->name_base + port->line); | ||
2055 | 2056 | ||
2056 | ops->shutdown(port); | 2057 | ops->shutdown(port); |
2057 | } | 2058 | } |
@@ -2154,12 +2155,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) | |||
2154 | 2155 | ||
2155 | switch (port->iotype) { | 2156 | switch (port->iotype) { |
2156 | case UPIO_PORT: | 2157 | case UPIO_PORT: |
2157 | snprintf(address, sizeof(address), | 2158 | snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); |
2158 | "I/O 0x%x", port->iobase); | ||
2159 | break; | 2159 | break; |
2160 | case UPIO_HUB6: | 2160 | case UPIO_HUB6: |
2161 | snprintf(address, sizeof(address), | 2161 | snprintf(address, sizeof(address), |
2162 | "I/O 0x%x offset 0x%x", port->iobase, port->hub6); | 2162 | "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); |
2163 | break; | 2163 | break; |
2164 | case UPIO_MEM: | 2164 | case UPIO_MEM: |
2165 | case UPIO_MEM32: | 2165 | case UPIO_MEM32: |
@@ -2177,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) | |||
2177 | printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", | 2177 | printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", |
2178 | port->dev ? port->dev->bus_id : "", | 2178 | port->dev ? port->dev->bus_id : "", |
2179 | port->dev ? ": " : "", | 2179 | port->dev ? ": " : "", |
2180 | drv->dev_name, port->line, address, port->irq, uart_type(port)); | 2180 | drv->dev_name, |
2181 | drv->tty_driver->name_base + port->line, | ||
2182 | address, port->irq, uart_type(port)); | ||
2181 | } | 2183 | } |
2182 | 2184 | ||
2183 | static void | 2185 | static void |
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 79ea98c66fa8..99fb7dc59c45 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c | |||
@@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work) | |||
272 | * 64 bytes, to ensure I do not get throttled. | 272 | * 64 bytes, to ensure I do not get throttled. |
273 | * Ask USB mailing list for better aproach. | 273 | * Ask USB mailing list for better aproach. |
274 | */ | 274 | */ |
275 | tty = port->port.tty; | 275 | tty = tty_port_tty_get(&port->port); |
276 | 276 | ||
277 | if (!tty) { | 277 | if (!tty) { |
278 | schedule_work(&priv->rx_work); | 278 | schedule_work(&priv->rx_work); |
@@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work) | |||
283 | count = min(64, serial_buf_data_avail(priv->rx_buf)); | 283 | count = min(64, serial_buf_data_avail(priv->rx_buf)); |
284 | 284 | ||
285 | if (count <= 0) | 285 | if (count <= 0) |
286 | return; /* We have finished sending everything. */ | 286 | goto out; /* We have finished sending everything. */ |
287 | 287 | ||
288 | tty_prepare_flip_string(tty, &data, count); | 288 | tty_prepare_flip_string(tty, &data, count); |
289 | if (!data) { | 289 | if (!data) { |
290 | err("%s- kzalloc(%d) failed.", __func__, count); | 290 | dev_err(&port->dev, "%s- kzalloc(%d) failed.", |
291 | return; | 291 | __func__, count); |
292 | goto out; | ||
292 | } | 293 | } |
293 | 294 | ||
294 | serial_buf_get(priv->rx_buf, data, count); | 295 | serial_buf_get(priv->rx_buf, data, count); |
@@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work) | |||
297 | 298 | ||
298 | if (serial_buf_data_avail(priv->rx_buf)) | 299 | if (serial_buf_data_avail(priv->rx_buf)) |
299 | schedule_work(&priv->rx_work); | 300 | schedule_work(&priv->rx_work); |
300 | 301 | out: | |
302 | tty_kref_put(tty); | ||
301 | return; | 303 | return; |
302 | } | 304 | } |
303 | /* End of private methods */ | 305 | /* End of private methods */ |
@@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb) | |||
495 | usb_serial_debug_data(debug, &port->dev, __func__, | 497 | usb_serial_debug_data(debug, &port->dev, __func__, |
496 | urb->actual_length, urb->transfer_buffer); | 498 | urb->actual_length, urb->transfer_buffer); |
497 | 499 | ||
498 | tty = port->port.tty; | 500 | tty = tty_port_tty_get(&port->port); |
499 | if (tty && urb->actual_length) { | 501 | if (tty && urb->actual_length) { |
500 | if (urb->actual_length <= 2) { | 502 | if (urb->actual_length <= 2) { |
501 | /* This is an incomplete package */ | 503 | /* This is an incomplete package */ |
@@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb) | |||
527 | } | 529 | } |
528 | aircable_read(&priv->rx_work); | 530 | aircable_read(&priv->rx_work); |
529 | } | 531 | } |
532 | tty_kref_put(tty); | ||
530 | 533 | ||
531 | /* Schedule the next read _if_ we are still open */ | 534 | /* Schedule the next read _if_ we are still open */ |
532 | if (port->port.count) { | 535 | if (port->port.count) { |
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 2ebe06c3405a..1913bc7c5f0b 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c | |||
@@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb) | |||
322 | * to look in to this before committing any code. | 322 | * to look in to this before committing any code. |
323 | */ | 323 | */ |
324 | if (priv->last_lsr & BELKIN_SA_LSR_ERR) { | 324 | if (priv->last_lsr & BELKIN_SA_LSR_ERR) { |
325 | tty = port->port.tty; | 325 | tty = tty_port_tty_get(&port->port); |
326 | /* Overrun Error */ | 326 | /* Overrun Error */ |
327 | if (priv->last_lsr & BELKIN_SA_LSR_OE) { | 327 | if (priv->last_lsr & BELKIN_SA_LSR_OE) { |
328 | } | 328 | } |
@@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb) | |||
335 | /* Break Indicator */ | 335 | /* Break Indicator */ |
336 | if (priv->last_lsr & BELKIN_SA_LSR_BI) { | 336 | if (priv->last_lsr & BELKIN_SA_LSR_BI) { |
337 | } | 337 | } |
338 | tty_kref_put(tty); | ||
338 | } | 339 | } |
339 | #endif | 340 | #endif |
340 | spin_unlock_irqrestore(&priv->lock, flags); | 341 | spin_unlock_irqrestore(&priv->lock, flags); |
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index e980766bb84b..5b20de130e08 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c | |||
@@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options) | |||
117 | } | 117 | } |
118 | 118 | ||
119 | port = serial->port[0]; | 119 | port = serial->port[0]; |
120 | port->port.tty = NULL; | 120 | tty_port_tty_set(&port->port, NULL); |
121 | 121 | ||
122 | info->port = port; | 122 | info->port = port; |
123 | 123 | ||
@@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options) | |||
143 | } | 143 | } |
144 | memset(&dummy, 0, sizeof(struct ktermios)); | 144 | memset(&dummy, 0, sizeof(struct ktermios)); |
145 | tty->termios = termios; | 145 | tty->termios = termios; |
146 | port->port.tty = tty; | 146 | tty_port_tty_set(&port->port, tty); |
147 | } | 147 | } |
148 | 148 | ||
149 | /* only call the device specific open if this | 149 | /* only call the device specific open if this |
@@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options) | |||
163 | tty_termios_encode_baud_rate(termios, baud, baud); | 163 | tty_termios_encode_baud_rate(termios, baud, baud); |
164 | serial->type->set_termios(tty, port, &dummy); | 164 | serial->type->set_termios(tty, port, &dummy); |
165 | 165 | ||
166 | port->port.tty = NULL; | 166 | tty_port_tty_set(&port->port, NULL); |
167 | kfree(termios); | 167 | kfree(termios); |
168 | kfree(tty); | 168 | kfree(tty); |
169 | } | 169 | } |
@@ -176,7 +176,7 @@ out: | |||
176 | return retval; | 176 | return retval; |
177 | free_termios: | 177 | free_termios: |
178 | kfree(termios); | 178 | kfree(termios); |
179 | port->port.tty = NULL; | 179 | tty_port_tty_set(&port->port, NULL); |
180 | free_tty: | 180 | free_tty: |
181 | kfree(tty); | 181 | kfree(tty); |
182 | reset_open_count: | 182 | reset_open_count: |
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index b4d72351cb96..94ef36c4764b 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c | |||
@@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) | |||
384 | return; | 384 | return; |
385 | } | 385 | } |
386 | 386 | ||
387 | tty = port->port.tty; | 387 | tty = tty_port_tty_get(&port->port); |
388 | if (!tty) { | 388 | if (!tty) { |
389 | dbg("%s - ignoring since device not open\n", __func__); | 389 | dbg("%s - ignoring since device not open\n", __func__); |
390 | return; | 390 | return; |
@@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) | |||
394 | tty_insert_flip_string(tty, data, urb->actual_length); | 394 | tty_insert_flip_string(tty, data, urb->actual_length); |
395 | tty_flip_buffer_push(tty); | 395 | tty_flip_buffer_push(tty); |
396 | } | 396 | } |
397 | tty_kref_put(tty); | ||
397 | 398 | ||
398 | spin_lock(&priv->lock); | 399 | spin_lock(&priv->lock); |
399 | 400 | ||
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 22837a3f2f89..f3514a91f915 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
@@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb) | |||
1286 | } | 1286 | } |
1287 | spin_unlock_irqrestore(&priv->lock, flags); | 1287 | spin_unlock_irqrestore(&priv->lock, flags); |
1288 | 1288 | ||
1289 | tty = port->port.tty; | 1289 | tty = tty_port_tty_get(&port->port); |
1290 | if (!tty) { | 1290 | if (!tty) { |
1291 | dbg("%s - bad tty pointer - exiting", __func__); | 1291 | dbg("%s - bad tty pointer - exiting", __func__); |
1292 | return; | 1292 | return; |
@@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb) | |||
1362 | data[i]); | 1362 | data[i]); |
1363 | tty_insert_flip_char(tty, data[i], tty_flag); | 1363 | tty_insert_flip_char(tty, data[i], tty_flag); |
1364 | } | 1364 | } |
1365 | tty_flip_buffer_push(port->port.tty); | 1365 | tty_flip_buffer_push(tty); |
1366 | } | 1366 | } |
1367 | 1367 | ||
1368 | spin_lock_irqsave(&priv->lock, flags); | 1368 | spin_lock_irqsave(&priv->lock, flags); |
@@ -1371,6 +1371,7 @@ static void cypress_read_int_callback(struct urb *urb) | |||
1371 | spin_unlock_irqrestore(&priv->lock, flags); | 1371 | spin_unlock_irqrestore(&priv->lock, flags); |
1372 | 1372 | ||
1373 | continue_read: | 1373 | continue_read: |
1374 | tty_kref_put(tty); | ||
1374 | 1375 | ||
1375 | /* Continue trying to always read... unless the port has closed. */ | 1376 | /* Continue trying to always read... unless the port has closed. */ |
1376 | 1377 | ||
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 240aad1acaab..5756ac6d6c92 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c | |||
@@ -604,7 +604,9 @@ static void digi_wakeup_write_lock(struct work_struct *work) | |||
604 | 604 | ||
605 | static void digi_wakeup_write(struct usb_serial_port *port) | 605 | static void digi_wakeup_write(struct usb_serial_port *port) |
606 | { | 606 | { |
607 | tty_wakeup(port->port.tty); | 607 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
608 | tty_wakeup(tty); | ||
609 | tty_kref_put(tty); | ||
608 | } | 610 | } |
609 | 611 | ||
610 | 612 | ||
@@ -1668,7 +1670,7 @@ static int digi_read_inb_callback(struct urb *urb) | |||
1668 | { | 1670 | { |
1669 | 1671 | ||
1670 | struct usb_serial_port *port = urb->context; | 1672 | struct usb_serial_port *port = urb->context; |
1671 | struct tty_struct *tty = port->port.tty; | 1673 | struct tty_struct *tty; |
1672 | struct digi_port *priv = usb_get_serial_port_data(port); | 1674 | struct digi_port *priv = usb_get_serial_port_data(port); |
1673 | int opcode = ((unsigned char *)urb->transfer_buffer)[0]; | 1675 | int opcode = ((unsigned char *)urb->transfer_buffer)[0]; |
1674 | int len = ((unsigned char *)urb->transfer_buffer)[1]; | 1676 | int len = ((unsigned char *)urb->transfer_buffer)[1]; |
@@ -1692,6 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb) | |||
1692 | return -1; | 1694 | return -1; |
1693 | } | 1695 | } |
1694 | 1696 | ||
1697 | tty = tty_port_tty_get(&port->port); | ||
1695 | spin_lock(&priv->dp_port_lock); | 1698 | spin_lock(&priv->dp_port_lock); |
1696 | 1699 | ||
1697 | /* check for throttle; if set, do not resubmit read urb */ | 1700 | /* check for throttle; if set, do not resubmit read urb */ |
@@ -1735,6 +1738,7 @@ static int digi_read_inb_callback(struct urb *urb) | |||
1735 | } | 1738 | } |
1736 | } | 1739 | } |
1737 | spin_unlock(&priv->dp_port_lock); | 1740 | spin_unlock(&priv->dp_port_lock); |
1741 | tty_kref_put(tty); | ||
1738 | 1742 | ||
1739 | if (opcode == DIGI_CMD_RECEIVE_DISABLE) | 1743 | if (opcode == DIGI_CMD_RECEIVE_DISABLE) |
1740 | dbg("%s: got RECEIVE_DISABLE", __func__); | 1744 | dbg("%s: got RECEIVE_DISABLE", __func__); |
@@ -1760,6 +1764,7 @@ static int digi_read_oob_callback(struct urb *urb) | |||
1760 | 1764 | ||
1761 | struct usb_serial_port *port = urb->context; | 1765 | struct usb_serial_port *port = urb->context; |
1762 | struct usb_serial *serial = port->serial; | 1766 | struct usb_serial *serial = port->serial; |
1767 | struct tty_struct *tty; | ||
1763 | struct digi_port *priv = usb_get_serial_port_data(port); | 1768 | struct digi_port *priv = usb_get_serial_port_data(port); |
1764 | int opcode, line, status, val; | 1769 | int opcode, line, status, val; |
1765 | int i; | 1770 | int i; |
@@ -1787,10 +1792,11 @@ static int digi_read_oob_callback(struct urb *urb) | |||
1787 | if (priv == NULL) | 1792 | if (priv == NULL) |
1788 | return -1; | 1793 | return -1; |
1789 | 1794 | ||
1795 | tty = tty_port_tty_get(&port->port); | ||
1790 | rts = 0; | 1796 | rts = 0; |
1791 | if (port->port.count) | 1797 | if (port->port.count) |
1792 | rts = port->port.tty->termios->c_cflag & CRTSCTS; | 1798 | rts = tty->termios->c_cflag & CRTSCTS; |
1793 | 1799 | ||
1794 | if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) { | 1800 | if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) { |
1795 | spin_lock(&priv->dp_port_lock); | 1801 | spin_lock(&priv->dp_port_lock); |
1796 | /* convert from digi flags to termiox flags */ | 1802 | /* convert from digi flags to termiox flags */ |
@@ -1798,14 +1804,14 @@ static int digi_read_oob_callback(struct urb *urb) | |||
1798 | priv->dp_modem_signals |= TIOCM_CTS; | 1804 | priv->dp_modem_signals |= TIOCM_CTS; |
1799 | /* port must be open to use tty struct */ | 1805 | /* port must be open to use tty struct */ |
1800 | if (rts) { | 1806 | if (rts) { |
1801 | port->port.tty->hw_stopped = 0; | 1807 | tty->hw_stopped = 0; |
1802 | digi_wakeup_write(port); | 1808 | digi_wakeup_write(port); |
1803 | } | 1809 | } |
1804 | } else { | 1810 | } else { |
1805 | priv->dp_modem_signals &= ~TIOCM_CTS; | 1811 | priv->dp_modem_signals &= ~TIOCM_CTS; |
1806 | /* port must be open to use tty struct */ | 1812 | /* port must be open to use tty struct */ |
1807 | if (rts) | 1813 | if (rts) |
1808 | port->port.tty->hw_stopped = 1; | 1814 | tty->hw_stopped = 1; |
1809 | } | 1815 | } |
1810 | if (val & DIGI_READ_INPUT_SIGNALS_DSR) | 1816 | if (val & DIGI_READ_INPUT_SIGNALS_DSR) |
1811 | priv->dp_modem_signals |= TIOCM_DSR; | 1817 | priv->dp_modem_signals |= TIOCM_DSR; |
@@ -1830,6 +1836,7 @@ static int digi_read_oob_callback(struct urb *urb) | |||
1830 | } else if (opcode == DIGI_CMD_IFLUSH_FIFO) { | 1836 | } else if (opcode == DIGI_CMD_IFLUSH_FIFO) { |
1831 | wake_up_interruptible(&priv->dp_flush_wait); | 1837 | wake_up_interruptible(&priv->dp_flush_wait); |
1832 | } | 1838 | } |
1839 | tty_kref_put(tty); | ||
1833 | } | 1840 | } |
1834 | return 0; | 1841 | return 0; |
1835 | 1842 | ||
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index a6ab5b58d9ca..1072e847280f 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c | |||
@@ -33,9 +33,8 @@ | |||
33 | * Moved MOD_DEC_USE_COUNT to end of empeg_close(). | 33 | * Moved MOD_DEC_USE_COUNT to end of empeg_close(). |
34 | * | 34 | * |
35 | * (12/03/2000) gb | 35 | * (12/03/2000) gb |
36 | * Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to | 36 | * Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open(). |
37 | * empeg_open(). This notifies the tty driver that the termios have | 37 | * This notifies the tty driver that the termios have changed. |
38 | * changed. | ||
39 | * | 38 | * |
40 | * (11/13/2000) gb | 39 | * (11/13/2000) gb |
41 | * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to | 40 | * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to |
@@ -354,7 +353,7 @@ static void empeg_read_bulk_callback(struct urb *urb) | |||
354 | 353 | ||
355 | usb_serial_debug_data(debug, &port->dev, __func__, | 354 | usb_serial_debug_data(debug, &port->dev, __func__, |
356 | urb->actual_length, data); | 355 | urb->actual_length, data); |
357 | tty = port->port.tty; | 356 | tty = tty_port_tty_get(&port->port); |
358 | 357 | ||
359 | if (urb->actual_length) { | 358 | if (urb->actual_length) { |
360 | tty_buffer_request_room(tty, urb->actual_length); | 359 | tty_buffer_request_room(tty, urb->actual_length); |
@@ -362,6 +361,7 @@ static void empeg_read_bulk_callback(struct urb *urb) | |||
362 | tty_flip_buffer_push(tty); | 361 | tty_flip_buffer_push(tty); |
363 | bytes_in += urb->actual_length; | 362 | bytes_in += urb->actual_length; |
364 | } | 363 | } |
364 | tty_kref_put(tty); | ||
365 | 365 | ||
366 | /* Continue trying to always read */ | 366 | /* Continue trying to always read */ |
367 | usb_fill_bulk_urb( | 367 | usb_fill_bulk_urb( |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3dc93b542b30..c2ac129557aa 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, | |||
860 | 860 | ||
861 | kfree(buf); | 861 | kfree(buf); |
862 | if (rv < 0) { | 862 | if (rv < 0) { |
863 | err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", | 863 | dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", |
864 | __func__, | 864 | __func__, |
865 | (set & TIOCM_DTR) ? "HIGH" : | 865 | (set & TIOCM_DTR) ? "HIGH" : |
866 | (clear & TIOCM_DTR) ? "LOW" : "unchanged", | 866 | (clear & TIOCM_DTR) ? "LOW" : "unchanged", |
@@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) | |||
1808 | if (port->port.count <= 0) | 1808 | if (port->port.count <= 0) |
1809 | return; | 1809 | return; |
1810 | 1810 | ||
1811 | tty = port->port.tty; | 1811 | tty = tty_port_tty_get(&port->port); |
1812 | if (!tty) { | 1812 | if (!tty) { |
1813 | dbg("%s - bad tty pointer - exiting", __func__); | 1813 | dbg("%s - bad tty pointer - exiting", __func__); |
1814 | return; | 1814 | return; |
@@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) | |||
1817 | priv = usb_get_serial_port_data(port); | 1817 | priv = usb_get_serial_port_data(port); |
1818 | if (!priv) { | 1818 | if (!priv) { |
1819 | dbg("%s - bad port private data pointer - exiting", __func__); | 1819 | dbg("%s - bad port private data pointer - exiting", __func__); |
1820 | return; | 1820 | goto out; |
1821 | } | 1821 | } |
1822 | 1822 | ||
1823 | if (urb != port->read_urb) | 1823 | if (urb != port->read_urb) |
@@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) | |||
1827 | /* This will happen at close every time so it is a dbg not an | 1827 | /* This will happen at close every time so it is a dbg not an |
1828 | err */ | 1828 | err */ |
1829 | dbg("(this is ok on close) nonzero read bulk status received: %d", status); | 1829 | dbg("(this is ok on close) nonzero read bulk status received: %d", status); |
1830 | return; | 1830 | goto out; |
1831 | } | 1831 | } |
1832 | 1832 | ||
1833 | /* count data bytes, but not status bytes */ | 1833 | /* count data bytes, but not status bytes */ |
@@ -1838,7 +1838,8 @@ static void ftdi_read_bulk_callback(struct urb *urb) | |||
1838 | spin_unlock_irqrestore(&priv->rx_lock, flags); | 1838 | spin_unlock_irqrestore(&priv->rx_lock, flags); |
1839 | 1839 | ||
1840 | ftdi_process_read(&priv->rx_work.work); | 1840 | ftdi_process_read(&priv->rx_work.work); |
1841 | 1841 | out: | |
1842 | tty_kref_put(tty); | ||
1842 | } /* ftdi_read_bulk_callback */ | 1843 | } /* ftdi_read_bulk_callback */ |
1843 | 1844 | ||
1844 | 1845 | ||
@@ -1863,7 +1864,7 @@ static void ftdi_process_read(struct work_struct *work) | |||
1863 | if (port->port.count <= 0) | 1864 | if (port->port.count <= 0) |
1864 | return; | 1865 | return; |
1865 | 1866 | ||
1866 | tty = port->port.tty; | 1867 | tty = tty_port_tty_get(&port->port); |
1867 | if (!tty) { | 1868 | if (!tty) { |
1868 | dbg("%s - bad tty pointer - exiting", __func__); | 1869 | dbg("%s - bad tty pointer - exiting", __func__); |
1869 | return; | 1870 | return; |
@@ -1872,13 +1873,13 @@ static void ftdi_process_read(struct work_struct *work) | |||
1872 | priv = usb_get_serial_port_data(port); | 1873 | priv = usb_get_serial_port_data(port); |
1873 | if (!priv) { | 1874 | if (!priv) { |
1874 | dbg("%s - bad port private data pointer - exiting", __func__); | 1875 | dbg("%s - bad port private data pointer - exiting", __func__); |
1875 | return; | 1876 | goto out; |
1876 | } | 1877 | } |
1877 | 1878 | ||
1878 | urb = port->read_urb; | 1879 | urb = port->read_urb; |
1879 | if (!urb) { | 1880 | if (!urb) { |
1880 | dbg("%s - bad read_urb pointer - exiting", __func__); | 1881 | dbg("%s - bad read_urb pointer - exiting", __func__); |
1881 | return; | 1882 | goto out; |
1882 | } | 1883 | } |
1883 | 1884 | ||
1884 | data = urb->transfer_buffer; | 1885 | data = urb->transfer_buffer; |
@@ -2020,7 +2021,7 @@ static void ftdi_process_read(struct work_struct *work) | |||
2020 | schedule_delayed_work(&priv->rx_work, 1); | 2021 | schedule_delayed_work(&priv->rx_work, 1); |
2021 | else | 2022 | else |
2022 | dbg("%s - port is closed", __func__); | 2023 | dbg("%s - port is closed", __func__); |
2023 | return; | 2024 | goto out; |
2024 | } | 2025 | } |
2025 | 2026 | ||
2026 | /* urb is completely processed */ | 2027 | /* urb is completely processed */ |
@@ -2041,6 +2042,8 @@ static void ftdi_process_read(struct work_struct *work) | |||
2041 | err("%s - failed resubmitting read urb, error %d", | 2042 | err("%s - failed resubmitting read urb, error %d", |
2042 | __func__, result); | 2043 | __func__, result); |
2043 | } | 2044 | } |
2045 | out: | ||
2046 | tty_kref_put(tty); | ||
2044 | } /* ftdi_process_read */ | 2047 | } /* ftdi_process_read */ |
2045 | 2048 | ||
2046 | 2049 | ||
@@ -2256,7 +2259,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) | |||
2256 | 0, 0, | 2259 | 0, 0, |
2257 | buf, 1, WDR_TIMEOUT); | 2260 | buf, 1, WDR_TIMEOUT); |
2258 | if (ret < 0) { | 2261 | if (ret < 0) { |
2259 | err("%s Could not get modem status of device - err: %d", __func__, | 2262 | dbg("%s Could not get modem status of device - err: %d", __func__, |
2260 | ret); | 2263 | ret); |
2261 | return ret; | 2264 | return ret; |
2262 | } | 2265 | } |
@@ -2275,7 +2278,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) | |||
2275 | 0, priv->interface, | 2278 | 0, priv->interface, |
2276 | buf, 2, WDR_TIMEOUT); | 2279 | buf, 2, WDR_TIMEOUT); |
2277 | if (ret < 0) { | 2280 | if (ret < 0) { |
2278 | err("%s Could not get modem status of device - err: %d", __func__, | 2281 | dbg("%s Could not get modem status of device - err: %d", __func__, |
2279 | ret); | 2282 | ret); |
2280 | return ret; | 2283 | return ret; |
2281 | } | 2284 | } |
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index d95382088075..2ad0569bcf19 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c | |||
@@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf) | |||
276 | static void send_to_tty(struct usb_serial_port *port, | 276 | static void send_to_tty(struct usb_serial_port *port, |
277 | char *data, unsigned int actual_length) | 277 | char *data, unsigned int actual_length) |
278 | { | 278 | { |
279 | struct tty_struct *tty = port->port.tty; | 279 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
280 | 280 | ||
281 | if (tty && actual_length) { | 281 | if (tty && actual_length) { |
282 | 282 | ||
@@ -287,6 +287,7 @@ static void send_to_tty(struct usb_serial_port *port, | |||
287 | tty_insert_flip_string(tty, data, actual_length); | 287 | tty_insert_flip_string(tty, data, actual_length); |
288 | tty_flip_buffer_push(tty); | 288 | tty_flip_buffer_push(tty); |
289 | } | 289 | } |
290 | tty_kref_put(tty); | ||
290 | } | 291 | } |
291 | 292 | ||
292 | 293 | ||
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index fe84c88ec20c..814909f1ee63 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) | |||
330 | static void flush_and_resubmit_read_urb(struct usb_serial_port *port) | 330 | static void flush_and_resubmit_read_urb(struct usb_serial_port *port) |
331 | { | 331 | { |
332 | struct urb *urb = port->read_urb; | 332 | struct urb *urb = port->read_urb; |
333 | struct tty_struct *tty = port->port.tty; | 333 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
334 | int room; | 334 | int room; |
335 | 335 | ||
336 | /* Push data to tty */ | 336 | /* Push data to tty */ |
@@ -341,6 +341,7 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) | |||
341 | tty_flip_buffer_push(tty); | 341 | tty_flip_buffer_push(tty); |
342 | } | 342 | } |
343 | } | 343 | } |
344 | tty_kref_put(tty); | ||
344 | 345 | ||
345 | resubmit_read_urb(port, GFP_ATOMIC); | 346 | resubmit_read_urb(port, GFP_ATOMIC); |
346 | } | 347 | } |
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index bfa508ddb0fe..611f97fd62f1 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c | |||
@@ -600,6 +600,7 @@ static void edge_interrupt_callback(struct urb *urb) | |||
600 | struct edgeport_serial *edge_serial = urb->context; | 600 | struct edgeport_serial *edge_serial = urb->context; |
601 | struct edgeport_port *edge_port; | 601 | struct edgeport_port *edge_port; |
602 | struct usb_serial_port *port; | 602 | struct usb_serial_port *port; |
603 | struct tty_struct *tty; | ||
603 | unsigned char *data = urb->transfer_buffer; | 604 | unsigned char *data = urb->transfer_buffer; |
604 | int length = urb->actual_length; | 605 | int length = urb->actual_length; |
605 | int bytes_avail; | 606 | int bytes_avail; |
@@ -675,9 +676,12 @@ static void edge_interrupt_callback(struct urb *urb) | |||
675 | 676 | ||
676 | /* tell the tty driver that something | 677 | /* tell the tty driver that something |
677 | has changed */ | 678 | has changed */ |
678 | if (edge_port->port->port.tty) | 679 | tty = tty_port_tty_get( |
679 | tty_wakeup(edge_port->port->port.tty); | 680 | &edge_port->port->port); |
680 | 681 | if (tty) { | |
682 | tty_wakeup(tty); | ||
683 | tty_kref_put(tty); | ||
684 | } | ||
681 | /* Since we have more credit, check | 685 | /* Since we have more credit, check |
682 | if more data can be sent */ | 686 | if more data can be sent */ |
683 | send_more_port_data(edge_serial, | 687 | send_more_port_data(edge_serial, |
@@ -778,13 +782,14 @@ static void edge_bulk_out_data_callback(struct urb *urb) | |||
778 | __func__, status); | 782 | __func__, status); |
779 | } | 783 | } |
780 | 784 | ||
781 | tty = edge_port->port->port.tty; | 785 | tty = tty_port_tty_get(&edge_port->port->port); |
782 | 786 | ||
783 | if (tty && edge_port->open) { | 787 | if (tty && edge_port->open) { |
784 | /* let the tty driver wakeup if it has a special | 788 | /* let the tty driver wakeup if it has a special |
785 | write_wakeup function */ | 789 | write_wakeup function */ |
786 | tty_wakeup(tty); | 790 | tty_wakeup(tty); |
787 | } | 791 | } |
792 | tty_kref_put(tty); | ||
788 | 793 | ||
789 | /* Release the Write URB */ | 794 | /* Release the Write URB */ |
790 | edge_port->write_in_progress = false; | 795 | edge_port->write_in_progress = false; |
@@ -826,11 +831,12 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) | |||
826 | } | 831 | } |
827 | 832 | ||
828 | /* Get pointer to tty */ | 833 | /* Get pointer to tty */ |
829 | tty = edge_port->port->port.tty; | 834 | tty = tty_port_tty_get(&edge_port->port->port); |
830 | 835 | ||
831 | /* tell the tty driver that something has changed */ | 836 | /* tell the tty driver that something has changed */ |
832 | if (tty && edge_port->open) | 837 | if (tty && edge_port->open) |
833 | tty_wakeup(tty); | 838 | tty_wakeup(tty); |
839 | tty_kref_put(tty); | ||
834 | 840 | ||
835 | /* we have completed the command */ | 841 | /* we have completed the command */ |
836 | edge_port->commandPending = false; | 842 | edge_port->commandPending = false; |
@@ -1932,11 +1938,13 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, | |||
1932 | edge_serial->rxPort]; | 1938 | edge_serial->rxPort]; |
1933 | edge_port = usb_get_serial_port_data(port); | 1939 | edge_port = usb_get_serial_port_data(port); |
1934 | if (edge_port->open) { | 1940 | if (edge_port->open) { |
1935 | tty = edge_port->port->port.tty; | 1941 | tty = tty_port_tty_get( |
1942 | &edge_port->port->port); | ||
1936 | if (tty) { | 1943 | if (tty) { |
1937 | dbg("%s - Sending %d bytes to TTY for port %d", | 1944 | dbg("%s - Sending %d bytes to TTY for port %d", |
1938 | __func__, rxLen, edge_serial->rxPort); | 1945 | __func__, rxLen, edge_serial->rxPort); |
1939 | edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); | 1946 | edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); |
1947 | tty_kref_put(tty); | ||
1940 | } | 1948 | } |
1941 | edge_port->icount.rx += rxLen; | 1949 | edge_port->icount.rx += rxLen; |
1942 | } | 1950 | } |
@@ -1971,6 +1979,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, | |||
1971 | { | 1979 | { |
1972 | struct usb_serial_port *port; | 1980 | struct usb_serial_port *port; |
1973 | struct edgeport_port *edge_port; | 1981 | struct edgeport_port *edge_port; |
1982 | struct tty_struct *tty; | ||
1974 | __u8 code = edge_serial->rxStatusCode; | 1983 | __u8 code = edge_serial->rxStatusCode; |
1975 | 1984 | ||
1976 | /* switch the port pointer to the one being currently talked about */ | 1985 | /* switch the port pointer to the one being currently talked about */ |
@@ -2020,10 +2029,12 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, | |||
2020 | 2029 | ||
2021 | /* send the current line settings to the port so we are | 2030 | /* send the current line settings to the port so we are |
2022 | in sync with any further termios calls */ | 2031 | in sync with any further termios calls */ |
2023 | /* FIXME: locking on tty */ | 2032 | tty = tty_port_tty_get(&edge_port->port->port); |
2024 | if (edge_port->port->port.tty) | 2033 | if (tty) { |
2025 | change_port_settings(edge_port->port->port.tty, | 2034 | change_port_settings(tty, |
2026 | edge_port, edge_port->port->port.tty->termios); | 2035 | edge_port, tty->termios); |
2036 | tty_kref_put(tty); | ||
2037 | } | ||
2027 | 2038 | ||
2028 | /* we have completed the open */ | 2039 | /* we have completed the open */ |
2029 | edge_port->openPending = false; | 2040 | edge_port->openPending = false; |
@@ -2163,10 +2174,14 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, | |||
2163 | } | 2174 | } |
2164 | 2175 | ||
2165 | /* Place LSR data byte into Rx buffer */ | 2176 | /* Place LSR data byte into Rx buffer */ |
2166 | if (lsrData && edge_port->port->port.tty) | 2177 | if (lsrData) { |
2167 | edge_tty_recv(&edge_port->port->dev, | 2178 | struct tty_struct *tty = |
2168 | edge_port->port->port.tty, &data, 1); | 2179 | tty_port_tty_get(&edge_port->port->port); |
2169 | 2180 | if (tty) { | |
2181 | edge_tty_recv(&edge_port->port->dev, tty, &data, 1); | ||
2182 | tty_kref_put(tty); | ||
2183 | } | ||
2184 | } | ||
2170 | /* update input line counters */ | 2185 | /* update input line counters */ |
2171 | icount = &edge_port->icount; | 2186 | icount = &edge_port->icount; |
2172 | if (newLsr & LSR_BREAK) | 2187 | if (newLsr & LSR_BREAK) |
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index cb4c54316cf5..541dd8e6e7a2 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c | |||
@@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, | |||
572 | int flush) | 572 | int flush) |
573 | { | 573 | { |
574 | int baud_rate; | 574 | int baud_rate; |
575 | struct tty_struct *tty = port->port->port.tty; | 575 | struct tty_struct *tty = tty_port_tty_get(&port->port->port); |
576 | wait_queue_t wait; | 576 | wait_queue_t wait; |
577 | unsigned long flags; | 577 | unsigned long flags; |
578 | 578 | ||
@@ -599,6 +599,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, | |||
599 | if (flush) | 599 | if (flush) |
600 | edge_buf_clear(port->ep_out_buf); | 600 | edge_buf_clear(port->ep_out_buf); |
601 | spin_unlock_irqrestore(&port->ep_lock, flags); | 601 | spin_unlock_irqrestore(&port->ep_lock, flags); |
602 | tty_kref_put(tty); | ||
602 | 603 | ||
603 | /* wait for data to drain from the device */ | 604 | /* wait for data to drain from the device */ |
604 | timeout += jiffies; | 605 | timeout += jiffies; |
@@ -1554,7 +1555,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) | |||
1554 | /* Save the new modem status */ | 1555 | /* Save the new modem status */ |
1555 | edge_port->shadow_msr = msr & 0xf0; | 1556 | edge_port->shadow_msr = msr & 0xf0; |
1556 | 1557 | ||
1557 | tty = edge_port->port->port.tty; | 1558 | tty = tty_port_tty_get(&edge_port->port->port); |
1558 | /* handle CTS flow control */ | 1559 | /* handle CTS flow control */ |
1559 | if (tty && C_CRTSCTS(tty)) { | 1560 | if (tty && C_CRTSCTS(tty)) { |
1560 | if (msr & EDGEPORT_MSR_CTS) { | 1561 | if (msr & EDGEPORT_MSR_CTS) { |
@@ -1564,6 +1565,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) | |||
1564 | tty->hw_stopped = 1; | 1565 | tty->hw_stopped = 1; |
1565 | } | 1566 | } |
1566 | } | 1567 | } |
1568 | tty_kref_put(tty); | ||
1567 | 1569 | ||
1568 | return; | 1570 | return; |
1569 | } | 1571 | } |
@@ -1574,6 +1576,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, | |||
1574 | struct async_icount *icount; | 1576 | struct async_icount *icount; |
1575 | __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | | 1577 | __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | |
1576 | LSR_FRM_ERR | LSR_BREAK)); | 1578 | LSR_FRM_ERR | LSR_BREAK)); |
1579 | struct tty_struct *tty; | ||
1577 | 1580 | ||
1578 | dbg("%s - %02x", __func__, new_lsr); | 1581 | dbg("%s - %02x", __func__, new_lsr); |
1579 | 1582 | ||
@@ -1587,8 +1590,13 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, | |||
1587 | new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); | 1590 | new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); |
1588 | 1591 | ||
1589 | /* Place LSR data byte into Rx buffer */ | 1592 | /* Place LSR data byte into Rx buffer */ |
1590 | if (lsr_data && edge_port->port->port.tty) | 1593 | if (lsr_data) { |
1591 | edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1); | 1594 | tty = tty_port_tty_get(&edge_port->port->port); |
1595 | if (tty) { | ||
1596 | edge_tty_recv(&edge_port->port->dev, tty, &data, 1); | ||
1597 | tty_kref_put(tty); | ||
1598 | } | ||
1599 | } | ||
1592 | 1600 | ||
1593 | /* update input line counters */ | 1601 | /* update input line counters */ |
1594 | icount = &edge_port->icount; | 1602 | icount = &edge_port->icount; |
@@ -1749,7 +1757,7 @@ static void edge_bulk_in_callback(struct urb *urb) | |||
1749 | ++data; | 1757 | ++data; |
1750 | } | 1758 | } |
1751 | 1759 | ||
1752 | tty = edge_port->port->port.tty; | 1760 | tty = tty_port_tty_get(&edge_port->port->port); |
1753 | if (tty && urb->actual_length) { | 1761 | if (tty && urb->actual_length) { |
1754 | usb_serial_debug_data(debug, &edge_port->port->dev, | 1762 | usb_serial_debug_data(debug, &edge_port->port->dev, |
1755 | __func__, urb->actual_length, data); | 1763 | __func__, urb->actual_length, data); |
@@ -1761,6 +1769,7 @@ static void edge_bulk_in_callback(struct urb *urb) | |||
1761 | urb->actual_length); | 1769 | urb->actual_length); |
1762 | edge_port->icount.rx += urb->actual_length; | 1770 | edge_port->icount.rx += urb->actual_length; |
1763 | } | 1771 | } |
1772 | tty_kref_put(tty); | ||
1764 | 1773 | ||
1765 | exit: | 1774 | exit: |
1766 | /* continue read unless stopped */ | 1775 | /* continue read unless stopped */ |
@@ -1796,6 +1805,7 @@ static void edge_bulk_out_callback(struct urb *urb) | |||
1796 | struct usb_serial_port *port = urb->context; | 1805 | struct usb_serial_port *port = urb->context; |
1797 | struct edgeport_port *edge_port = usb_get_serial_port_data(port); | 1806 | struct edgeport_port *edge_port = usb_get_serial_port_data(port); |
1798 | int status = urb->status; | 1807 | int status = urb->status; |
1808 | struct tty_struct *tty; | ||
1799 | 1809 | ||
1800 | dbg("%s - port %d", __func__, port->number); | 1810 | dbg("%s - port %d", __func__, port->number); |
1801 | 1811 | ||
@@ -1818,7 +1828,9 @@ static void edge_bulk_out_callback(struct urb *urb) | |||
1818 | } | 1828 | } |
1819 | 1829 | ||
1820 | /* send any buffered data */ | 1830 | /* send any buffered data */ |
1821 | edge_send(port->port.tty); | 1831 | tty = tty_port_tty_get(&port->port); |
1832 | edge_send(tty); | ||
1833 | tty_kref_put(tty); | ||
1822 | } | 1834 | } |
1823 | 1835 | ||
1824 | static int edge_open(struct tty_struct *tty, | 1836 | static int edge_open(struct tty_struct *tty, |
@@ -1876,7 +1888,7 @@ static int edge_open(struct tty_struct *tty, | |||
1876 | 1888 | ||
1877 | /* set up the port settings */ | 1889 | /* set up the port settings */ |
1878 | if (tty) | 1890 | if (tty) |
1879 | edge_set_termios(tty, port, port->port.tty->termios); | 1891 | edge_set_termios(tty, port, tty->termios); |
1880 | 1892 | ||
1881 | /* open up the port */ | 1893 | /* open up the port */ |
1882 | 1894 | ||
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index cd9a2e138c8b..2affa9c118b2 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c | |||
@@ -764,13 +764,14 @@ static void ipaq_read_bulk_callback(struct urb *urb) | |||
764 | usb_serial_debug_data(debug, &port->dev, __func__, | 764 | usb_serial_debug_data(debug, &port->dev, __func__, |
765 | urb->actual_length, data); | 765 | urb->actual_length, data); |
766 | 766 | ||
767 | tty = port->port.tty; | 767 | tty = tty_port_tty_get(&port->port); |
768 | if (tty && urb->actual_length) { | 768 | if (tty && urb->actual_length) { |
769 | tty_buffer_request_room(tty, urb->actual_length); | 769 | tty_buffer_request_room(tty, urb->actual_length); |
770 | tty_insert_flip_string(tty, data, urb->actual_length); | 770 | tty_insert_flip_string(tty, data, urb->actual_length); |
771 | tty_flip_buffer_push(tty); | 771 | tty_flip_buffer_push(tty); |
772 | bytes_in += urb->actual_length; | 772 | bytes_in += urb->actual_length; |
773 | } | 773 | } |
774 | tty_kref_put(tty); | ||
774 | 775 | ||
775 | /* Continue trying to always read */ | 776 | /* Continue trying to always read */ |
776 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, | 777 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, |
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index a842025b9b57..480cac27d646 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c | |||
@@ -170,12 +170,13 @@ static void ipw_read_bulk_callback(struct urb *urb) | |||
170 | usb_serial_debug_data(debug, &port->dev, __func__, | 170 | usb_serial_debug_data(debug, &port->dev, __func__, |
171 | urb->actual_length, data); | 171 | urb->actual_length, data); |
172 | 172 | ||
173 | tty = port->port.tty; | 173 | tty = tty_port_tty_get(&port->port); |
174 | if (tty && urb->actual_length) { | 174 | if (tty && urb->actual_length) { |
175 | tty_buffer_request_room(tty, urb->actual_length); | 175 | tty_buffer_request_room(tty, urb->actual_length); |
176 | tty_insert_flip_string(tty, data, urb->actual_length); | 176 | tty_insert_flip_string(tty, data, urb->actual_length); |
177 | tty_flip_buffer_push(tty); | 177 | tty_flip_buffer_push(tty); |
178 | } | 178 | } |
179 | tty_kref_put(tty); | ||
179 | 180 | ||
180 | /* Continue trying to always read */ | 181 | /* Continue trying to always read */ |
181 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, | 182 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, |
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index e59155c6607d..45d4043e04ab 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c | |||
@@ -465,11 +465,12 @@ static void ir_read_bulk_callback(struct urb *urb) | |||
465 | ir_baud = *data & 0x0f; | 465 | ir_baud = *data & 0x0f; |
466 | usb_serial_debug_data(debug, &port->dev, __func__, | 466 | usb_serial_debug_data(debug, &port->dev, __func__, |
467 | urb->actual_length, data); | 467 | urb->actual_length, data); |
468 | tty = port->port.tty; | 468 | tty = tty_port_tty_get(&port->port); |
469 | if (tty_buffer_request_room(tty, urb->actual_length - 1)) { | 469 | if (tty_buffer_request_room(tty, urb->actual_length - 1)) { |
470 | tty_insert_flip_string(tty, data+1, urb->actual_length - 1); | 470 | tty_insert_flip_string(tty, data+1, urb->actual_length - 1); |
471 | tty_flip_buffer_push(tty); | 471 | tty_flip_buffer_push(tty); |
472 | } | 472 | } |
473 | tty_kref_put(tty); | ||
473 | 474 | ||
474 | /* | 475 | /* |
475 | * No break here. | 476 | * No break here. |
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index ddff37fa6339..53710aa7eadd 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c | |||
@@ -629,13 +629,14 @@ static void read_buf_callback(struct urb *urb) | |||
629 | } | 629 | } |
630 | 630 | ||
631 | dbg("%s - %i chars to write", __func__, urb->actual_length); | 631 | dbg("%s - %i chars to write", __func__, urb->actual_length); |
632 | tty = port->port.tty; | 632 | tty = tty_port_tty_get(&port->port); |
633 | if (data == NULL) | 633 | if (data == NULL) |
634 | dbg("%s - data is NULL !!!", __func__); | 634 | dbg("%s - data is NULL !!!", __func__); |
635 | if (tty && urb->actual_length && data) { | 635 | if (tty && urb->actual_length && data) { |
636 | tty_insert_flip_string(tty, data, urb->actual_length); | 636 | tty_insert_flip_string(tty, data, urb->actual_length); |
637 | tty_flip_buffer_push(tty); | 637 | tty_flip_buffer_push(tty); |
638 | } | 638 | } |
639 | tty_kref_put(tty); | ||
639 | iuu_led_activity_on(urb); | 640 | iuu_led_activity_on(urb); |
640 | } | 641 | } |
641 | 642 | ||
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 704716f6f6d3..15447af48691 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
@@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb) | |||
430 | } | 430 | } |
431 | 431 | ||
432 | port = urb->context; | 432 | port = urb->context; |
433 | tty = port->port.tty; | 433 | tty = tty_port_tty_get(&port->port); |
434 | if (tty && urb->actual_length) { | 434 | if (tty && urb->actual_length) { |
435 | /* 0x80 bit is error flag */ | 435 | /* 0x80 bit is error flag */ |
436 | if ((data[0] & 0x80) == 0) { | 436 | if ((data[0] & 0x80) == 0) { |
@@ -459,6 +459,7 @@ static void usa26_indat_callback(struct urb *urb) | |||
459 | } | 459 | } |
460 | tty_flip_buffer_push(tty); | 460 | tty_flip_buffer_push(tty); |
461 | } | 461 | } |
462 | tty_kref_put(tty); | ||
462 | 463 | ||
463 | /* Resubmit urb so we continue receiving */ | 464 | /* Resubmit urb so we continue receiving */ |
464 | urb->dev = port->serial->dev; | 465 | urb->dev = port->serial->dev; |
@@ -513,6 +514,7 @@ static void usa26_instat_callback(struct urb *urb) | |||
513 | struct usb_serial *serial; | 514 | struct usb_serial *serial; |
514 | struct usb_serial_port *port; | 515 | struct usb_serial_port *port; |
515 | struct keyspan_port_private *p_priv; | 516 | struct keyspan_port_private *p_priv; |
517 | struct tty_struct *tty; | ||
516 | int old_dcd_state, err; | 518 | int old_dcd_state, err; |
517 | int status = urb->status; | 519 | int status = urb->status; |
518 | 520 | ||
@@ -553,12 +555,11 @@ static void usa26_instat_callback(struct urb *urb) | |||
553 | p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); | 555 | p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); |
554 | p_priv->ri_state = ((msg->ri) ? 1 : 0); | 556 | p_priv->ri_state = ((msg->ri) ? 1 : 0); |
555 | 557 | ||
556 | if (port->port.tty && !C_CLOCAL(port->port.tty) | 558 | if (old_dcd_state != p_priv->dcd_state) { |
557 | && old_dcd_state != p_priv->dcd_state) { | 559 | tty = tty_port_tty_get(&port->port); |
558 | if (old_dcd_state) | 560 | if (tty && !C_CLOCAL(tty)) |
559 | tty_hangup(port->port.tty); | 561 | tty_hangup(tty); |
560 | /* else */ | 562 | tty_kref_put(tty); |
561 | /* wake_up_interruptible(&p_priv->open_wait); */ | ||
562 | } | 563 | } |
563 | 564 | ||
564 | /* Resubmit urb so we continue receiving */ | 565 | /* Resubmit urb so we continue receiving */ |
@@ -604,11 +605,12 @@ static void usa28_indat_callback(struct urb *urb) | |||
604 | p_priv = usb_get_serial_port_data(port); | 605 | p_priv = usb_get_serial_port_data(port); |
605 | data = urb->transfer_buffer; | 606 | data = urb->transfer_buffer; |
606 | 607 | ||
607 | tty = port->port.tty; | 608 | tty =tty_port_tty_get(&port->port); |
608 | if (urb->actual_length) { | 609 | if (tty && urb->actual_length) { |
609 | tty_insert_flip_string(tty, data, urb->actual_length); | 610 | tty_insert_flip_string(tty, data, urb->actual_length); |
610 | tty_flip_buffer_push(tty); | 611 | tty_flip_buffer_push(tty); |
611 | } | 612 | } |
613 | tty_kref_put(tty); | ||
612 | 614 | ||
613 | /* Resubmit urb so we continue receiving */ | 615 | /* Resubmit urb so we continue receiving */ |
614 | urb->dev = port->serial->dev; | 616 | urb->dev = port->serial->dev; |
@@ -652,6 +654,7 @@ static void usa28_instat_callback(struct urb *urb) | |||
652 | struct usb_serial *serial; | 654 | struct usb_serial *serial; |
653 | struct usb_serial_port *port; | 655 | struct usb_serial_port *port; |
654 | struct keyspan_port_private *p_priv; | 656 | struct keyspan_port_private *p_priv; |
657 | struct tty_struct *tty; | ||
655 | int old_dcd_state; | 658 | int old_dcd_state; |
656 | int status = urb->status; | 659 | int status = urb->status; |
657 | 660 | ||
@@ -689,12 +692,11 @@ static void usa28_instat_callback(struct urb *urb) | |||
689 | p_priv->dcd_state = ((msg->dcd) ? 1 : 0); | 692 | p_priv->dcd_state = ((msg->dcd) ? 1 : 0); |
690 | p_priv->ri_state = ((msg->ri) ? 1 : 0); | 693 | p_priv->ri_state = ((msg->ri) ? 1 : 0); |
691 | 694 | ||
692 | if (port->port.tty && !C_CLOCAL(port->port.tty) | 695 | if( old_dcd_state != p_priv->dcd_state && old_dcd_state) { |
693 | && old_dcd_state != p_priv->dcd_state) { | 696 | tty = tty_port_tty_get(&port->port); |
694 | if (old_dcd_state) | 697 | if (tty && !C_CLOCAL(tty)) |
695 | tty_hangup(port->port.tty); | 698 | tty_hangup(tty); |
696 | /* else */ | 699 | tty_kref_put(tty); |
697 | /* wake_up_interruptible(&p_priv->open_wait); */ | ||
698 | } | 700 | } |
699 | 701 | ||
700 | /* Resubmit urb so we continue receiving */ | 702 | /* Resubmit urb so we continue receiving */ |
@@ -785,12 +787,11 @@ static void usa49_instat_callback(struct urb *urb) | |||
785 | p_priv->dcd_state = ((msg->dcd) ? 1 : 0); | 787 | p_priv->dcd_state = ((msg->dcd) ? 1 : 0); |
786 | p_priv->ri_state = ((msg->ri) ? 1 : 0); | 788 | p_priv->ri_state = ((msg->ri) ? 1 : 0); |
787 | 789 | ||
788 | if (port->port.tty && !C_CLOCAL(port->port.tty) | 790 | if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { |
789 | && old_dcd_state != p_priv->dcd_state) { | 791 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
790 | if (old_dcd_state) | 792 | if (tty && !C_CLOCAL(tty)) |
791 | tty_hangup(port->port.tty); | 793 | tty_hangup(tty); |
792 | /* else */ | 794 | tty_kref_put(tty); |
793 | /* wake_up_interruptible(&p_priv->open_wait); */ | ||
794 | } | 795 | } |
795 | 796 | ||
796 | /* Resubmit urb so we continue receiving */ | 797 | /* Resubmit urb so we continue receiving */ |
@@ -827,7 +828,7 @@ static void usa49_indat_callback(struct urb *urb) | |||
827 | } | 828 | } |
828 | 829 | ||
829 | port = urb->context; | 830 | port = urb->context; |
830 | tty = port->port.tty; | 831 | tty = tty_port_tty_get(&port->port); |
831 | if (tty && urb->actual_length) { | 832 | if (tty && urb->actual_length) { |
832 | /* 0x80 bit is error flag */ | 833 | /* 0x80 bit is error flag */ |
833 | if ((data[0] & 0x80) == 0) { | 834 | if ((data[0] & 0x80) == 0) { |
@@ -850,6 +851,7 @@ static void usa49_indat_callback(struct urb *urb) | |||
850 | } | 851 | } |
851 | tty_flip_buffer_push(tty); | 852 | tty_flip_buffer_push(tty); |
852 | } | 853 | } |
854 | tty_kref_put(tty); | ||
853 | 855 | ||
854 | /* Resubmit urb so we continue receiving */ | 856 | /* Resubmit urb so we continue receiving */ |
855 | urb->dev = port->serial->dev; | 857 | urb->dev = port->serial->dev; |
@@ -893,7 +895,7 @@ static void usa49wg_indat_callback(struct urb *urb) | |||
893 | return; | 895 | return; |
894 | } | 896 | } |
895 | port = serial->port[data[i++]]; | 897 | port = serial->port[data[i++]]; |
896 | tty = port->port.tty; | 898 | tty = tty_port_tty_get(&port->port); |
897 | len = data[i++]; | 899 | len = data[i++]; |
898 | 900 | ||
899 | /* 0x80 bit is error flag */ | 901 | /* 0x80 bit is error flag */ |
@@ -927,6 +929,7 @@ static void usa49wg_indat_callback(struct urb *urb) | |||
927 | } | 929 | } |
928 | if (port->port.count) | 930 | if (port->port.count) |
929 | tty_flip_buffer_push(tty); | 931 | tty_flip_buffer_push(tty); |
932 | tty_kref_put(tty); | ||
930 | } | 933 | } |
931 | } | 934 | } |
932 | 935 | ||
@@ -967,8 +970,8 @@ static void usa90_indat_callback(struct urb *urb) | |||
967 | port = urb->context; | 970 | port = urb->context; |
968 | p_priv = usb_get_serial_port_data(port); | 971 | p_priv = usb_get_serial_port_data(port); |
969 | 972 | ||
970 | tty = port->port.tty; | ||
971 | if (urb->actual_length) { | 973 | if (urb->actual_length) { |
974 | tty = tty_port_tty_get(&port->port); | ||
972 | /* if current mode is DMA, looks like usa28 format | 975 | /* if current mode is DMA, looks like usa28 format |
973 | otherwise looks like usa26 data format */ | 976 | otherwise looks like usa26 data format */ |
974 | 977 | ||
@@ -1004,6 +1007,7 @@ static void usa90_indat_callback(struct urb *urb) | |||
1004 | } | 1007 | } |
1005 | } | 1008 | } |
1006 | tty_flip_buffer_push(tty); | 1009 | tty_flip_buffer_push(tty); |
1010 | tty_kref_put(tty); | ||
1007 | } | 1011 | } |
1008 | 1012 | ||
1009 | /* Resubmit urb so we continue receiving */ | 1013 | /* Resubmit urb so we continue receiving */ |
@@ -1025,6 +1029,7 @@ static void usa90_instat_callback(struct urb *urb) | |||
1025 | struct usb_serial *serial; | 1029 | struct usb_serial *serial; |
1026 | struct usb_serial_port *port; | 1030 | struct usb_serial_port *port; |
1027 | struct keyspan_port_private *p_priv; | 1031 | struct keyspan_port_private *p_priv; |
1032 | struct tty_struct *tty; | ||
1028 | int old_dcd_state, err; | 1033 | int old_dcd_state, err; |
1029 | int status = urb->status; | 1034 | int status = urb->status; |
1030 | 1035 | ||
@@ -1053,12 +1058,11 @@ static void usa90_instat_callback(struct urb *urb) | |||
1053 | p_priv->dcd_state = ((msg->dcd) ? 1 : 0); | 1058 | p_priv->dcd_state = ((msg->dcd) ? 1 : 0); |
1054 | p_priv->ri_state = ((msg->ri) ? 1 : 0); | 1059 | p_priv->ri_state = ((msg->ri) ? 1 : 0); |
1055 | 1060 | ||
1056 | if (port->port.tty && !C_CLOCAL(port->port.tty) | 1061 | if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { |
1057 | && old_dcd_state != p_priv->dcd_state) { | 1062 | tty = tty_port_tty_get(&port->port); |
1058 | if (old_dcd_state) | 1063 | if (tty && !C_CLOCAL(tty)) |
1059 | tty_hangup(port->port.tty); | 1064 | tty_hangup(tty); |
1060 | /* else */ | 1065 | tty_kref_put(tty); |
1061 | /* wake_up_interruptible(&p_priv->open_wait); */ | ||
1062 | } | 1066 | } |
1063 | 1067 | ||
1064 | /* Resubmit urb so we continue receiving */ | 1068 | /* Resubmit urb so we continue receiving */ |
@@ -1130,12 +1134,11 @@ static void usa67_instat_callback(struct urb *urb) | |||
1130 | p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); | 1134 | p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); |
1131 | p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); | 1135 | p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); |
1132 | 1136 | ||
1133 | if (port->port.tty && !C_CLOCAL(port->port.tty) | 1137 | if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { |
1134 | && old_dcd_state != p_priv->dcd_state) { | 1138 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
1135 | if (old_dcd_state) | 1139 | if (tty && !C_CLOCAL(tty)) |
1136 | tty_hangup(port->port.tty); | 1140 | tty_hangup(tty); |
1137 | /* else */ | 1141 | tty_kref_put(tty); |
1138 | /* wake_up_interruptible(&p_priv->open_wait); */ | ||
1139 | } | 1142 | } |
1140 | 1143 | ||
1141 | /* Resubmit urb so we continue receiving */ | 1144 | /* Resubmit urb so we continue receiving */ |
@@ -1332,7 +1335,7 @@ static void keyspan_close(struct tty_struct *tty, | |||
1332 | stop_urb(p_priv->out_urbs[i]); | 1335 | stop_urb(p_priv->out_urbs[i]); |
1333 | } | 1336 | } |
1334 | } | 1337 | } |
1335 | port->port.tty = NULL; | 1338 | tty_port_tty_set(&port->port, NULL); |
1336 | } | 1339 | } |
1337 | 1340 | ||
1338 | /* download the firmware to a pre-renumeration device */ | 1341 | /* download the firmware to a pre-renumeration device */ |
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 040040a267d9..99e9a14c5bf6 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c | |||
@@ -172,8 +172,9 @@ static void keyspan_pda_wakeup_write(struct work_struct *work) | |||
172 | struct keyspan_pda_private *priv = | 172 | struct keyspan_pda_private *priv = |
173 | container_of(work, struct keyspan_pda_private, wakeup_work); | 173 | container_of(work, struct keyspan_pda_private, wakeup_work); |
174 | struct usb_serial_port *port = priv->port; | 174 | struct usb_serial_port *port = priv->port; |
175 | 175 | struct tty_struct *tty = tty_port_tty_get(&port->port); | |
176 | tty_wakeup(port->port.tty); | 176 | tty_wakeup(tty); |
177 | tty_kref_put(tty); | ||
177 | } | 178 | } |
178 | 179 | ||
179 | static void keyspan_pda_request_unthrottle(struct work_struct *work) | 180 | static void keyspan_pda_request_unthrottle(struct work_struct *work) |
@@ -205,7 +206,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) | |||
205 | static void keyspan_pda_rx_interrupt(struct urb *urb) | 206 | static void keyspan_pda_rx_interrupt(struct urb *urb) |
206 | { | 207 | { |
207 | struct usb_serial_port *port = urb->context; | 208 | struct usb_serial_port *port = urb->context; |
208 | struct tty_struct *tty = port->port.tty; | 209 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
209 | unsigned char *data = urb->transfer_buffer; | 210 | unsigned char *data = urb->transfer_buffer; |
210 | int retval; | 211 | int retval; |
211 | int status = urb->status; | 212 | int status = urb->status; |
@@ -222,7 +223,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) | |||
222 | /* this urb is terminated, clean up */ | 223 | /* this urb is terminated, clean up */ |
223 | dbg("%s - urb shutting down with status: %d", | 224 | dbg("%s - urb shutting down with status: %d", |
224 | __func__, status); | 225 | __func__, status); |
225 | return; | 226 | goto out; |
226 | default: | 227 | default: |
227 | dbg("%s - nonzero urb status received: %d", | 228 | dbg("%s - nonzero urb status received: %d", |
228 | __func__, status); | 229 | __func__, status); |
@@ -261,8 +262,11 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) | |||
261 | exit: | 262 | exit: |
262 | retval = usb_submit_urb(urb, GFP_ATOMIC); | 263 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
263 | if (retval) | 264 | if (retval) |
264 | err("%s - usb_submit_urb failed with result %d", | 265 | dev_err(&port->dev, |
265 | __func__, retval); | 266 | "%s - usb_submit_urb failed with result %d", |
267 | __func__, retval); | ||
268 | out: | ||
269 | tty_kref_put(tty); | ||
266 | } | 270 | } |
267 | 271 | ||
268 | 272 | ||
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index b84dddc71124..ff3a07f5102f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c | |||
@@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb) | |||
658 | } else { | 658 | } else { |
659 | int bytes_sent = ((__u8 *) data)[0] + | 659 | int bytes_sent = ((__u8 *) data)[0] + |
660 | ((unsigned int) ((__u8 *) data)[1] << 8); | 660 | ((unsigned int) ((__u8 *) data)[1] << 8); |
661 | tty = port->port.tty; | 661 | tty = tty_port_tty_get(&port->port); |
662 | /* we should immediately resubmit the URB, before attempting | 662 | /* we should immediately resubmit the URB, before attempting |
663 | * to pass the data on to the tty layer. But that needs locking | 663 | * to pass the data on to the tty layer. But that needs locking |
664 | * against re-entry an then mixed-up data because of | 664 | * against re-entry an then mixed-up data because of |
@@ -679,6 +679,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb) | |||
679 | tty_buffer_request_room(tty, bytes_sent); | 679 | tty_buffer_request_room(tty, bytes_sent); |
680 | tty_insert_flip_string(tty, data + 2, bytes_sent); | 680 | tty_insert_flip_string(tty, data + 2, bytes_sent); |
681 | tty_flip_buffer_push(tty); | 681 | tty_flip_buffer_push(tty); |
682 | tty_kref_put(tty); | ||
682 | 683 | ||
683 | /* again lockless, but debug info only */ | 684 | /* again lockless, but debug info only */ |
684 | priv->bytes_in += bytes_sent; | 685 | priv->bytes_in += bytes_sent; |
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index deba28ec77e8..cfcf37c2b957 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c | |||
@@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb) | |||
383 | return; | 383 | return; |
384 | } | 384 | } |
385 | 385 | ||
386 | tty = port->port.tty; | 386 | tty = tty_port_tty_get(&port->port); |
387 | if (urb->actual_length) { | 387 | if (urb->actual_length) { |
388 | 388 | ||
389 | /* BEGIN DEBUG */ | 389 | /* BEGIN DEBUG */ |
@@ -405,6 +405,7 @@ static void kobil_read_int_callback(struct urb *urb) | |||
405 | tty_insert_flip_string(tty, data, urb->actual_length); | 405 | tty_insert_flip_string(tty, data, urb->actual_length); |
406 | tty_flip_buffer_push(tty); | 406 | tty_flip_buffer_push(tty); |
407 | } | 407 | } |
408 | tty_kref_put(tty); | ||
408 | /* someone sets the dev to 0 if the close method has been called */ | 409 | /* someone sets the dev to 0 if the close method has been called */ |
409 | port->interrupt_in_urb->dev = port->serial->dev; | 410 | port->interrupt_in_urb->dev = port->serial->dev; |
410 | 411 | ||
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 0ded8bd6ec85..9b2cef81cde0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c | |||
@@ -563,10 +563,11 @@ static void mct_u232_read_int_callback(struct urb *urb) | |||
563 | * Work-a-round: handle the 'usual' bulk-in pipe here | 563 | * Work-a-round: handle the 'usual' bulk-in pipe here |
564 | */ | 564 | */ |
565 | if (urb->transfer_buffer_length > 2) { | 565 | if (urb->transfer_buffer_length > 2) { |
566 | tty = port->port.tty; | 566 | tty = tty_port_tty_get(&port->port); |
567 | if (urb->actual_length) { | 567 | if (urb->actual_length) { |
568 | tty_insert_flip_string(tty, data, urb->actual_length); | 568 | tty_insert_flip_string(tty, data, urb->actual_length); |
569 | tty_flip_buffer_push(tty); | 569 | tty_flip_buffer_push(tty); |
570 | tty_kref_put(tty); | ||
570 | } | 571 | } |
571 | goto exit; | 572 | goto exit; |
572 | } | 573 | } |
@@ -591,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb) | |||
591 | * to look in to this before committing any code. | 592 | * to look in to this before committing any code. |
592 | */ | 593 | */ |
593 | if (priv->last_lsr & MCT_U232_LSR_ERR) { | 594 | if (priv->last_lsr & MCT_U232_LSR_ERR) { |
594 | tty = port->port.tty; | 595 | tty = tty_port_tty_get(&port->port); |
595 | /* Overrun Error */ | 596 | /* Overrun Error */ |
596 | if (priv->last_lsr & MCT_U232_LSR_OE) { | 597 | if (priv->last_lsr & MCT_U232_LSR_OE) { |
597 | } | 598 | } |
@@ -604,6 +605,7 @@ static void mct_u232_read_int_callback(struct urb *urb) | |||
604 | /* Break Indicator */ | 605 | /* Break Indicator */ |
605 | if (priv->last_lsr & MCT_U232_LSR_BI) { | 606 | if (priv->last_lsr & MCT_U232_LSR_BI) { |
606 | } | 607 | } |
608 | tty_kref_put(tty); | ||
607 | } | 609 | } |
608 | #endif | 610 | #endif |
609 | spin_unlock_irqrestore(&priv->lock, flags); | 611 | spin_unlock_irqrestore(&priv->lock, flags); |
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 7c4917d77c0a..7b538caec37f 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c | |||
@@ -216,12 +216,13 @@ static void mos7720_bulk_in_callback(struct urb *urb) | |||
216 | 216 | ||
217 | data = urb->transfer_buffer; | 217 | data = urb->transfer_buffer; |
218 | 218 | ||
219 | tty = port->port.tty; | 219 | tty = tty_port_tty_get(&port->port); |
220 | if (tty && urb->actual_length) { | 220 | if (tty && urb->actual_length) { |
221 | tty_buffer_request_room(tty, urb->actual_length); | 221 | tty_buffer_request_room(tty, urb->actual_length); |
222 | tty_insert_flip_string(tty, data, urb->actual_length); | 222 | tty_insert_flip_string(tty, data, urb->actual_length); |
223 | tty_flip_buffer_push(tty); | 223 | tty_flip_buffer_push(tty); |
224 | } | 224 | } |
225 | tty_kref_put(tty); | ||
225 | 226 | ||
226 | if (!port->read_urb) { | 227 | if (!port->read_urb) { |
227 | dbg("URB KILLED !!!"); | 228 | dbg("URB KILLED !!!"); |
@@ -262,10 +263,11 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) | |||
262 | 263 | ||
263 | dbg("Entering ........."); | 264 | dbg("Entering ........."); |
264 | 265 | ||
265 | tty = mos7720_port->port->port.tty; | 266 | tty = tty_port_tty_get(&mos7720_port->port->port); |
266 | 267 | ||
267 | if (tty && mos7720_port->open) | 268 | if (tty && mos7720_port->open) |
268 | tty_wakeup(tty); | 269 | tty_wakeup(tty); |
270 | tty_kref_put(tty); | ||
269 | } | 271 | } |
270 | 272 | ||
271 | /* | 273 | /* |
@@ -1267,29 +1269,6 @@ static int get_lsr_info(struct tty_struct *tty, | |||
1267 | return 0; | 1269 | return 0; |
1268 | } | 1270 | } |
1269 | 1271 | ||
1270 | /* | ||
1271 | * get_number_bytes_avail - get number of bytes available | ||
1272 | * | ||
1273 | * Purpose: Let user call ioctl to get the count of number of bytes available. | ||
1274 | */ | ||
1275 | static int get_number_bytes_avail(struct moschip_port *mos7720_port, | ||
1276 | unsigned int __user *value) | ||
1277 | { | ||
1278 | unsigned int result = 0; | ||
1279 | struct tty_struct *tty = mos7720_port->port->port.tty; | ||
1280 | |||
1281 | if (!tty) | ||
1282 | return -ENOIOCTLCMD; | ||
1283 | |||
1284 | result = tty->read_cnt; | ||
1285 | |||
1286 | dbg("%s(%d) = %d", __func__, mos7720_port->port->number, result); | ||
1287 | if (copy_to_user(value, &result, sizeof(int))) | ||
1288 | return -EFAULT; | ||
1289 | |||
1290 | return -ENOIOCTLCMD; | ||
1291 | } | ||
1292 | |||
1293 | static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, | 1272 | static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, |
1294 | unsigned int __user *value) | 1273 | unsigned int __user *value) |
1295 | { | 1274 | { |
@@ -1409,13 +1388,6 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, | |||
1409 | dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); | 1388 | dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); |
1410 | 1389 | ||
1411 | switch (cmd) { | 1390 | switch (cmd) { |
1412 | case TIOCINQ: | ||
1413 | /* return number of bytes available */ | ||
1414 | dbg("%s (%d) TIOCINQ", __func__, port->number); | ||
1415 | return get_number_bytes_avail(mos7720_port, | ||
1416 | (unsigned int __user *)arg); | ||
1417 | break; | ||
1418 | |||
1419 | case TIOCSERGETLSR: | 1391 | case TIOCSERGETLSR: |
1420 | dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); | 1392 | dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); |
1421 | return get_lsr_info(tty, mos7720_port, | 1393 | return get_lsr_info(tty, mos7720_port, |
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 09d82062b973..60543d79ef56 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c | |||
@@ -709,12 +709,13 @@ static void mos7840_bulk_in_callback(struct urb *urb) | |||
709 | dbg("%s", "Entering ........... \n"); | 709 | dbg("%s", "Entering ........... \n"); |
710 | 710 | ||
711 | if (urb->actual_length) { | 711 | if (urb->actual_length) { |
712 | tty = mos7840_port->port->port.tty; | 712 | tty = tty_port_tty_get(&mos7840_port->port->port); |
713 | if (tty) { | 713 | if (tty) { |
714 | tty_buffer_request_room(tty, urb->actual_length); | 714 | tty_buffer_request_room(tty, urb->actual_length); |
715 | tty_insert_flip_string(tty, data, urb->actual_length); | 715 | tty_insert_flip_string(tty, data, urb->actual_length); |
716 | dbg(" %s \n", data); | 716 | dbg(" %s \n", data); |
717 | tty_flip_buffer_push(tty); | 717 | tty_flip_buffer_push(tty); |
718 | tty_kref_put(tty); | ||
718 | } | 719 | } |
719 | mos7840_port->icount.rx += urb->actual_length; | 720 | mos7840_port->icount.rx += urb->actual_length; |
720 | smp_wmb(); | 721 | smp_wmb(); |
@@ -773,10 +774,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) | |||
773 | 774 | ||
774 | dbg("%s \n", "Entering ........."); | 775 | dbg("%s \n", "Entering ........."); |
775 | 776 | ||
776 | tty = mos7840_port->port->port.tty; | 777 | tty = tty_port_tty_get(&mos7840_port->port->port); |
777 | |||
778 | if (tty && mos7840_port->open) | 778 | if (tty && mos7840_port->open) |
779 | tty_wakeup(tty); | 779 | tty_wakeup(tty); |
780 | tty_kref_put(tty); | ||
780 | 781 | ||
781 | } | 782 | } |
782 | 783 | ||
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index d6736531a0fa..bcdcbb822705 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c | |||
@@ -64,12 +64,13 @@ static void navman_read_int_callback(struct urb *urb) | |||
64 | usb_serial_debug_data(debug, &port->dev, __func__, | 64 | usb_serial_debug_data(debug, &port->dev, __func__, |
65 | urb->actual_length, data); | 65 | urb->actual_length, data); |
66 | 66 | ||
67 | tty = port->port.tty; | 67 | tty = tty_port_tty_get(&port->port); |
68 | if (tty && urb->actual_length) { | 68 | if (tty && urb->actual_length) { |
69 | tty_buffer_request_room(tty, urb->actual_length); | 69 | tty_buffer_request_room(tty, urb->actual_length); |
70 | tty_insert_flip_string(tty, data, urb->actual_length); | 70 | tty_insert_flip_string(tty, data, urb->actual_length); |
71 | tty_flip_buffer_push(tty); | 71 | tty_flip_buffer_push(tty); |
72 | } | 72 | } |
73 | tty_kref_put(tty); | ||
73 | 74 | ||
74 | exit: | 75 | exit: |
75 | result = usb_submit_urb(urb, GFP_ATOMIC); | 76 | result = usb_submit_urb(urb, GFP_ATOMIC); |
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index ae8e227f3db2..c4d70b0f1e48 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c | |||
@@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty, | |||
172 | dbg("%s - port %d", __func__, port->number); | 172 | dbg("%s - port %d", __func__, port->number); |
173 | 173 | ||
174 | wport = serial->port[1]; | 174 | wport = serial->port[1]; |
175 | wport->port.tty = tty; /* FIXME */ | 175 | tty_port_tty_set(&wport->port, tty); |
176 | 176 | ||
177 | /* Start reading from the device */ | 177 | /* Start reading from the device */ |
178 | usb_fill_bulk_urb(port->read_urb, serial->dev, | 178 | usb_fill_bulk_urb(port->read_urb, serial->dev, |
@@ -229,9 +229,11 @@ static void omninet_read_bulk_callback(struct urb *urb) | |||
229 | } | 229 | } |
230 | 230 | ||
231 | if (urb->actual_length && header->oh_len) { | 231 | if (urb->actual_length && header->oh_len) { |
232 | tty_insert_flip_string(port->port.tty, | 232 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
233 | data + OMNINET_DATAOFFSET, header->oh_len); | 233 | tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, |
234 | tty_flip_buffer_push(port->port.tty); | 234 | header->oh_len); |
235 | tty_flip_buffer_push(tty); | ||
236 | tty_kref_put(tty); | ||
235 | } | 237 | } |
236 | 238 | ||
237 | /* Continue trying to always read */ | 239 | /* Continue trying to always read */ |
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 73f8277f88f2..6b1727e751e3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb) | |||
571 | dbg("%s: nonzero status: %d on endpoint %02x.", | 571 | dbg("%s: nonzero status: %d on endpoint %02x.", |
572 | __func__, status, endpoint); | 572 | __func__, status, endpoint); |
573 | } else { | 573 | } else { |
574 | tty = port->port.tty; | 574 | tty = tty_port_tty_get(&port->port); |
575 | if (urb->actual_length) { | 575 | if (urb->actual_length) { |
576 | tty_buffer_request_room(tty, urb->actual_length); | 576 | tty_buffer_request_room(tty, urb->actual_length); |
577 | tty_insert_flip_string(tty, data, urb->actual_length); | 577 | tty_insert_flip_string(tty, data, urb->actual_length); |
578 | tty_flip_buffer_push(tty); | 578 | tty_flip_buffer_push(tty); |
579 | } else { | 579 | } else |
580 | dbg("%s: empty read urb received", __func__); | 580 | dbg("%s: empty read urb received", __func__); |
581 | } | 581 | tty_kref_put(tty); |
582 | 582 | ||
583 | /* Resubmit urb so we continue receiving */ | 583 | /* Resubmit urb so we continue receiving */ |
584 | if (port->port.count && status != -ESHUTDOWN) { | 584 | if (port->port.count && status != -ESHUTDOWN) { |
@@ -647,9 +647,13 @@ static void option_instat_callback(struct urb *urb) | |||
647 | portdata->dsr_state = ((signals & 0x02) ? 1 : 0); | 647 | portdata->dsr_state = ((signals & 0x02) ? 1 : 0); |
648 | portdata->ri_state = ((signals & 0x08) ? 1 : 0); | 648 | portdata->ri_state = ((signals & 0x08) ? 1 : 0); |
649 | 649 | ||
650 | if (port->port.tty && !C_CLOCAL(port->port.tty) && | 650 | if (old_dcd_state && !portdata->dcd_state) { |
651 | old_dcd_state && !portdata->dcd_state) | 651 | struct tty_struct *tty = |
652 | tty_hangup(port->port.tty); | 652 | tty_port_tty_get(&port->port); |
653 | if (tty && !C_CLOCAL(tty)) | ||
654 | tty_hangup(tty); | ||
655 | tty_kref_put(tty); | ||
656 | } | ||
653 | } else { | 657 | } else { |
654 | dbg("%s: type %x req %x", __func__, | 658 | dbg("%s: type %x req %x", __func__, |
655 | req_pkt->bRequestType, req_pkt->bRequest); | 659 | req_pkt->bRequestType, req_pkt->bRequest); |
@@ -793,7 +797,7 @@ static void option_close(struct tty_struct *tty, | |||
793 | for (i = 0; i < N_OUT_URB; i++) | 797 | for (i = 0; i < N_OUT_URB; i++) |
794 | usb_kill_urb(portdata->out_urbs[i]); | 798 | usb_kill_urb(portdata->out_urbs[i]); |
795 | } | 799 | } |
796 | port->port.tty = NULL; /* FIXME */ | 800 | tty_port_tty_set(&port->port, NULL); |
797 | } | 801 | } |
798 | 802 | ||
799 | /* Helper functions used by option_setup_urbs */ | 803 | /* Helper functions used by option_setup_urbs */ |
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 81db5715ee25..ba551f00f16f 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c | |||
@@ -224,10 +224,6 @@ struct oti6858_private { | |||
224 | struct usb_serial_port *port; /* USB port with which associated */ | 224 | struct usb_serial_port *port; /* USB port with which associated */ |
225 | }; | 225 | }; |
226 | 226 | ||
227 | #undef dbg | ||
228 | /* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */ | ||
229 | #define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg) | ||
230 | |||
231 | static void setup_line(struct work_struct *work) | 227 | static void setup_line(struct work_struct *work) |
232 | { | 228 | { |
233 | struct oti6858_private *priv = container_of(work, | 229 | struct oti6858_private *priv = container_of(work, |
@@ -1002,11 +998,12 @@ static void oti6858_read_bulk_callback(struct urb *urb) | |||
1002 | return; | 998 | return; |
1003 | } | 999 | } |
1004 | 1000 | ||
1005 | tty = port->port.tty; | 1001 | tty = tty_port_tty_get(&port->port); |
1006 | if (tty != NULL && urb->actual_length > 0) { | 1002 | if (tty != NULL && urb->actual_length > 0) { |
1007 | tty_insert_flip_string(tty, data, urb->actual_length); | 1003 | tty_insert_flip_string(tty, data, urb->actual_length); |
1008 | tty_flip_buffer_push(tty); | 1004 | tty_flip_buffer_push(tty); |
1009 | } | 1005 | } |
1006 | tty_kref_put(tty); | ||
1010 | 1007 | ||
1011 | /* schedule the interrupt urb if we are still open */ | 1008 | /* schedule the interrupt urb if we are still open */ |
1012 | if (port->port.count != 0) { | 1009 | if (port->port.count != 0) { |
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1ede1441cb1b..908437847165 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c | |||
@@ -154,7 +154,6 @@ struct pl2303_private { | |||
154 | wait_queue_head_t delta_msr_wait; | 154 | wait_queue_head_t delta_msr_wait; |
155 | u8 line_control; | 155 | u8 line_control; |
156 | u8 line_status; | 156 | u8 line_status; |
157 | u8 termios_initialized; | ||
158 | enum pl2303_type type; | 157 | enum pl2303_type type; |
159 | }; | 158 | }; |
160 | 159 | ||
@@ -526,16 +525,6 @@ static void pl2303_set_termios(struct tty_struct *tty, | |||
526 | 525 | ||
527 | dbg("%s - port %d", __func__, port->number); | 526 | dbg("%s - port %d", __func__, port->number); |
528 | 527 | ||
529 | spin_lock_irqsave(&priv->lock, flags); | ||
530 | if (!priv->termios_initialized) { | ||
531 | *(tty->termios) = tty_std_termios; | ||
532 | tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
533 | tty->termios->c_ispeed = 9600; | ||
534 | tty->termios->c_ospeed = 9600; | ||
535 | priv->termios_initialized = 1; | ||
536 | } | ||
537 | spin_unlock_irqrestore(&priv->lock, flags); | ||
538 | |||
539 | /* The PL2303 is reported to lose bytes if you change | 528 | /* The PL2303 is reported to lose bytes if you change |
540 | serial settings even to the same values as before. Thus | 529 | serial settings even to the same values as before. Thus |
541 | we actually need to filter in this specific case */ | 530 | we actually need to filter in this specific case */ |
@@ -1057,7 +1046,7 @@ static void pl2303_read_bulk_callback(struct urb *urb) | |||
1057 | tty_flag = TTY_FRAME; | 1046 | tty_flag = TTY_FRAME; |
1058 | dbg("%s - tty_flag = %d", __func__, tty_flag); | 1047 | dbg("%s - tty_flag = %d", __func__, tty_flag); |
1059 | 1048 | ||
1060 | tty = port->port.tty; | 1049 | tty = tty_port_tty_get(&port->port); |
1061 | if (tty && urb->actual_length) { | 1050 | if (tty && urb->actual_length) { |
1062 | tty_buffer_request_room(tty, urb->actual_length + 1); | 1051 | tty_buffer_request_room(tty, urb->actual_length + 1); |
1063 | /* overrun is special, not associated with a char */ | 1052 | /* overrun is special, not associated with a char */ |
@@ -1067,7 +1056,7 @@ static void pl2303_read_bulk_callback(struct urb *urb) | |||
1067 | tty_insert_flip_char(tty, data[i], tty_flag); | 1056 | tty_insert_flip_char(tty, data[i], tty_flag); |
1068 | tty_flip_buffer_push(tty); | 1057 | tty_flip_buffer_push(tty); |
1069 | } | 1058 | } |
1070 | 1059 | tty_kref_put(tty); | |
1071 | /* Schedule the next read _if_ we are still open */ | 1060 | /* Schedule the next read _if_ we are still open */ |
1072 | if (port->port.count) { | 1061 | if (port->port.count) { |
1073 | urb->dev = port->serial->dev; | 1062 | urb->dev = port->serial->dev; |
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index def52d07a4ea..72903ac9f5c0 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c | |||
@@ -217,6 +217,7 @@ static void safe_read_bulk_callback(struct urb *urb) | |||
217 | struct usb_serial_port *port = urb->context; | 217 | struct usb_serial_port *port = urb->context; |
218 | unsigned char *data = urb->transfer_buffer; | 218 | unsigned char *data = urb->transfer_buffer; |
219 | unsigned char length = urb->actual_length; | 219 | unsigned char length = urb->actual_length; |
220 | struct tty_struct *tty; | ||
220 | int result; | 221 | int result; |
221 | int status = urb->status; | 222 | int status = urb->status; |
222 | 223 | ||
@@ -242,6 +243,7 @@ static void safe_read_bulk_callback(struct urb *urb) | |||
242 | printk("\n"); | 243 | printk("\n"); |
243 | } | 244 | } |
244 | #endif | 245 | #endif |
246 | tty = tty_port_tty_get(&port->port); | ||
245 | if (safe) { | 247 | if (safe) { |
246 | __u16 fcs; | 248 | __u16 fcs; |
247 | fcs = fcs_compute10(data, length, CRC10_INITFCS); | 249 | fcs = fcs_compute10(data, length, CRC10_INITFCS); |
@@ -250,9 +252,9 @@ static void safe_read_bulk_callback(struct urb *urb) | |||
250 | if (actual_length <= (length - 2)) { | 252 | if (actual_length <= (length - 2)) { |
251 | info("%s - actual: %d", __func__, | 253 | info("%s - actual: %d", __func__, |
252 | actual_length); | 254 | actual_length); |
253 | tty_insert_flip_string(port->port.tty, | 255 | tty_insert_flip_string(tty, |
254 | data, actual_length); | 256 | data, actual_length); |
255 | tty_flip_buffer_push(port->port.tty); | 257 | tty_flip_buffer_push(tty); |
256 | } else { | 258 | } else { |
257 | err("%s - inconsistent lengths %d:%d", | 259 | err("%s - inconsistent lengths %d:%d", |
258 | __func__, actual_length, length); | 260 | __func__, actual_length, length); |
@@ -261,9 +263,10 @@ static void safe_read_bulk_callback(struct urb *urb) | |||
261 | err("%s - bad CRC %x", __func__, fcs); | 263 | err("%s - bad CRC %x", __func__, fcs); |
262 | } | 264 | } |
263 | } else { | 265 | } else { |
264 | tty_insert_flip_string(port->port.tty, data, length); | 266 | tty_insert_flip_string(tty, data, length); |
265 | tty_flip_buffer_push(port->port.tty); | 267 | tty_flip_buffer_push(tty); |
266 | } | 268 | } |
269 | tty_kref_put(tty); | ||
267 | 270 | ||
268 | /* Continue trying to always read */ | 271 | /* Continue trying to always read */ |
269 | usb_fill_bulk_urb(urb, port->serial->dev, | 272 | usb_fill_bulk_urb(urb, port->serial->dev, |
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index ea1a103c99be..8b9eaf383679 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
@@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb) | |||
440 | dbg("%s: nonzero status: %d on endpoint %02x.", | 440 | dbg("%s: nonzero status: %d on endpoint %02x.", |
441 | __func__, status, endpoint); | 441 | __func__, status, endpoint); |
442 | } else { | 442 | } else { |
443 | tty = port->port.tty; | ||
444 | if (urb->actual_length) { | 443 | if (urb->actual_length) { |
444 | tty = tty_port_tty_get(&port->port); | ||
445 | tty_buffer_request_room(tty, urb->actual_length); | 445 | tty_buffer_request_room(tty, urb->actual_length); |
446 | tty_insert_flip_string(tty, data, urb->actual_length); | 446 | tty_insert_flip_string(tty, data, urb->actual_length); |
447 | tty_flip_buffer_push(tty); | 447 | tty_flip_buffer_push(tty); |
448 | } else { | 448 | tty_kref_put(tty); |
449 | } else | ||
449 | dbg("%s: empty read urb received", __func__); | 450 | dbg("%s: empty read urb received", __func__); |
450 | } | ||
451 | 451 | ||
452 | /* Resubmit urb so we continue receiving */ | 452 | /* Resubmit urb so we continue receiving */ |
453 | if (port->port.count && status != -ESHUTDOWN) { | 453 | if (port->port.count && status != -ESHUTDOWN) { |
@@ -485,6 +485,7 @@ static void sierra_instat_callback(struct urb *urb) | |||
485 | unsigned char signals = *((unsigned char *) | 485 | unsigned char signals = *((unsigned char *) |
486 | urb->transfer_buffer + | 486 | urb->transfer_buffer + |
487 | sizeof(struct usb_ctrlrequest)); | 487 | sizeof(struct usb_ctrlrequest)); |
488 | struct tty_struct *tty; | ||
488 | 489 | ||
489 | dbg("%s: signal x%x", __func__, signals); | 490 | dbg("%s: signal x%x", __func__, signals); |
490 | 491 | ||
@@ -494,9 +495,11 @@ static void sierra_instat_callback(struct urb *urb) | |||
494 | portdata->dsr_state = ((signals & 0x02) ? 1 : 0); | 495 | portdata->dsr_state = ((signals & 0x02) ? 1 : 0); |
495 | portdata->ri_state = ((signals & 0x08) ? 1 : 0); | 496 | portdata->ri_state = ((signals & 0x08) ? 1 : 0); |
496 | 497 | ||
497 | if (port->port.tty && !C_CLOCAL(port->port.tty) && | 498 | tty = tty_port_tty_get(&port->port); |
499 | if (tty && !C_CLOCAL(tty) && | ||
498 | old_dcd_state && !portdata->dcd_state) | 500 | old_dcd_state && !portdata->dcd_state) |
499 | tty_hangup(port->port.tty); | 501 | tty_hangup(tty); |
502 | tty_kref_put(tty); | ||
500 | } else { | 503 | } else { |
501 | dbg("%s: type %x req %x", __func__, | 504 | dbg("%s: type %x req %x", __func__, |
502 | req_pkt->bRequestType, req_pkt->bRequest); | 505 | req_pkt->bRequestType, req_pkt->bRequest); |
@@ -616,8 +619,7 @@ static void sierra_close(struct tty_struct *tty, | |||
616 | } | 619 | } |
617 | 620 | ||
618 | usb_kill_urb(port->interrupt_in_urb); | 621 | usb_kill_urb(port->interrupt_in_urb); |
619 | 622 | tty_port_tty_set(&port->port, NULL); | |
620 | port->port.tty = NULL; /* FIXME */ | ||
621 | } | 623 | } |
622 | 624 | ||
623 | static int sierra_startup(struct usb_serial *serial) | 625 | static int sierra_startup(struct usb_serial *serial) |
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 283cf6b36b2c..1533d6e12238 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c | |||
@@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb) | |||
755 | tty_flag = TTY_FRAME; | 755 | tty_flag = TTY_FRAME; |
756 | dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); | 756 | dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); |
757 | 757 | ||
758 | tty = port->port.tty; | 758 | tty = tty_port_tty_get(&port->port); |
759 | if (tty && urb->actual_length) { | 759 | if (tty && urb->actual_length) { |
760 | tty_buffer_request_room(tty, urb->actual_length + 1); | 760 | tty_buffer_request_room(tty, urb->actual_length + 1); |
761 | /* overrun is special, not associated with a char */ | 761 | /* overrun is special, not associated with a char */ |
@@ -765,6 +765,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb) | |||
765 | tty_insert_flip_char(tty, data[i], tty_flag); | 765 | tty_insert_flip_char(tty, data[i], tty_flag); |
766 | tty_flip_buffer_push(tty); | 766 | tty_flip_buffer_push(tty); |
767 | } | 767 | } |
768 | tty_kref_put(tty); | ||
768 | 769 | ||
769 | /* Schedule the next read _if_ we are still open */ | 770 | /* Schedule the next read _if_ we are still open */ |
770 | if (port->port.count) { | 771 | if (port->port.count) { |
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 9a3e495c769c..c90237d48b0e 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c | |||
@@ -179,7 +179,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); | |||
179 | static int ti_get_lsr(struct ti_port *tport); | 179 | static int ti_get_lsr(struct ti_port *tport); |
180 | static int ti_get_serial_info(struct ti_port *tport, | 180 | static int ti_get_serial_info(struct ti_port *tport, |
181 | struct serial_struct __user *ret_arg); | 181 | struct serial_struct __user *ret_arg); |
182 | static int ti_set_serial_info(struct ti_port *tport, | 182 | static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, |
183 | struct serial_struct __user *new_arg); | 183 | struct serial_struct __user *new_arg); |
184 | static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); | 184 | static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); |
185 | 185 | ||
@@ -857,8 +857,8 @@ static int ti_ioctl(struct tty_struct *tty, struct file *file, | |||
857 | (struct serial_struct __user *)arg); | 857 | (struct serial_struct __user *)arg); |
858 | case TIOCSSERIAL: | 858 | case TIOCSSERIAL: |
859 | dbg("%s - (%d) TIOCSSERIAL", __func__, port->number); | 859 | dbg("%s - (%d) TIOCSSERIAL", __func__, port->number); |
860 | return ti_set_serial_info(tport, | 860 | return ti_set_serial_info(tty, tport, |
861 | (struct serial_struct __user *)arg); | 861 | (struct serial_struct __user *)arg); |
862 | case TIOCMIWAIT: | 862 | case TIOCMIWAIT: |
863 | dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); | 863 | dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); |
864 | cprev = tport->tp_icount; | 864 | cprev = tport->tp_icount; |
@@ -1211,6 +1211,7 @@ static void ti_bulk_in_callback(struct urb *urb) | |||
1211 | struct device *dev = &urb->dev->dev; | 1211 | struct device *dev = &urb->dev->dev; |
1212 | int status = urb->status; | 1212 | int status = urb->status; |
1213 | int retval = 0; | 1213 | int retval = 0; |
1214 | struct tty_struct *tty; | ||
1214 | 1215 | ||
1215 | dbg("%s", __func__); | 1216 | dbg("%s", __func__); |
1216 | 1217 | ||
@@ -1239,20 +1240,22 @@ static void ti_bulk_in_callback(struct urb *urb) | |||
1239 | return; | 1240 | return; |
1240 | } | 1241 | } |
1241 | 1242 | ||
1242 | if (port->port.tty && urb->actual_length) { | 1243 | tty = tty_port_tty_get(&port->port); |
1244 | if (tty && urb->actual_length) { | ||
1243 | usb_serial_debug_data(debug, dev, __func__, | 1245 | usb_serial_debug_data(debug, dev, __func__, |
1244 | urb->actual_length, urb->transfer_buffer); | 1246 | urb->actual_length, urb->transfer_buffer); |
1245 | 1247 | ||
1246 | if (!tport->tp_is_open) | 1248 | if (!tport->tp_is_open) |
1247 | dbg("%s - port closed, dropping data", __func__); | 1249 | dbg("%s - port closed, dropping data", __func__); |
1248 | else | 1250 | else |
1249 | ti_recv(&urb->dev->dev, port->port.tty, | 1251 | ti_recv(&urb->dev->dev, tty, |
1250 | urb->transfer_buffer, | 1252 | urb->transfer_buffer, |
1251 | urb->actual_length); | 1253 | urb->actual_length); |
1252 | 1254 | ||
1253 | spin_lock(&tport->tp_lock); | 1255 | spin_lock(&tport->tp_lock); |
1254 | tport->tp_icount.rx += urb->actual_length; | 1256 | tport->tp_icount.rx += urb->actual_length; |
1255 | spin_unlock(&tport->tp_lock); | 1257 | spin_unlock(&tport->tp_lock); |
1258 | tty_kref_put(tty); | ||
1256 | } | 1259 | } |
1257 | 1260 | ||
1258 | exit: | 1261 | exit: |
@@ -1330,7 +1333,7 @@ static void ti_send(struct ti_port *tport) | |||
1330 | { | 1333 | { |
1331 | int count, result; | 1334 | int count, result; |
1332 | struct usb_serial_port *port = tport->tp_port; | 1335 | struct usb_serial_port *port = tport->tp_port; |
1333 | struct tty_struct *tty = port->port.tty; /* FIXME */ | 1336 | struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ |
1334 | unsigned long flags; | 1337 | unsigned long flags; |
1335 | 1338 | ||
1336 | 1339 | ||
@@ -1338,19 +1341,15 @@ static void ti_send(struct ti_port *tport) | |||
1338 | 1341 | ||
1339 | spin_lock_irqsave(&tport->tp_lock, flags); | 1342 | spin_lock_irqsave(&tport->tp_lock, flags); |
1340 | 1343 | ||
1341 | if (tport->tp_write_urb_in_use) { | 1344 | if (tport->tp_write_urb_in_use) |
1342 | spin_unlock_irqrestore(&tport->tp_lock, flags); | 1345 | goto unlock; |
1343 | return; | ||
1344 | } | ||
1345 | 1346 | ||
1346 | count = ti_buf_get(tport->tp_write_buf, | 1347 | count = ti_buf_get(tport->tp_write_buf, |
1347 | port->write_urb->transfer_buffer, | 1348 | port->write_urb->transfer_buffer, |
1348 | port->bulk_out_size); | 1349 | port->bulk_out_size); |
1349 | 1350 | ||
1350 | if (count == 0) { | 1351 | if (count == 0) |
1351 | spin_unlock_irqrestore(&tport->tp_lock, flags); | 1352 | goto unlock; |
1352 | return; | ||
1353 | } | ||
1354 | 1353 | ||
1355 | tport->tp_write_urb_in_use = 1; | 1354 | tport->tp_write_urb_in_use = 1; |
1356 | 1355 | ||
@@ -1380,7 +1379,13 @@ static void ti_send(struct ti_port *tport) | |||
1380 | /* more room in the buffer for new writes, wakeup */ | 1379 | /* more room in the buffer for new writes, wakeup */ |
1381 | if (tty) | 1380 | if (tty) |
1382 | tty_wakeup(tty); | 1381 | tty_wakeup(tty); |
1382 | tty_kref_put(tty); | ||
1383 | wake_up_interruptible(&tport->tp_write_wait); | 1383 | wake_up_interruptible(&tport->tp_write_wait); |
1384 | return; | ||
1385 | unlock: | ||
1386 | spin_unlock_irqrestore(&tport->tp_lock, flags); | ||
1387 | tty_kref_put(tty); | ||
1388 | return; | ||
1384 | } | 1389 | } |
1385 | 1390 | ||
1386 | 1391 | ||
@@ -1464,20 +1469,16 @@ static int ti_get_serial_info(struct ti_port *tport, | |||
1464 | } | 1469 | } |
1465 | 1470 | ||
1466 | 1471 | ||
1467 | static int ti_set_serial_info(struct ti_port *tport, | 1472 | static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, |
1468 | struct serial_struct __user *new_arg) | 1473 | struct serial_struct __user *new_arg) |
1469 | { | 1474 | { |
1470 | struct usb_serial_port *port = tport->tp_port; | ||
1471 | struct serial_struct new_serial; | 1475 | struct serial_struct new_serial; |
1472 | 1476 | ||
1473 | if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) | 1477 | if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) |
1474 | return -EFAULT; | 1478 | return -EFAULT; |
1475 | 1479 | ||
1476 | tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; | 1480 | tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; |
1477 | /* FIXME */ | 1481 | tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
1478 | if (port->port.tty) | ||
1479 | port->port.tty->low_latency = | ||
1480 | (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
1481 | tport->tp_closing_wait = new_serial.closing_wait; | 1482 | tport->tp_closing_wait = new_serial.closing_wait; |
1482 | 1483 | ||
1483 | return 0; | 1484 | return 0; |
@@ -1510,7 +1511,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) | |||
1510 | tport->tp_msr = msr & TI_MSR_MASK; | 1511 | tport->tp_msr = msr & TI_MSR_MASK; |
1511 | 1512 | ||
1512 | /* handle CTS flow control */ | 1513 | /* handle CTS flow control */ |
1513 | tty = tport->tp_port->port.tty; | 1514 | tty = tty_port_tty_get(&tport->tp_port->port); |
1514 | if (tty && C_CRTSCTS(tty)) { | 1515 | if (tty && C_CRTSCTS(tty)) { |
1515 | if (msr & TI_MSR_CTS) { | 1516 | if (msr & TI_MSR_CTS) { |
1516 | tty->hw_stopped = 0; | 1517 | tty->hw_stopped = 0; |
@@ -1519,6 +1520,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) | |||
1519 | tty->hw_stopped = 1; | 1520 | tty->hw_stopped = 1; |
1520 | } | 1521 | } |
1521 | } | 1522 | } |
1523 | tty_kref_put(tty); | ||
1522 | } | 1524 | } |
1523 | 1525 | ||
1524 | 1526 | ||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4f7f9e3ae0a4..e7d4246027b2 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
214 | /* set up our port structure making the tty driver | 214 | /* set up our port structure making the tty driver |
215 | * remember our port object, and us it */ | 215 | * remember our port object, and us it */ |
216 | tty->driver_data = port; | 216 | tty->driver_data = port; |
217 | port->port.tty = tty; | 217 | tty_port_tty_set(&port->port, tty); |
218 | 218 | ||
219 | if (port->port.count == 1) { | 219 | if (port->port.count == 1) { |
220 | 220 | ||
@@ -246,7 +246,7 @@ bailout_module_put: | |||
246 | bailout_mutex_unlock: | 246 | bailout_mutex_unlock: |
247 | port->port.count = 0; | 247 | port->port.count = 0; |
248 | tty->driver_data = NULL; | 248 | tty->driver_data = NULL; |
249 | port->port.tty = NULL; | 249 | tty_port_tty_set(&port->port, NULL); |
250 | mutex_unlock(&port->mutex); | 250 | mutex_unlock(&port->mutex); |
251 | bailout_kref_put: | 251 | bailout_kref_put: |
252 | usb_serial_put(serial); | 252 | usb_serial_put(serial); |
@@ -276,10 +276,11 @@ static void serial_close(struct tty_struct *tty, struct file *filp) | |||
276 | port->serial->type->close(tty, port, filp); | 276 | port->serial->type->close(tty, port, filp); |
277 | 277 | ||
278 | if (port->port.count == (port->console? 1 : 0)) { | 278 | if (port->port.count == (port->console? 1 : 0)) { |
279 | if (port->port.tty) { | 279 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
280 | if (port->port.tty->driver_data) | 280 | if (tty) { |
281 | port->port.tty->driver_data = NULL; | 281 | if (tty->driver_data) |
282 | port->port.tty = NULL; | 282 | tty->driver_data = NULL; |
283 | tty_port_tty_set(&port->port, NULL); | ||
283 | } | 284 | } |
284 | } | 285 | } |
285 | 286 | ||
@@ -508,11 +509,12 @@ static void usb_serial_port_work(struct work_struct *work) | |||
508 | if (!port) | 509 | if (!port) |
509 | return; | 510 | return; |
510 | 511 | ||
511 | tty = port->port.tty; | 512 | tty = tty_port_tty_get(&port->port); |
512 | if (!tty) | 513 | if (!tty) |
513 | return; | 514 | return; |
514 | 515 | ||
515 | tty_wakeup(tty); | 516 | tty_wakeup(tty); |
517 | tty_kref_put(tty); | ||
516 | } | 518 | } |
517 | 519 | ||
518 | static void port_release(struct device *dev) | 520 | static void port_release(struct device *dev) |
@@ -819,6 +821,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
819 | port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); | 821 | port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); |
820 | if (!port) | 822 | if (!port) |
821 | goto probe_error; | 823 | goto probe_error; |
824 | tty_port_init(&port->port); | ||
822 | port->serial = serial; | 825 | port->serial = serial; |
823 | spin_lock_init(&port->lock); | 826 | spin_lock_init(&port->lock); |
824 | mutex_init(&port->mutex); | 827 | mutex_init(&port->mutex); |
@@ -1040,8 +1043,11 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1040 | for (i = 0; i < serial->num_ports; ++i) { | 1043 | for (i = 0; i < serial->num_ports; ++i) { |
1041 | port = serial->port[i]; | 1044 | port = serial->port[i]; |
1042 | if (port) { | 1045 | if (port) { |
1043 | if (port->port.tty) | 1046 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
1044 | tty_hangup(port->port.tty); | 1047 | if (tty) { |
1048 | tty_hangup(tty); | ||
1049 | tty_kref_put(tty); | ||
1050 | } | ||
1045 | kill_traffic(port); | 1051 | kill_traffic(port); |
1046 | } | 1052 | } |
1047 | } | 1053 | } |
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index cf8924f9a2cc..a6d1c75a1c89 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c | |||
@@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb) | |||
499 | int status = urb->status; | 499 | int status = urb->status; |
500 | struct tty_struct *tty; | 500 | struct tty_struct *tty; |
501 | int result; | 501 | int result; |
502 | int available_room; | 502 | int available_room = 0; |
503 | 503 | ||
504 | dbg("%s - port %d", __func__, port->number); | 504 | dbg("%s - port %d", __func__, port->number); |
505 | 505 | ||
@@ -512,13 +512,17 @@ static void visor_read_bulk_callback(struct urb *urb) | |||
512 | usb_serial_debug_data(debug, &port->dev, __func__, | 512 | usb_serial_debug_data(debug, &port->dev, __func__, |
513 | urb->actual_length, data); | 513 | urb->actual_length, data); |
514 | 514 | ||
515 | tty = port->port.tty; | 515 | if (urb->actual_length) { |
516 | if (tty && urb->actual_length) { | 516 | tty = tty_port_tty_get(&port->port); |
517 | available_room = tty_buffer_request_room(tty, | 517 | if (tty) { |
518 | available_room = tty_buffer_request_room(tty, | ||
518 | urb->actual_length); | 519 | urb->actual_length); |
519 | if (available_room) { | 520 | if (available_room) { |
520 | tty_insert_flip_string(tty, data, available_room); | 521 | tty_insert_flip_string(tty, data, |
521 | tty_flip_buffer_push(tty); | 522 | available_room); |
523 | tty_flip_buffer_push(tty); | ||
524 | } | ||
525 | tty_kref_put(tty); | ||
522 | } | 526 | } |
523 | spin_lock(&priv->lock); | 527 | spin_lock(&priv->lock); |
524 | priv->bytes_in += available_room; | 528 | priv->bytes_in += available_room; |
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 3a9d14384a43..11c8b97a5177 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c | |||
@@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work) | |||
1481 | struct whiteheat_private *info = | 1481 | struct whiteheat_private *info = |
1482 | container_of(work, struct whiteheat_private, rx_work); | 1482 | container_of(work, struct whiteheat_private, rx_work); |
1483 | struct usb_serial_port *port = info->port; | 1483 | struct usb_serial_port *port = info->port; |
1484 | struct tty_struct *tty = port->port.tty; | 1484 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
1485 | struct whiteheat_urb_wrap *wrap; | 1485 | struct whiteheat_urb_wrap *wrap; |
1486 | struct urb *urb; | 1486 | struct urb *urb; |
1487 | unsigned long flags; | 1487 | unsigned long flags; |
@@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work) | |||
1493 | spin_lock_irqsave(&info->lock, flags); | 1493 | spin_lock_irqsave(&info->lock, flags); |
1494 | if (info->flags & THROTTLED) { | 1494 | if (info->flags & THROTTLED) { |
1495 | spin_unlock_irqrestore(&info->lock, flags); | 1495 | spin_unlock_irqrestore(&info->lock, flags); |
1496 | return; | 1496 | goto out; |
1497 | } | 1497 | } |
1498 | 1498 | ||
1499 | list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { | 1499 | list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { |
@@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work) | |||
1513 | spin_unlock_irqrestore(&info->lock, flags); | 1513 | spin_unlock_irqrestore(&info->lock, flags); |
1514 | tty_flip_buffer_push(tty); | 1514 | tty_flip_buffer_push(tty); |
1515 | schedule_work(&info->rx_work); | 1515 | schedule_work(&info->rx_work); |
1516 | return; | 1516 | goto out; |
1517 | } | 1517 | } |
1518 | tty_insert_flip_string(tty, urb->transfer_buffer, len); | 1518 | tty_insert_flip_string(tty, urb->transfer_buffer, len); |
1519 | sent += len; | 1519 | sent += len; |
@@ -1536,6 +1536,8 @@ static void rx_data_softint(struct work_struct *work) | |||
1536 | 1536 | ||
1537 | if (sent) | 1537 | if (sent) |
1538 | tty_flip_buffer_push(tty); | 1538 | tty_flip_buffer_push(tty); |
1539 | out: | ||
1540 | tty_kref_put(tty); | ||
1539 | } | 1541 | } |
1540 | 1542 | ||
1541 | 1543 | ||
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 385cba40ea87..06964af761c6 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c | |||
@@ -111,6 +111,4 @@ module_exit(mbp_exit); | |||
111 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | 111 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); |
112 | MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver"); | 112 | MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver"); |
113 | MODULE_LICENSE("GPL"); | 113 | MODULE_LICENSE("GPL"); |
114 | MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1"); | 114 | MODULE_DEVICE_TABLE(dmi, mbp_device_table); |
115 | MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2"); | ||
116 | MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1"); | ||
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 4a551af6f3fc..17c9c5ec14c5 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt | |||
@@ -59,10 +59,12 @@ config BINFMT_SHARED_FLAT | |||
59 | help | 59 | help |
60 | Support FLAT shared libraries | 60 | Support FLAT shared libraries |
61 | 61 | ||
62 | config HAVE_AOUT | ||
63 | def_bool n | ||
64 | |||
62 | config BINFMT_AOUT | 65 | config BINFMT_AOUT |
63 | tristate "Kernel support for a.out and ECOFF binaries" | 66 | tristate "Kernel support for a.out and ECOFF binaries" |
64 | depends on ARCH_SUPPORTS_AOUT && \ | 67 | depends on HAVE_AOUT |
65 | (X86_32 || ALPHA || ARM || M68K) | ||
66 | ---help--- | 68 | ---help--- |
67 | A.out (Assembler.OUTput) is a set of formats for libraries and | 69 | A.out (Assembler.OUTput) is a set of formats for libraries and |
68 | executables used in the earliest versions of UNIX. Linux used | 70 | executables used in the earliest versions of UNIX. Linux used |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 08e28c9bb416..3dbe2169cf36 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -26,8 +26,7 @@ | |||
26 | #include <linux/debugfs.h> | 26 | #include <linux/debugfs.h> |
27 | #include <linux/fsnotify.h> | 27 | #include <linux/fsnotify.h> |
28 | #include <linux/string.h> | 28 | #include <linux/string.h> |
29 | 29 | #include <linux/magic.h> | |
30 | #define DEBUGFS_MAGIC 0x64626720 | ||
31 | 30 | ||
32 | static struct vfsmount *debugfs_mount; | 31 | static struct vfsmount *debugfs_mount; |
33 | static int debugfs_mount_count; | 32 | static int debugfs_mount_count; |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 488eb424f662..a70d5d0890c7 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #define DEVPTS_SUPER_MAGIC 0x1cd1 | 27 | #define DEVPTS_SUPER_MAGIC 0x1cd1 |
28 | 28 | ||
29 | #define DEVPTS_DEFAULT_MODE 0600 | 29 | #define DEVPTS_DEFAULT_MODE 0600 |
30 | #define PTMX_MINOR 2 | ||
30 | 31 | ||
31 | extern int pty_limit; /* Config limit on Unix98 ptys */ | 32 | extern int pty_limit; /* Config limit on Unix98 ptys */ |
32 | static DEFINE_IDA(allocated_ptys); | 33 | static DEFINE_IDA(allocated_ptys); |
@@ -169,15 +170,7 @@ static struct file_system_type devpts_fs_type = { | |||
169 | * to the System V naming convention | 170 | * to the System V naming convention |
170 | */ | 171 | */ |
171 | 172 | ||
172 | static struct dentry *get_node(int num) | 173 | int devpts_new_index(struct inode *ptmx_inode) |
173 | { | ||
174 | char s[12]; | ||
175 | struct dentry *root = devpts_root; | ||
176 | mutex_lock(&root->d_inode->i_mutex); | ||
177 | return lookup_one_len(s, root, sprintf(s, "%d", num)); | ||
178 | } | ||
179 | |||
180 | int devpts_new_index(void) | ||
181 | { | 174 | { |
182 | int index; | 175 | int index; |
183 | int ida_ret; | 176 | int ida_ret; |
@@ -205,20 +198,21 @@ retry: | |||
205 | return index; | 198 | return index; |
206 | } | 199 | } |
207 | 200 | ||
208 | void devpts_kill_index(int idx) | 201 | void devpts_kill_index(struct inode *ptmx_inode, int idx) |
209 | { | 202 | { |
210 | mutex_lock(&allocated_ptys_lock); | 203 | mutex_lock(&allocated_ptys_lock); |
211 | ida_remove(&allocated_ptys, idx); | 204 | ida_remove(&allocated_ptys, idx); |
212 | mutex_unlock(&allocated_ptys_lock); | 205 | mutex_unlock(&allocated_ptys_lock); |
213 | } | 206 | } |
214 | 207 | ||
215 | int devpts_pty_new(struct tty_struct *tty) | 208 | int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) |
216 | { | 209 | { |
217 | int number = tty->index; /* tty layer puts index from devpts_new_index() in here */ | 210 | int number = tty->index; /* tty layer puts index from devpts_new_index() in here */ |
218 | struct tty_driver *driver = tty->driver; | 211 | struct tty_driver *driver = tty->driver; |
219 | dev_t device = MKDEV(driver->major, driver->minor_start+number); | 212 | dev_t device = MKDEV(driver->major, driver->minor_start+number); |
220 | struct dentry *dentry; | 213 | struct dentry *dentry; |
221 | struct inode *inode = new_inode(devpts_mnt->mnt_sb); | 214 | struct inode *inode = new_inode(devpts_mnt->mnt_sb); |
215 | char s[12]; | ||
222 | 216 | ||
223 | /* We're supposed to be given the slave end of a pty */ | 217 | /* We're supposed to be given the slave end of a pty */ |
224 | BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY); | 218 | BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY); |
@@ -233,10 +227,15 @@ int devpts_pty_new(struct tty_struct *tty) | |||
233 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 227 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
234 | init_special_inode(inode, S_IFCHR|config.mode, device); | 228 | init_special_inode(inode, S_IFCHR|config.mode, device); |
235 | inode->i_private = tty; | 229 | inode->i_private = tty; |
230 | tty->driver_data = inode; | ||
236 | 231 | ||
237 | dentry = get_node(number); | 232 | sprintf(s, "%d", number); |
238 | if (!IS_ERR(dentry) && !dentry->d_inode) { | 233 | |
239 | d_instantiate(dentry, inode); | 234 | mutex_lock(&devpts_root->d_inode->i_mutex); |
235 | |||
236 | dentry = d_alloc_name(devpts_root, s); | ||
237 | if (!IS_ERR(dentry)) { | ||
238 | d_add(dentry, inode); | ||
240 | fsnotify_create(devpts_root->d_inode, dentry); | 239 | fsnotify_create(devpts_root->d_inode, dentry); |
241 | } | 240 | } |
242 | 241 | ||
@@ -245,36 +244,31 @@ int devpts_pty_new(struct tty_struct *tty) | |||
245 | return 0; | 244 | return 0; |
246 | } | 245 | } |
247 | 246 | ||
248 | struct tty_struct *devpts_get_tty(int number) | 247 | struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number) |
249 | { | 248 | { |
250 | struct dentry *dentry = get_node(number); | 249 | BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); |
251 | struct tty_struct *tty; | ||
252 | |||
253 | tty = NULL; | ||
254 | if (!IS_ERR(dentry)) { | ||
255 | if (dentry->d_inode) | ||
256 | tty = dentry->d_inode->i_private; | ||
257 | dput(dentry); | ||
258 | } | ||
259 | 250 | ||
260 | mutex_unlock(&devpts_root->d_inode->i_mutex); | 251 | if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) |
261 | 252 | return (struct tty_struct *)pts_inode->i_private; | |
262 | return tty; | 253 | return NULL; |
263 | } | 254 | } |
264 | 255 | ||
265 | void devpts_pty_kill(int number) | 256 | void devpts_pty_kill(struct tty_struct *tty) |
266 | { | 257 | { |
267 | struct dentry *dentry = get_node(number); | 258 | struct inode *inode = tty->driver_data; |
259 | struct dentry *dentry; | ||
268 | 260 | ||
269 | if (!IS_ERR(dentry)) { | 261 | BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); |
270 | struct inode *inode = dentry->d_inode; | 262 | |
271 | if (inode) { | 263 | mutex_lock(&devpts_root->d_inode->i_mutex); |
272 | inode->i_nlink--; | 264 | |
273 | d_delete(dentry); | 265 | dentry = d_find_alias(inode); |
274 | dput(dentry); | 266 | if (dentry && !IS_ERR(dentry)) { |
275 | } | 267 | inode->i_nlink--; |
268 | d_delete(dentry); | ||
276 | dput(dentry); | 269 | dput(dentry); |
277 | } | 270 | } |
271 | |||
278 | mutex_unlock(&devpts_root->d_inode->i_mutex); | 272 | mutex_unlock(&devpts_root->d_inode->i_mutex); |
279 | } | 273 | } |
280 | 274 | ||
diff --git a/fs/dquot.c b/fs/dquot.c index 8ec4d6cc7633..ad7e59003e04 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -895,10 +895,9 @@ static void print_warning(struct dquot *dquot, const int warntype) | |||
895 | warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot)) | 895 | warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot)) |
896 | return; | 896 | return; |
897 | 897 | ||
898 | mutex_lock(&tty_mutex); | ||
899 | tty = get_current_tty(); | 898 | tty = get_current_tty(); |
900 | if (!tty) | 899 | if (!tty) |
901 | goto out_lock; | 900 | return; |
902 | tty_write_message(tty, dquot->dq_sb->s_id); | 901 | tty_write_message(tty, dquot->dq_sb->s_id); |
903 | if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) | 902 | if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) |
904 | tty_write_message(tty, ": warning, "); | 903 | tty_write_message(tty, ": warning, "); |
@@ -926,8 +925,7 @@ static void print_warning(struct dquot *dquot, const int warntype) | |||
926 | break; | 925 | break; |
927 | } | 926 | } |
928 | tty_write_message(tty, msg); | 927 | tty_write_message(tty, msg); |
929 | out_lock: | 928 | tty_kref_put(tty); |
930 | mutex_unlock(&tty_mutex); | ||
931 | } | 929 | } |
932 | #endif | 930 | #endif |
933 | 931 | ||
diff --git a/fs/efs/super.c b/fs/efs/super.c index 567b134fa1f1..73b19cfc91fc 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c | |||
@@ -341,8 +341,6 @@ static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) { | |||
341 | sb->inode_blocks * | 341 | sb->inode_blocks * |
342 | (EFS_BLOCKSIZE / sizeof(struct efs_dinode)); | 342 | (EFS_BLOCKSIZE / sizeof(struct efs_dinode)); |
343 | buf->f_ffree = sb->inode_free; /* free inodes */ | 343 | buf->f_ffree = sb->inode_free; /* free inodes */ |
344 | buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */ | ||
345 | buf->f_fsid.val[1] = sb->fs_magic & 0xffff; /* fs ID */ | ||
346 | buf->f_namelen = EFS_MAXNAMELEN; /* max filename length */ | 344 | buf->f_namelen = EFS_MAXNAMELEN; /* max filename length */ |
347 | 345 | ||
348 | return 0; | 346 | return 0; |
@@ -1141,8 +1141,7 @@ EXPORT_SYMBOL(sys_close); | |||
1141 | asmlinkage long sys_vhangup(void) | 1141 | asmlinkage long sys_vhangup(void) |
1142 | { | 1142 | { |
1143 | if (capable(CAP_SYS_TTY_CONFIG)) { | 1143 | if (capable(CAP_SYS_TTY_CONFIG)) { |
1144 | /* XXX: this needs locking */ | 1144 | tty_vhangup_self(); |
1145 | tty_vhangup(current->signal->tty); | ||
1146 | return 0; | 1145 | return 0; |
1147 | } | 1146 | } |
1148 | return -EPERM; | 1147 | return -EPERM; |
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 73cd7a418f06..50f8f0600f06 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig | |||
@@ -57,3 +57,13 @@ config PROC_SYSCTL | |||
57 | As it is generally a good thing, you should say Y here unless | 57 | As it is generally a good thing, you should say Y here unless |
58 | building a kernel for install/rescue disks or your system is very | 58 | building a kernel for install/rescue disks or your system is very |
59 | limited in memory. | 59 | limited in memory. |
60 | |||
61 | config PROC_PAGE_MONITOR | ||
62 | default y | ||
63 | depends on PROC_FS && MMU | ||
64 | bool "Enable /proc page monitoring" if EMBEDDED | ||
65 | help | ||
66 | Various /proc files exist to monitor process memory utilization: | ||
67 | /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, | ||
68 | /proc/kpagecount, and /proc/kpageflags. Disabling these | ||
69 | interfaces will reduce the size of the kernel by approximately 4kb. | ||
diff --git a/fs/proc/array.c b/fs/proc/array.c index 71c9be59c9c2..f4bc0e789539 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -86,11 +86,6 @@ | |||
86 | #include <asm/processor.h> | 86 | #include <asm/processor.h> |
87 | #include "internal.h" | 87 | #include "internal.h" |
88 | 88 | ||
89 | /* Gcc optimizes away "strlen(x)" for constant x */ | ||
90 | #define ADDBUF(buffer, string) \ | ||
91 | do { memcpy(buffer, string, strlen(string)); \ | ||
92 | buffer += strlen(string); } while (0) | ||
93 | |||
94 | static inline void task_name(struct seq_file *m, struct task_struct *p) | 89 | static inline void task_name(struct seq_file *m, struct task_struct *p) |
95 | { | 90 | { |
96 | int i; | 91 | int i; |
@@ -261,7 +256,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) | |||
261 | sigemptyset(&ignored); | 256 | sigemptyset(&ignored); |
262 | sigemptyset(&caught); | 257 | sigemptyset(&caught); |
263 | 258 | ||
264 | rcu_read_lock(); | ||
265 | if (lock_task_sighand(p, &flags)) { | 259 | if (lock_task_sighand(p, &flags)) { |
266 | pending = p->pending.signal; | 260 | pending = p->pending.signal; |
267 | shpending = p->signal->shared_pending.signal; | 261 | shpending = p->signal->shared_pending.signal; |
@@ -272,7 +266,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) | |||
272 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; | 266 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; |
273 | unlock_task_sighand(p, &flags); | 267 | unlock_task_sighand(p, &flags); |
274 | } | 268 | } |
275 | rcu_read_unlock(); | ||
276 | 269 | ||
277 | seq_printf(m, "Threads:\t%d\n", num_threads); | 270 | seq_printf(m, "Threads:\t%d\n", num_threads); |
278 | seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim); | 271 | seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index a28840b11b89..b5918ae8ca79 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -148,9 +148,6 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, | |||
148 | return count; | 148 | return count; |
149 | } | 149 | } |
150 | 150 | ||
151 | int maps_protect; | ||
152 | EXPORT_SYMBOL(maps_protect); | ||
153 | |||
154 | static struct fs_struct *get_fs_struct(struct task_struct *task) | 151 | static struct fs_struct *get_fs_struct(struct task_struct *task) |
155 | { | 152 | { |
156 | struct fs_struct *fs; | 153 | struct fs_struct *fs; |
@@ -164,7 +161,6 @@ static struct fs_struct *get_fs_struct(struct task_struct *task) | |||
164 | 161 | ||
165 | static int get_nr_threads(struct task_struct *tsk) | 162 | static int get_nr_threads(struct task_struct *tsk) |
166 | { | 163 | { |
167 | /* Must be called with the rcu_read_lock held */ | ||
168 | unsigned long flags; | 164 | unsigned long flags; |
169 | int count = 0; | 165 | int count = 0; |
170 | 166 | ||
@@ -471,14 +467,10 @@ static int proc_pid_limits(struct task_struct *task, char *buffer) | |||
471 | 467 | ||
472 | struct rlimit rlim[RLIM_NLIMITS]; | 468 | struct rlimit rlim[RLIM_NLIMITS]; |
473 | 469 | ||
474 | rcu_read_lock(); | 470 | if (!lock_task_sighand(task, &flags)) |
475 | if (!lock_task_sighand(task,&flags)) { | ||
476 | rcu_read_unlock(); | ||
477 | return 0; | 471 | return 0; |
478 | } | ||
479 | memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); | 472 | memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); |
480 | unlock_task_sighand(task, &flags); | 473 | unlock_task_sighand(task, &flags); |
481 | rcu_read_unlock(); | ||
482 | 474 | ||
483 | /* | 475 | /* |
484 | * print the file header | 476 | * print the file header |
@@ -2443,6 +2435,13 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | |||
2443 | } | 2435 | } |
2444 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ | 2436 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ |
2445 | 2437 | ||
2438 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | ||
2439 | struct pid *pid, struct task_struct *task) | ||
2440 | { | ||
2441 | seq_printf(m, "%08x\n", task->personality); | ||
2442 | return 0; | ||
2443 | } | ||
2444 | |||
2446 | /* | 2445 | /* |
2447 | * Thread groups | 2446 | * Thread groups |
2448 | */ | 2447 | */ |
@@ -2459,6 +2458,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2459 | REG("environ", S_IRUSR, environ), | 2458 | REG("environ", S_IRUSR, environ), |
2460 | INF("auxv", S_IRUSR, pid_auxv), | 2459 | INF("auxv", S_IRUSR, pid_auxv), |
2461 | ONE("status", S_IRUGO, pid_status), | 2460 | ONE("status", S_IRUGO, pid_status), |
2461 | ONE("personality", S_IRUSR, pid_personality), | ||
2462 | INF("limits", S_IRUSR, pid_limits), | 2462 | INF("limits", S_IRUSR, pid_limits), |
2463 | #ifdef CONFIG_SCHED_DEBUG | 2463 | #ifdef CONFIG_SCHED_DEBUG |
2464 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), | 2464 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), |
@@ -2794,6 +2794,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2794 | REG("environ", S_IRUSR, environ), | 2794 | REG("environ", S_IRUSR, environ), |
2795 | INF("auxv", S_IRUSR, pid_auxv), | 2795 | INF("auxv", S_IRUSR, pid_auxv), |
2796 | ONE("status", S_IRUGO, pid_status), | 2796 | ONE("status", S_IRUGO, pid_status), |
2797 | ONE("personality", S_IRUSR, pid_personality), | ||
2797 | INF("limits", S_IRUSR, pid_limits), | 2798 | INF("limits", S_IRUSR, pid_limits), |
2798 | #ifdef CONFIG_SCHED_DEBUG | 2799 | #ifdef CONFIG_SCHED_DEBUG |
2799 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), | 2800 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), |
@@ -3088,9 +3089,7 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct | |||
3088 | generic_fillattr(inode, stat); | 3089 | generic_fillattr(inode, stat); |
3089 | 3090 | ||
3090 | if (p) { | 3091 | if (p) { |
3091 | rcu_read_lock(); | ||
3092 | stat->nlink += get_nr_threads(p); | 3092 | stat->nlink += get_nr_threads(p); |
3093 | rcu_read_unlock(); | ||
3094 | put_task_struct(p); | 3093 | put_task_struct(p); |
3095 | } | 3094 | } |
3096 | 3095 | ||
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 8bb03f056c28..c6b4fa7e3b49 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -342,7 +342,7 @@ static int proc_reg_open(struct inode *inode, struct file *file) | |||
342 | if (!pde->proc_fops) { | 342 | if (!pde->proc_fops) { |
343 | spin_unlock(&pde->pde_unload_lock); | 343 | spin_unlock(&pde->pde_unload_lock); |
344 | kfree(pdeo); | 344 | kfree(pdeo); |
345 | return rv; | 345 | return -EINVAL; |
346 | } | 346 | } |
347 | pde->pde_users++; | 347 | pde->pde_users++; |
348 | open = pde->proc_fops->open; | 348 | open = pde->proc_fops->open; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 442202314d53..3bfb7b8747b3 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -45,8 +45,6 @@ do { \ | |||
45 | extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); | 45 | extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | extern int maps_protect; | ||
49 | |||
50 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, | 48 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, |
51 | struct pid *pid, struct task_struct *task); | 49 | struct pid *pid, struct task_struct *task); |
52 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, | 50 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 29e20c6b1f7f..66c1ab87656c 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -68,7 +68,6 @@ | |||
68 | extern int get_hardware_list(char *); | 68 | extern int get_hardware_list(char *); |
69 | extern int get_stram_list(char *); | 69 | extern int get_stram_list(char *); |
70 | extern int get_exec_domain_list(char *); | 70 | extern int get_exec_domain_list(char *); |
71 | extern int get_dma_list(char *); | ||
72 | 71 | ||
73 | static int proc_calc_metrics(char *page, char **start, off_t off, | 72 | static int proc_calc_metrics(char *page, char **start, off_t off, |
74 | int count, int *eof, int len) | 73 | int count, int *eof, int len) |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index f9a8b892718f..945a81043ba2 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -66,7 +66,7 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) | |||
66 | return NULL; | 66 | return NULL; |
67 | } | 67 | } |
68 | 68 | ||
69 | struct ctl_table_header *grab_header(struct inode *inode) | 69 | static struct ctl_table_header *grab_header(struct inode *inode) |
70 | { | 70 | { |
71 | if (PROC_I(inode)->sysctl) | 71 | if (PROC_I(inode)->sysctl) |
72 | return sysctl_head_grab(PROC_I(inode)->sysctl); | 72 | return sysctl_head_grab(PROC_I(inode)->sysctl); |
@@ -395,10 +395,10 @@ static struct dentry_operations proc_sys_dentry_operations = { | |||
395 | .d_compare = proc_sys_compare, | 395 | .d_compare = proc_sys_compare, |
396 | }; | 396 | }; |
397 | 397 | ||
398 | static struct proc_dir_entry *proc_sys_root; | ||
399 | |||
400 | int proc_sys_init(void) | 398 | int proc_sys_init(void) |
401 | { | 399 | { |
400 | struct proc_dir_entry *proc_sys_root; | ||
401 | |||
402 | proc_sys_root = proc_mkdir("sys", NULL); | 402 | proc_sys_root = proc_mkdir("sys", NULL); |
403 | proc_sys_root->proc_iops = &proc_sys_dir_operations; | 403 | proc_sys_root->proc_iops = &proc_sys_dir_operations; |
404 | proc_sys_root->proc_fops = &proc_sys_dir_file_operations; | 404 | proc_sys_root->proc_fops = &proc_sys_dir_file_operations; |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 73d1891ee625..4806830ea2a1 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -210,9 +210,6 @@ static int show_map(struct seq_file *m, void *v) | |||
210 | dev_t dev = 0; | 210 | dev_t dev = 0; |
211 | int len; | 211 | int len; |
212 | 212 | ||
213 | if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) | ||
214 | return -EACCES; | ||
215 | |||
216 | if (file) { | 213 | if (file) { |
217 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; | 214 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; |
218 | dev = inode->i_sb->s_dev; | 215 | dev = inode->i_sb->s_dev; |
@@ -742,22 +739,11 @@ const struct file_operations proc_pagemap_operations = { | |||
742 | #ifdef CONFIG_NUMA | 739 | #ifdef CONFIG_NUMA |
743 | extern int show_numa_map(struct seq_file *m, void *v); | 740 | extern int show_numa_map(struct seq_file *m, void *v); |
744 | 741 | ||
745 | static int show_numa_map_checked(struct seq_file *m, void *v) | ||
746 | { | ||
747 | struct proc_maps_private *priv = m->private; | ||
748 | struct task_struct *task = priv->task; | ||
749 | |||
750 | if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) | ||
751 | return -EACCES; | ||
752 | |||
753 | return show_numa_map(m, v); | ||
754 | } | ||
755 | |||
756 | static const struct seq_operations proc_pid_numa_maps_op = { | 742 | static const struct seq_operations proc_pid_numa_maps_op = { |
757 | .start = m_start, | 743 | .start = m_start, |
758 | .next = m_next, | 744 | .next = m_next, |
759 | .stop = m_stop, | 745 | .stop = m_stop, |
760 | .show = show_numa_map_checked | 746 | .show = show_numa_map, |
761 | }; | 747 | }; |
762 | 748 | ||
763 | static int numa_maps_open(struct inode *inode, struct file *file) | 749 | static int numa_maps_open(struct inode *inode, struct file *file) |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 5d84e7121df8..219bd79ea894 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -110,11 +110,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, | |||
110 | static int show_map(struct seq_file *m, void *_vml) | 110 | static int show_map(struct seq_file *m, void *_vml) |
111 | { | 111 | { |
112 | struct vm_list_struct *vml = _vml; | 112 | struct vm_list_struct *vml = _vml; |
113 | struct proc_maps_private *priv = m->private; | ||
114 | struct task_struct *task = priv->task; | ||
115 | |||
116 | if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) | ||
117 | return -EACCES; | ||
118 | 113 | ||
119 | return nommu_vma_show(m, vml->vma); | 114 | return nommu_vma_show(m, vml->vma); |
120 | } | 115 | } |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 9ac0f5e064e0..841368b87a29 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -165,14 +165,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, | |||
165 | return acc; | 165 | return acc; |
166 | } | 166 | } |
167 | 167 | ||
168 | static int open_vmcore(struct inode *inode, struct file *filp) | ||
169 | { | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | const struct file_operations proc_vmcore_operations = { | 168 | const struct file_operations proc_vmcore_operations = { |
174 | .read = read_vmcore, | 169 | .read = read_vmcore, |
175 | .open = open_vmcore, | ||
176 | }; | 170 | }; |
177 | 171 | ||
178 | static struct vmcore* __init get_new_element(void) | 172 | static struct vmcore* __init get_new_element(void) |
diff --git a/include/asm-cris/a.out.h b/include/asm-cris/a.out.h deleted file mode 100644 index c82e9f9b75f6..000000000000 --- a/include/asm-cris/a.out.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | #ifndef __CRIS_A_OUT_H__ | ||
2 | #define __CRIS_A_OUT_H__ | ||
3 | |||
4 | /* we don't support a.out binaries on Linux/CRIS anyway, so this is | ||
5 | * not really used but still needed because binfmt_elf.c for some reason | ||
6 | * wants to know about a.out even if there is no interpreter available... | ||
7 | */ | ||
8 | |||
9 | struct exec | ||
10 | { | ||
11 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
12 | unsigned a_text; /* length of text, in bytes */ | ||
13 | unsigned a_data; /* length of data, in bytes */ | ||
14 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
15 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
16 | unsigned a_entry; /* start address */ | ||
17 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
18 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
19 | }; | ||
20 | |||
21 | |||
22 | #define N_TRSIZE(a) ((a).a_trsize) | ||
23 | #define N_DRSIZE(a) ((a).a_drsize) | ||
24 | #define N_SYMSIZE(a) ((a).a_syms) | ||
25 | |||
26 | #endif | ||
diff --git a/include/asm-generic/statfs.h b/include/asm-generic/statfs.h index 1d01043e797d..6129d6802149 100644 --- a/include/asm-generic/statfs.h +++ b/include/asm-generic/statfs.h | |||
@@ -6,33 +6,64 @@ | |||
6 | typedef __kernel_fsid_t fsid_t; | 6 | typedef __kernel_fsid_t fsid_t; |
7 | #endif | 7 | #endif |
8 | 8 | ||
9 | /* | ||
10 | * Most 64-bit platforms use 'long', while most 32-bit platforms use '__u32'. | ||
11 | * Yes, they differ in signedness as well as size. | ||
12 | * Special cases can override it for themselves -- except for S390x, which | ||
13 | * is just a little too special for us. And MIPS, which I'm not touching | ||
14 | * with a 10' pole. | ||
15 | */ | ||
16 | #ifndef __statfs_word | ||
17 | #if BITS_PER_LONG == 64 | ||
18 | #define __statfs_word long | ||
19 | #else | ||
20 | #define __statfs_word __u32 | ||
21 | #endif | ||
22 | #endif | ||
23 | |||
9 | struct statfs { | 24 | struct statfs { |
10 | __u32 f_type; | 25 | __statfs_word f_type; |
11 | __u32 f_bsize; | 26 | __statfs_word f_bsize; |
12 | __u32 f_blocks; | 27 | __statfs_word f_blocks; |
13 | __u32 f_bfree; | 28 | __statfs_word f_bfree; |
14 | __u32 f_bavail; | 29 | __statfs_word f_bavail; |
15 | __u32 f_files; | 30 | __statfs_word f_files; |
16 | __u32 f_ffree; | 31 | __statfs_word f_ffree; |
17 | __kernel_fsid_t f_fsid; | 32 | __kernel_fsid_t f_fsid; |
18 | __u32 f_namelen; | 33 | __statfs_word f_namelen; |
19 | __u32 f_frsize; | 34 | __statfs_word f_frsize; |
20 | __u32 f_spare[5]; | 35 | __statfs_word f_spare[5]; |
21 | }; | 36 | }; |
22 | 37 | ||
38 | /* | ||
39 | * ARM needs to avoid the 32-bit padding at the end, for consistency | ||
40 | * between EABI and OABI | ||
41 | */ | ||
42 | #ifndef ARCH_PACK_STATFS64 | ||
43 | #define ARCH_PACK_STATFS64 | ||
44 | #endif | ||
45 | |||
23 | struct statfs64 { | 46 | struct statfs64 { |
24 | __u32 f_type; | 47 | __statfs_word f_type; |
25 | __u32 f_bsize; | 48 | __statfs_word f_bsize; |
26 | __u64 f_blocks; | 49 | __u64 f_blocks; |
27 | __u64 f_bfree; | 50 | __u64 f_bfree; |
28 | __u64 f_bavail; | 51 | __u64 f_bavail; |
29 | __u64 f_files; | 52 | __u64 f_files; |
30 | __u64 f_ffree; | 53 | __u64 f_ffree; |
31 | __kernel_fsid_t f_fsid; | 54 | __kernel_fsid_t f_fsid; |
32 | __u32 f_namelen; | 55 | __statfs_word f_namelen; |
33 | __u32 f_frsize; | 56 | __statfs_word f_frsize; |
34 | __u32 f_spare[5]; | 57 | __statfs_word f_spare[5]; |
35 | }; | 58 | } ARCH_PACK_STATFS64; |
59 | |||
60 | /* | ||
61 | * IA64 and x86_64 need to avoid the 32-bit padding at the end, | ||
62 | * to be compatible with the i386 ABI | ||
63 | */ | ||
64 | #ifndef ARCH_PACK_COMPAT_STATFS64 | ||
65 | #define ARCH_PACK_COMPAT_STATFS64 | ||
66 | #endif | ||
36 | 67 | ||
37 | struct compat_statfs64 { | 68 | struct compat_statfs64 { |
38 | __u32 f_type; | 69 | __u32 f_type; |
@@ -46,6 +77,6 @@ struct compat_statfs64 { | |||
46 | __u32 f_namelen; | 77 | __u32 f_namelen; |
47 | __u32 f_frsize; | 78 | __u32 f_frsize; |
48 | __u32 f_spare[5]; | 79 | __u32 f_spare[5]; |
49 | }; | 80 | } ARCH_PACK_COMPAT_STATFS64; |
50 | 81 | ||
51 | #endif | 82 | #endif |
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h deleted file mode 100644 index ab150f5c1666..000000000000 --- a/include/asm-m32r/a.out.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef _ASM_M32R_A_OUT_H | ||
2 | #define _ASM_M32R_A_OUT_H | ||
3 | |||
4 | struct exec | ||
5 | { | ||
6 | unsigned long a_info; /* Use macros N_MAGIC, etc for access */ | ||
7 | unsigned a_text; /* length of text, in bytes */ | ||
8 | unsigned a_data; /* length of data, in bytes */ | ||
9 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
10 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
11 | unsigned a_entry; /* start address */ | ||
12 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
13 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
14 | }; | ||
15 | |||
16 | #define N_TRSIZE(a) ((a).a_trsize) | ||
17 | #define N_DRSIZE(a) ((a).a_drsize) | ||
18 | #define N_SYMSIZE(a) ((a).a_syms) | ||
19 | |||
20 | #endif /* _ASM_M32R_A_OUT_H */ | ||
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h deleted file mode 100644 index eb04e34c5bb1..000000000000 --- a/include/asm-parisc/a.out.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef __PARISC_A_OUT_H__ | ||
2 | #define __PARISC_A_OUT_H__ | ||
3 | |||
4 | struct exec | ||
5 | { | ||
6 | unsigned int a_info; /* Use macros N_MAGIC, etc for access */ | ||
7 | unsigned a_text; /* length of text, in bytes */ | ||
8 | unsigned a_data; /* length of data, in bytes */ | ||
9 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
10 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
11 | unsigned a_entry; /* start address */ | ||
12 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
13 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
14 | }; | ||
15 | |||
16 | #define N_TRSIZE(a) ((a).a_trsize) | ||
17 | #define N_DRSIZE(a) ((a).a_drsize) | ||
18 | #define N_SYMSIZE(a) ((a).a_syms) | ||
19 | |||
20 | #endif /* __A_OUT_GNU_H__ */ | ||
diff --git a/include/asm-parisc/statfs.h b/include/asm-parisc/statfs.h index 1d2b8130b23d..324bea905dc6 100644 --- a/include/asm-parisc/statfs.h +++ b/include/asm-parisc/statfs.h | |||
@@ -1,58 +1,7 @@ | |||
1 | #ifndef _PARISC_STATFS_H | 1 | #ifndef _PARISC_STATFS_H |
2 | #define _PARISC_STATFS_H | 2 | #define _PARISC_STATFS_H |
3 | 3 | ||
4 | #ifndef __KERNEL_STRICT_NAMES | 4 | #define __statfs_word long |
5 | 5 | #include <asm-generic/statfs.h> | |
6 | #include <linux/types.h> | ||
7 | |||
8 | typedef __kernel_fsid_t fsid_t; | ||
9 | |||
10 | #endif | ||
11 | |||
12 | /* | ||
13 | * It appears that PARISC could be 64 _or_ 32 bit. | ||
14 | * 64-bit fields must be explicitly 64-bit in statfs64. | ||
15 | */ | ||
16 | struct statfs { | ||
17 | long f_type; | ||
18 | long f_bsize; | ||
19 | long f_blocks; | ||
20 | long f_bfree; | ||
21 | long f_bavail; | ||
22 | long f_files; | ||
23 | long f_ffree; | ||
24 | __kernel_fsid_t f_fsid; | ||
25 | long f_namelen; | ||
26 | long f_frsize; | ||
27 | long f_spare[5]; | ||
28 | }; | ||
29 | |||
30 | struct statfs64 { | ||
31 | long f_type; | ||
32 | long f_bsize; | ||
33 | __u64 f_blocks; | ||
34 | __u64 f_bfree; | ||
35 | __u64 f_bavail; | ||
36 | __u64 f_files; | ||
37 | __u64 f_ffree; | ||
38 | __kernel_fsid_t f_fsid; | ||
39 | long f_namelen; | ||
40 | long f_frsize; | ||
41 | long f_spare[5]; | ||
42 | }; | ||
43 | |||
44 | struct compat_statfs64 { | ||
45 | __u32 f_type; | ||
46 | __u32 f_bsize; | ||
47 | __u64 f_blocks; | ||
48 | __u64 f_bfree; | ||
49 | __u64 f_bavail; | ||
50 | __u64 f_files; | ||
51 | __u64 f_ffree; | ||
52 | __kernel_fsid_t f_fsid; | ||
53 | __u32 f_namelen; | ||
54 | __u32 f_frsize; | ||
55 | __u32 f_spare[5]; | ||
56 | }; | ||
57 | 6 | ||
58 | #endif | 7 | #endif |
diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index ebc307817e98..f06adac7938c 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h | |||
@@ -351,20 +351,16 @@ static inline void set_system_intr_gate(unsigned int n, void *addr) | |||
351 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS); | 351 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS); |
352 | } | 352 | } |
353 | 353 | ||
354 | static inline void set_trap_gate(unsigned int n, void *addr) | 354 | static inline void set_system_trap_gate(unsigned int n, void *addr) |
355 | { | 355 | { |
356 | BUG_ON((unsigned)n > 0xFF); | 356 | BUG_ON((unsigned)n > 0xFF); |
357 | _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS); | 357 | _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS); |
358 | } | 358 | } |
359 | 359 | ||
360 | static inline void set_system_gate(unsigned int n, void *addr) | 360 | static inline void set_trap_gate(unsigned int n, void *addr) |
361 | { | 361 | { |
362 | BUG_ON((unsigned)n > 0xFF); | 362 | BUG_ON((unsigned)n > 0xFF); |
363 | #ifdef CONFIG_X86_32 | 363 | _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS); |
364 | _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS); | ||
365 | #else | ||
366 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS); | ||
367 | #endif | ||
368 | } | 364 | } |
369 | 365 | ||
370 | static inline void set_task_gate(unsigned int n, unsigned int gdt_entry) | 366 | static inline void set_task_gate(unsigned int n, unsigned int gdt_entry) |
@@ -379,7 +375,7 @@ static inline void set_intr_gate_ist(int n, void *addr, unsigned ist) | |||
379 | _set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS); | 375 | _set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS); |
380 | } | 376 | } |
381 | 377 | ||
382 | static inline void set_system_gate_ist(int n, void *addr, unsigned ist) | 378 | static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist) |
383 | { | 379 | { |
384 | BUG_ON((unsigned)n > 0xFF); | 380 | BUG_ON((unsigned)n > 0xFF); |
385 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); | 381 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); |
diff --git a/include/asm-x86/es7000/mpparse.h b/include/asm-x86/es7000/mpparse.h index 7b5c889d8e7d..ed5a3caae141 100644 --- a/include/asm-x86/es7000/mpparse.h +++ b/include/asm-x86/es7000/mpparse.h | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | extern int parse_unisys_oem (char *oemptr); | 6 | extern int parse_unisys_oem (char *oemptr); |
7 | extern int find_unisys_acpi_oem_table(unsigned long *oem_addr); | 7 | extern int find_unisys_acpi_oem_table(unsigned long *oem_addr); |
8 | extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr); | ||
8 | extern void setup_unisys(void); | 9 | extern void setup_unisys(void); |
9 | 10 | ||
10 | #ifndef CONFIG_X86_GENERICARCH | 11 | #ifndef CONFIG_X86_GENERICARCH |
diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h index 784e3e759866..8844002da0e0 100644 --- a/include/asm-x86/fixmap_32.h +++ b/include/asm-x86/fixmap_32.h | |||
@@ -94,10 +94,10 @@ enum fixed_addresses { | |||
94 | * can have a single pgd entry and a single pte table: | 94 | * can have a single pgd entry and a single pte table: |
95 | */ | 95 | */ |
96 | #define NR_FIX_BTMAPS 64 | 96 | #define NR_FIX_BTMAPS 64 |
97 | #define FIX_BTMAPS_NESTING 4 | 97 | #define FIX_BTMAPS_SLOTS 4 |
98 | FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 - | 98 | FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 - |
99 | (__end_of_permanent_fixed_addresses & 255), | 99 | (__end_of_permanent_fixed_addresses & 255), |
100 | FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1, | 100 | FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1, |
101 | FIX_WP_TEST, | 101 | FIX_WP_TEST, |
102 | #ifdef CONFIG_ACPI | 102 | #ifdef CONFIG_ACPI |
103 | FIX_ACPI_BEGIN, | 103 | FIX_ACPI_BEGIN, |
diff --git a/include/asm-x86/fixmap_64.h b/include/asm-x86/fixmap_64.h index dafb24bc0424..dab4751d1307 100644 --- a/include/asm-x86/fixmap_64.h +++ b/include/asm-x86/fixmap_64.h | |||
@@ -49,6 +49,7 @@ enum fixed_addresses { | |||
49 | #ifdef CONFIG_PARAVIRT | 49 | #ifdef CONFIG_PARAVIRT |
50 | FIX_PARAVIRT_BOOTMAP, | 50 | FIX_PARAVIRT_BOOTMAP, |
51 | #endif | 51 | #endif |
52 | __end_of_permanent_fixed_addresses, | ||
52 | #ifdef CONFIG_ACPI | 53 | #ifdef CONFIG_ACPI |
53 | FIX_ACPI_BEGIN, | 54 | FIX_ACPI_BEGIN, |
54 | FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, | 55 | FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, |
@@ -56,19 +57,18 @@ enum fixed_addresses { | |||
56 | #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT | 57 | #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT |
57 | FIX_OHCI1394_BASE, | 58 | FIX_OHCI1394_BASE, |
58 | #endif | 59 | #endif |
59 | __end_of_permanent_fixed_addresses, | ||
60 | /* | 60 | /* |
61 | * 256 temporary boot-time mappings, used by early_ioremap(), | 61 | * 256 temporary boot-time mappings, used by early_ioremap(), |
62 | * before ioremap() is functional. | 62 | * before ioremap() is functional. |
63 | * | 63 | * |
64 | * We round it up to the next 512 pages boundary so that we | 64 | * We round it up to the next 256 pages boundary so that we |
65 | * can have a single pgd entry and a single pte table: | 65 | * can have a single pgd entry and a single pte table: |
66 | */ | 66 | */ |
67 | #define NR_FIX_BTMAPS 64 | 67 | #define NR_FIX_BTMAPS 64 |
68 | #define FIX_BTMAPS_NESTING 4 | 68 | #define FIX_BTMAPS_SLOTS 4 |
69 | FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 - | 69 | FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 - |
70 | (__end_of_permanent_fixed_addresses & 511), | 70 | (__end_of_permanent_fixed_addresses & 255), |
71 | FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1, | 71 | FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1, |
72 | __end_of_fixed_addresses | 72 | __end_of_fixed_addresses |
73 | }; | 73 | }; |
74 | 74 | ||
diff --git a/include/asm-x86/io.h b/include/asm-x86/io.h index 72b7719523bf..a233f835e0b5 100644 --- a/include/asm-x86/io.h +++ b/include/asm-x86/io.h | |||
@@ -5,20 +5,6 @@ | |||
5 | 5 | ||
6 | #include <linux/compiler.h> | 6 | #include <linux/compiler.h> |
7 | 7 | ||
8 | /* | ||
9 | * early_ioremap() and early_iounmap() are for temporary early boot-time | ||
10 | * mappings, before the real ioremap() is functional. | ||
11 | * A boot-time mapping is currently limited to at most 16 pages. | ||
12 | */ | ||
13 | #ifndef __ASSEMBLY__ | ||
14 | extern void early_ioremap_init(void); | ||
15 | extern void early_ioremap_clear(void); | ||
16 | extern void early_ioremap_reset(void); | ||
17 | extern void *early_ioremap(unsigned long offset, unsigned long size); | ||
18 | extern void early_iounmap(void *addr, unsigned long size); | ||
19 | extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys); | ||
20 | #endif | ||
21 | |||
22 | #define build_mmio_read(name, size, type, reg, barrier) \ | 8 | #define build_mmio_read(name, size, type, reg, barrier) \ |
23 | static inline type name(const volatile void __iomem *addr) \ | 9 | static inline type name(const volatile void __iomem *addr) \ |
24 | { type ret; asm volatile("mov" size " %1,%0":reg (ret) \ | 10 | { type ret; asm volatile("mov" size " %1,%0":reg (ret) \ |
@@ -97,6 +83,7 @@ extern void early_ioremap_init(void); | |||
97 | extern void early_ioremap_clear(void); | 83 | extern void early_ioremap_clear(void); |
98 | extern void early_ioremap_reset(void); | 84 | extern void early_ioremap_reset(void); |
99 | extern void *early_ioremap(unsigned long offset, unsigned long size); | 85 | extern void *early_ioremap(unsigned long offset, unsigned long size); |
86 | extern void *early_memremap(unsigned long offset, unsigned long size); | ||
100 | extern void early_iounmap(void *addr, unsigned long size); | 87 | extern void early_iounmap(void *addr, unsigned long size); |
101 | extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys); | 88 | extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys); |
102 | 89 | ||
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h index 64429e9431a8..ee6e086b7dfe 100644 --- a/include/asm-x86/io_64.h +++ b/include/asm-x86/io_64.h | |||
@@ -165,9 +165,6 @@ static inline void *phys_to_virt(unsigned long address) | |||
165 | 165 | ||
166 | #include <asm-generic/iomap.h> | 166 | #include <asm-generic/iomap.h> |
167 | 167 | ||
168 | extern void *early_ioremap(unsigned long addr, unsigned long size); | ||
169 | extern void early_iounmap(void *addr, unsigned long size); | ||
170 | |||
171 | /* | 168 | /* |
172 | * This one maps high address device memory and turns off caching for that area. | 169 | * This one maps high address device memory and turns off caching for that area. |
173 | * it's useful if some control registers are in such an area and write combining | 170 | * it's useful if some control registers are in such an area and write combining |
diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h index 336603512399..06752a649044 100644 --- a/include/asm-x86/ioctls.h +++ b/include/asm-x86/ioctls.h | |||
@@ -51,9 +51,15 @@ | |||
51 | #define TCSETS2 _IOW('T', 0x2B, struct termios2) | 51 | #define TCSETS2 _IOW('T', 0x2B, struct termios2) |
52 | #define TCSETSW2 _IOW('T', 0x2C, struct termios2) | 52 | #define TCSETSW2 _IOW('T', 0x2C, struct termios2) |
53 | #define TCSETSF2 _IOW('T', 0x2D, struct termios2) | 53 | #define TCSETSF2 _IOW('T', 0x2D, struct termios2) |
54 | #define TIOCGRS485 0x542E | ||
55 | #define TIOCSRS485 0x542F | ||
54 | #define TIOCGPTN _IOR('T', 0x30, unsigned int) | 56 | #define TIOCGPTN _IOR('T', 0x30, unsigned int) |
55 | /* Get Pty Number (of pty-mux device) */ | 57 | /* Get Pty Number (of pty-mux device) */ |
56 | #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ | 58 | #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ |
59 | #define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ | ||
60 | #define TCSETX 0x5433 | ||
61 | #define TCSETXF 0x5434 | ||
62 | #define TCSETXW 0x5435 | ||
57 | 63 | ||
58 | #define FIONCLEX 0x5450 | 64 | #define FIONCLEX 0x5450 |
59 | #define FIOCLEX 0x5451 | 65 | #define FIOCLEX 0x5451 |
diff --git a/include/asm-x86/irqflags.h b/include/asm-x86/irqflags.h index 424acb48cd61..2bdab21f0898 100644 --- a/include/asm-x86/irqflags.h +++ b/include/asm-x86/irqflags.h | |||
@@ -166,27 +166,6 @@ static inline int raw_irqs_disabled(void) | |||
166 | return raw_irqs_disabled_flags(flags); | 166 | return raw_irqs_disabled_flags(flags); |
167 | } | 167 | } |
168 | 168 | ||
169 | /* | ||
170 | * makes the traced hardirq state match with the machine state | ||
171 | * | ||
172 | * should be a rarely used function, only in places where its | ||
173 | * otherwise impossible to know the irq state, like in traps. | ||
174 | */ | ||
175 | static inline void trace_hardirqs_fixup_flags(unsigned long flags) | ||
176 | { | ||
177 | if (raw_irqs_disabled_flags(flags)) | ||
178 | trace_hardirqs_off(); | ||
179 | else | ||
180 | trace_hardirqs_on(); | ||
181 | } | ||
182 | |||
183 | static inline void trace_hardirqs_fixup(void) | ||
184 | { | ||
185 | unsigned long flags = __raw_local_save_flags(); | ||
186 | |||
187 | trace_hardirqs_fixup_flags(flags); | ||
188 | } | ||
189 | |||
190 | #else | 169 | #else |
191 | 170 | ||
192 | #ifdef CONFIG_X86_64 | 171 | #ifdef CONFIG_X86_64 |
diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h index 5ec3ad3e825c..fbbab66ee9df 100644 --- a/include/asm-x86/kdebug.h +++ b/include/asm-x86/kdebug.h | |||
@@ -27,10 +27,9 @@ extern void printk_address(unsigned long address, int reliable); | |||
27 | extern void die(const char *, struct pt_regs *,long); | 27 | extern void die(const char *, struct pt_regs *,long); |
28 | extern int __must_check __die(const char *, struct pt_regs *, long); | 28 | extern int __must_check __die(const char *, struct pt_regs *, long); |
29 | extern void show_registers(struct pt_regs *regs); | 29 | extern void show_registers(struct pt_regs *regs); |
30 | extern void __show_registers(struct pt_regs *, int all); | ||
31 | extern void show_trace(struct task_struct *t, struct pt_regs *regs, | 30 | extern void show_trace(struct task_struct *t, struct pt_regs *regs, |
32 | unsigned long *sp, unsigned long bp); | 31 | unsigned long *sp, unsigned long bp); |
33 | extern void __show_regs(struct pt_regs *regs); | 32 | extern void __show_regs(struct pt_regs *regs, int all); |
34 | extern void show_regs(struct pt_regs *regs); | 33 | extern void show_regs(struct pt_regs *regs); |
35 | extern unsigned long oops_begin(void); | 34 | extern unsigned long oops_begin(void); |
36 | extern void oops_end(unsigned long, struct pt_regs *, int signr); | 35 | extern void oops_end(unsigned long, struct pt_regs *, int signr); |
diff --git a/include/asm-x86/kprobes.h b/include/asm-x86/kprobes.h index bd8407863c13..8a0748d01036 100644 --- a/include/asm-x86/kprobes.h +++ b/include/asm-x86/kprobes.h | |||
@@ -82,15 +82,6 @@ struct kprobe_ctlblk { | |||
82 | struct prev_kprobe prev_kprobe; | 82 | struct prev_kprobe prev_kprobe; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | /* trap3/1 are intr gates for kprobes. So, restore the status of IF, | ||
86 | * if necessary, before executing the original int3/1 (trap) handler. | ||
87 | */ | ||
88 | static inline void restore_interrupts(struct pt_regs *regs) | ||
89 | { | ||
90 | if (regs->flags & X86_EFLAGS_IF) | ||
91 | local_irq_enable(); | ||
92 | } | ||
93 | |||
94 | extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); | 85 | extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); |
95 | extern int kprobe_exceptions_notify(struct notifier_block *self, | 86 | extern int kprobe_exceptions_notify(struct notifier_block *self, |
96 | unsigned long val, void *data); | 87 | unsigned long val, void *data); |
diff --git a/include/asm-x86/mach-default/mach_traps.h b/include/asm-x86/mach-default/mach_traps.h index de9ac3f5c4ce..ff8778f26b84 100644 --- a/include/asm-x86/mach-default/mach_traps.h +++ b/include/asm-x86/mach-default/mach_traps.h | |||
@@ -7,12 +7,6 @@ | |||
7 | 7 | ||
8 | #include <asm/mc146818rtc.h> | 8 | #include <asm/mc146818rtc.h> |
9 | 9 | ||
10 | static inline void clear_mem_error(unsigned char reason) | ||
11 | { | ||
12 | reason = (reason & 0xf) | 4; | ||
13 | outb(reason, 0x61); | ||
14 | } | ||
15 | |||
16 | static inline unsigned char get_nmi_reason(void) | 10 | static inline unsigned char get_nmi_reason(void) |
17 | { | 11 | { |
18 | return inb(0x61); | 12 | return inb(0x61); |
diff --git a/include/asm-x86/module.h b/include/asm-x86/module.h index 48dc3e0c07d9..864f2005fc1d 100644 --- a/include/asm-x86/module.h +++ b/include/asm-x86/module.h | |||
@@ -52,8 +52,6 @@ struct mod_arch_specific {}; | |||
52 | #define MODULE_PROC_FAMILY "EFFICEON " | 52 | #define MODULE_PROC_FAMILY "EFFICEON " |
53 | #elif defined CONFIG_MWINCHIPC6 | 53 | #elif defined CONFIG_MWINCHIPC6 |
54 | #define MODULE_PROC_FAMILY "WINCHIPC6 " | 54 | #define MODULE_PROC_FAMILY "WINCHIPC6 " |
55 | #elif defined CONFIG_MWINCHIP2 | ||
56 | #define MODULE_PROC_FAMILY "WINCHIP2 " | ||
57 | #elif defined CONFIG_MWINCHIP3D | 55 | #elif defined CONFIG_MWINCHIP3D |
58 | #define MODULE_PROC_FAMILY "WINCHIP3D " | 56 | #define MODULE_PROC_FAMILY "WINCHIP3D " |
59 | #elif defined CONFIG_MCYRIXIII | 57 | #elif defined CONFIG_MCYRIXIII |
diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h index d5e715f024dc..a53f829a97c5 100644 --- a/include/asm-x86/nmi.h +++ b/include/asm-x86/nmi.h | |||
@@ -15,10 +15,6 @@ | |||
15 | */ | 15 | */ |
16 | int do_nmi_callback(struct pt_regs *regs, int cpu); | 16 | int do_nmi_callback(struct pt_regs *regs, int cpu); |
17 | 17 | ||
18 | #ifdef CONFIG_X86_64 | ||
19 | extern void default_do_nmi(struct pt_regs *); | ||
20 | #endif | ||
21 | |||
22 | extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); | 18 | extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); |
23 | extern int check_nmi_watchdog(void); | 19 | extern int check_nmi_watchdog(void); |
24 | extern int nmi_watchdog_enabled; | 20 | extern int nmi_watchdog_enabled; |
diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h index c91574776751..d4f1d5791fc1 100644 --- a/include/asm-x86/page.h +++ b/include/asm-x86/page.h | |||
@@ -179,6 +179,7 @@ static inline pteval_t native_pte_flags(pte_t pte) | |||
179 | #endif /* CONFIG_PARAVIRT */ | 179 | #endif /* CONFIG_PARAVIRT */ |
180 | 180 | ||
181 | #define __pa(x) __phys_addr((unsigned long)(x)) | 181 | #define __pa(x) __phys_addr((unsigned long)(x)) |
182 | #define __pa_nodebug(x) __phys_addr_nodebug((unsigned long)(x)) | ||
182 | /* __pa_symbol should be used for C visible symbols. | 183 | /* __pa_symbol should be used for C visible symbols. |
183 | This seems to be the official gcc blessed way to do such arithmetic. */ | 184 | This seems to be the official gcc blessed way to do such arithmetic. */ |
184 | #define __pa_symbol(x) __pa(__phys_reloc_hide((unsigned long)(x))) | 185 | #define __pa_symbol(x) __pa(__phys_reloc_hide((unsigned long)(x))) |
@@ -188,9 +189,14 @@ static inline pteval_t native_pte_flags(pte_t pte) | |||
188 | #define __boot_va(x) __va(x) | 189 | #define __boot_va(x) __va(x) |
189 | #define __boot_pa(x) __pa(x) | 190 | #define __boot_pa(x) __pa(x) |
190 | 191 | ||
192 | /* | ||
193 | * virt_to_page(kaddr) returns a valid pointer if and only if | ||
194 | * virt_addr_valid(kaddr) returns true. | ||
195 | */ | ||
191 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 196 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
192 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) | 197 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) |
193 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) | 198 | extern bool __virt_addr_valid(unsigned long kaddr); |
199 | #define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr)) | ||
194 | 200 | ||
195 | #endif /* __ASSEMBLY__ */ | 201 | #endif /* __ASSEMBLY__ */ |
196 | 202 | ||
diff --git a/include/asm-x86/page_32.h b/include/asm-x86/page_32.h index 9c5a737a9af9..e8d80d1de237 100644 --- a/include/asm-x86/page_32.h +++ b/include/asm-x86/page_32.h | |||
@@ -20,6 +20,12 @@ | |||
20 | #endif | 20 | #endif |
21 | #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) | 21 | #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) |
22 | 22 | ||
23 | #define STACKFAULT_STACK 0 | ||
24 | #define DOUBLEFAULT_STACK 1 | ||
25 | #define NMI_STACK 0 | ||
26 | #define DEBUG_STACK 0 | ||
27 | #define MCE_STACK 0 | ||
28 | #define N_EXCEPTION_STACKS 1 | ||
23 | 29 | ||
24 | #ifdef CONFIG_X86_PAE | 30 | #ifdef CONFIG_X86_PAE |
25 | /* 44=32+12, the limit we can fit into an unsigned long pfn */ | 31 | /* 44=32+12, the limit we can fit into an unsigned long pfn */ |
@@ -73,11 +79,11 @@ typedef struct page *pgtable_t; | |||
73 | #endif | 79 | #endif |
74 | 80 | ||
75 | #ifndef __ASSEMBLY__ | 81 | #ifndef __ASSEMBLY__ |
76 | #define __phys_addr_const(x) ((x) - PAGE_OFFSET) | 82 | #define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET) |
77 | #ifdef CONFIG_DEBUG_VIRTUAL | 83 | #ifdef CONFIG_DEBUG_VIRTUAL |
78 | extern unsigned long __phys_addr(unsigned long); | 84 | extern unsigned long __phys_addr(unsigned long); |
79 | #else | 85 | #else |
80 | #define __phys_addr(x) ((x) - PAGE_OFFSET) | 86 | #define __phys_addr(x) __phys_addr_nodebug(x) |
81 | #endif | 87 | #endif |
82 | #define __phys_reloc_hide(x) RELOC_HIDE((x), 0) | 88 | #define __phys_reloc_hide(x) RELOC_HIDE((x), 0) |
83 | 89 | ||
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h index ed932453ef26..182f9d4c570f 100644 --- a/include/asm-x86/pgtable.h +++ b/include/asm-x86/pgtable.h | |||
@@ -15,7 +15,7 @@ | |||
15 | #define _PAGE_BIT_PAT 7 /* on 4KB pages */ | 15 | #define _PAGE_BIT_PAT 7 /* on 4KB pages */ |
16 | #define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */ | 16 | #define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */ |
17 | #define _PAGE_BIT_UNUSED1 9 /* available for programmer */ | 17 | #define _PAGE_BIT_UNUSED1 9 /* available for programmer */ |
18 | #define _PAGE_BIT_UNUSED2 10 | 18 | #define _PAGE_BIT_IOMAP 10 /* flag used to indicate IO mapping */ |
19 | #define _PAGE_BIT_UNUSED3 11 | 19 | #define _PAGE_BIT_UNUSED3 11 |
20 | #define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */ | 20 | #define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */ |
21 | #define _PAGE_BIT_SPECIAL _PAGE_BIT_UNUSED1 | 21 | #define _PAGE_BIT_SPECIAL _PAGE_BIT_UNUSED1 |
@@ -32,7 +32,7 @@ | |||
32 | #define _PAGE_PSE (_AT(pteval_t, 1) << _PAGE_BIT_PSE) | 32 | #define _PAGE_PSE (_AT(pteval_t, 1) << _PAGE_BIT_PSE) |
33 | #define _PAGE_GLOBAL (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL) | 33 | #define _PAGE_GLOBAL (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL) |
34 | #define _PAGE_UNUSED1 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1) | 34 | #define _PAGE_UNUSED1 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1) |
35 | #define _PAGE_UNUSED2 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2) | 35 | #define _PAGE_IOMAP (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP) |
36 | #define _PAGE_UNUSED3 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3) | 36 | #define _PAGE_UNUSED3 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3) |
37 | #define _PAGE_PAT (_AT(pteval_t, 1) << _PAGE_BIT_PAT) | 37 | #define _PAGE_PAT (_AT(pteval_t, 1) << _PAGE_BIT_PAT) |
38 | #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE) | 38 | #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE) |
@@ -99,6 +99,11 @@ | |||
99 | #define __PAGE_KERNEL_LARGE_NOCACHE (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE) | 99 | #define __PAGE_KERNEL_LARGE_NOCACHE (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE) |
100 | #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) | 100 | #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) |
101 | 101 | ||
102 | #define __PAGE_KERNEL_IO (__PAGE_KERNEL | _PAGE_IOMAP) | ||
103 | #define __PAGE_KERNEL_IO_NOCACHE (__PAGE_KERNEL_NOCACHE | _PAGE_IOMAP) | ||
104 | #define __PAGE_KERNEL_IO_UC_MINUS (__PAGE_KERNEL_UC_MINUS | _PAGE_IOMAP) | ||
105 | #define __PAGE_KERNEL_IO_WC (__PAGE_KERNEL_WC | _PAGE_IOMAP) | ||
106 | |||
102 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) | 107 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) |
103 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) | 108 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) |
104 | #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) | 109 | #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) |
@@ -113,6 +118,11 @@ | |||
113 | #define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL) | 118 | #define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL) |
114 | #define PAGE_KERNEL_VSYSCALL_NOCACHE __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE) | 119 | #define PAGE_KERNEL_VSYSCALL_NOCACHE __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE) |
115 | 120 | ||
121 | #define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO) | ||
122 | #define PAGE_KERNEL_IO_NOCACHE __pgprot(__PAGE_KERNEL_IO_NOCACHE) | ||
123 | #define PAGE_KERNEL_IO_UC_MINUS __pgprot(__PAGE_KERNEL_IO_UC_MINUS) | ||
124 | #define PAGE_KERNEL_IO_WC __pgprot(__PAGE_KERNEL_IO_WC) | ||
125 | |||
116 | /* xwr */ | 126 | /* xwr */ |
117 | #define __P000 PAGE_NONE | 127 | #define __P000 PAGE_NONE |
118 | #define __P001 PAGE_READONLY | 128 | #define __P001 PAGE_READONLY |
@@ -196,7 +206,7 @@ static inline int pte_exec(pte_t pte) | |||
196 | 206 | ||
197 | static inline int pte_special(pte_t pte) | 207 | static inline int pte_special(pte_t pte) |
198 | { | 208 | { |
199 | return pte_val(pte) & _PAGE_SPECIAL; | 209 | return pte_flags(pte) & _PAGE_SPECIAL; |
200 | } | 210 | } |
201 | 211 | ||
202 | static inline unsigned long pte_pfn(pte_t pte) | 212 | static inline unsigned long pte_pfn(pte_t pte) |
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h index ac578f11c1c5..a2025525a15a 100644 --- a/include/asm-x86/ptrace.h +++ b/include/asm-x86/ptrace.h | |||
@@ -174,12 +174,8 @@ extern unsigned long profile_pc(struct pt_regs *regs); | |||
174 | 174 | ||
175 | extern unsigned long | 175 | extern unsigned long |
176 | convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); | 176 | convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); |
177 | |||
178 | #ifdef CONFIG_X86_32 | ||
179 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | 177 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, |
180 | int error_code, int si_code); | 178 | int error_code, int si_code); |
181 | #endif | ||
182 | |||
183 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | 179 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); |
184 | 180 | ||
185 | extern long syscall_trace_enter(struct pt_regs *); | 181 | extern long syscall_trace_enter(struct pt_regs *); |
diff --git a/include/asm-x86/segment.h b/include/asm-x86/segment.h index ea5f0a8686f7..5d6e69454891 100644 --- a/include/asm-x86/segment.h +++ b/include/asm-x86/segment.h | |||
@@ -131,12 +131,6 @@ | |||
131 | * Matching rules for certain types of segments. | 131 | * Matching rules for certain types of segments. |
132 | */ | 132 | */ |
133 | 133 | ||
134 | /* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */ | ||
135 | #define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8) | ||
136 | |||
137 | /* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ | ||
138 | #define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) | ||
139 | |||
140 | /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ | 134 | /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ |
141 | #define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) | 135 | #define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) |
142 | 136 | ||
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h index 6df2615f9138..a6afc29f2dd9 100644 --- a/include/asm-x86/smp.h +++ b/include/asm-x86/smp.h | |||
@@ -141,6 +141,8 @@ void play_dead_common(void); | |||
141 | void native_send_call_func_ipi(cpumask_t mask); | 141 | void native_send_call_func_ipi(cpumask_t mask); |
142 | void native_send_call_func_single_ipi(int cpu); | 142 | void native_send_call_func_single_ipi(int cpu); |
143 | 143 | ||
144 | extern void prefill_possible_map(void); | ||
145 | |||
144 | void smp_store_cpu_info(int id); | 146 | void smp_store_cpu_info(int id); |
145 | #define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu) | 147 | #define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu) |
146 | 148 | ||
@@ -149,15 +151,11 @@ static inline int num_booting_cpus(void) | |||
149 | { | 151 | { |
150 | return cpus_weight(cpu_callout_map); | 152 | return cpus_weight(cpu_callout_map); |
151 | } | 153 | } |
152 | #endif /* CONFIG_SMP */ | ||
153 | |||
154 | #if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_CPU) | ||
155 | extern void prefill_possible_map(void); | ||
156 | #else | 154 | #else |
157 | static inline void prefill_possible_map(void) | 155 | static inline void prefill_possible_map(void) |
158 | { | 156 | { |
159 | } | 157 | } |
160 | #endif | 158 | #endif /* CONFIG_SMP */ |
161 | 159 | ||
162 | extern unsigned disabled_cpus __cpuinitdata; | 160 | extern unsigned disabled_cpus __cpuinitdata; |
163 | 161 | ||
diff --git a/include/asm-x86/statfs.h b/include/asm-x86/statfs.h index 3f005bc3aa5b..ca5dc19dd461 100644 --- a/include/asm-x86/statfs.h +++ b/include/asm-x86/statfs.h | |||
@@ -1,63 +1,12 @@ | |||
1 | #ifndef ASM_X86__STATFS_H | 1 | #ifndef ASM_X86__STATFS_H |
2 | #define ASM_X86__STATFS_H | 2 | #define ASM_X86__STATFS_H |
3 | 3 | ||
4 | #ifdef __i386__ | ||
5 | #include <asm-generic/statfs.h> | ||
6 | #else | ||
7 | |||
8 | #ifndef __KERNEL_STRICT_NAMES | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | |||
12 | typedef __kernel_fsid_t fsid_t; | ||
13 | |||
14 | #endif | ||
15 | |||
16 | /* | 4 | /* |
17 | * This is ugly -- we're already 64-bit clean, so just duplicate the | 5 | * We need compat_statfs64 to be packed, because the i386 ABI won't |
18 | * definitions. | 6 | * add padding at the end to bring it to a multiple of 8 bytes, but |
7 | * the x86_64 ABI will. | ||
19 | */ | 8 | */ |
20 | struct statfs { | 9 | #define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4))) |
21 | long f_type; | ||
22 | long f_bsize; | ||
23 | long f_blocks; | ||
24 | long f_bfree; | ||
25 | long f_bavail; | ||
26 | long f_files; | ||
27 | long f_ffree; | ||
28 | __kernel_fsid_t f_fsid; | ||
29 | long f_namelen; | ||
30 | long f_frsize; | ||
31 | long f_spare[5]; | ||
32 | }; | ||
33 | |||
34 | struct statfs64 { | ||
35 | long f_type; | ||
36 | long f_bsize; | ||
37 | long f_blocks; | ||
38 | long f_bfree; | ||
39 | long f_bavail; | ||
40 | long f_files; | ||
41 | long f_ffree; | ||
42 | __kernel_fsid_t f_fsid; | ||
43 | long f_namelen; | ||
44 | long f_frsize; | ||
45 | long f_spare[5]; | ||
46 | }; | ||
47 | 10 | ||
48 | struct compat_statfs64 { | 11 | #include <asm-generic/statfs.h> |
49 | __u32 f_type; | ||
50 | __u32 f_bsize; | ||
51 | __u64 f_blocks; | ||
52 | __u64 f_bfree; | ||
53 | __u64 f_bavail; | ||
54 | __u64 f_files; | ||
55 | __u64 f_ffree; | ||
56 | __kernel_fsid_t f_fsid; | ||
57 | __u32 f_namelen; | ||
58 | __u32 f_frsize; | ||
59 | __u32 f_spare[5]; | ||
60 | } __attribute__((packed)); | ||
61 | |||
62 | #endif /* !__i386__ */ | ||
63 | #endif /* ASM_X86__STATFS_H */ | 12 | #endif /* ASM_X86__STATFS_H */ |
diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h index 34505dd7b24d..b20c894660f9 100644 --- a/include/asm-x86/system.h +++ b/include/asm-x86/system.h | |||
@@ -64,7 +64,10 @@ do { \ | |||
64 | \ | 64 | \ |
65 | /* regparm parameters for __switch_to(): */ \ | 65 | /* regparm parameters for __switch_to(): */ \ |
66 | [prev] "a" (prev), \ | 66 | [prev] "a" (prev), \ |
67 | [next] "d" (next)); \ | 67 | [next] "d" (next) \ |
68 | \ | ||
69 | : /* reloaded segment registers */ \ | ||
70 | "memory"); \ | ||
68 | } while (0) | 71 | } while (0) |
69 | 72 | ||
70 | /* | 73 | /* |
diff --git a/include/asm-x86/traps.h b/include/asm-x86/traps.h index 7a692baa51ae..6c3dc2c65751 100644 --- a/include/asm-x86/traps.h +++ b/include/asm-x86/traps.h | |||
@@ -3,7 +3,12 @@ | |||
3 | 3 | ||
4 | #include <asm/debugreg.h> | 4 | #include <asm/debugreg.h> |
5 | 5 | ||
6 | /* Common in X86_32 and X86_64 */ | 6 | #ifdef CONFIG_X86_32 |
7 | #define dotraplinkage | ||
8 | #else | ||
9 | #define dotraplinkage asmlinkage | ||
10 | #endif | ||
11 | |||
7 | asmlinkage void divide_error(void); | 12 | asmlinkage void divide_error(void); |
8 | asmlinkage void debug(void); | 13 | asmlinkage void debug(void); |
9 | asmlinkage void nmi(void); | 14 | asmlinkage void nmi(void); |
@@ -12,31 +17,47 @@ asmlinkage void overflow(void); | |||
12 | asmlinkage void bounds(void); | 17 | asmlinkage void bounds(void); |
13 | asmlinkage void invalid_op(void); | 18 | asmlinkage void invalid_op(void); |
14 | asmlinkage void device_not_available(void); | 19 | asmlinkage void device_not_available(void); |
20 | #ifdef CONFIG_X86_64 | ||
21 | asmlinkage void double_fault(void); | ||
22 | #endif | ||
15 | asmlinkage void coprocessor_segment_overrun(void); | 23 | asmlinkage void coprocessor_segment_overrun(void); |
16 | asmlinkage void invalid_TSS(void); | 24 | asmlinkage void invalid_TSS(void); |
17 | asmlinkage void segment_not_present(void); | 25 | asmlinkage void segment_not_present(void); |
18 | asmlinkage void stack_segment(void); | 26 | asmlinkage void stack_segment(void); |
19 | asmlinkage void general_protection(void); | 27 | asmlinkage void general_protection(void); |
20 | asmlinkage void page_fault(void); | 28 | asmlinkage void page_fault(void); |
29 | asmlinkage void spurious_interrupt_bug(void); | ||
21 | asmlinkage void coprocessor_error(void); | 30 | asmlinkage void coprocessor_error(void); |
22 | asmlinkage void simd_coprocessor_error(void); | ||
23 | asmlinkage void alignment_check(void); | 31 | asmlinkage void alignment_check(void); |
24 | asmlinkage void spurious_interrupt_bug(void); | ||
25 | #ifdef CONFIG_X86_MCE | 32 | #ifdef CONFIG_X86_MCE |
26 | asmlinkage void machine_check(void); | 33 | asmlinkage void machine_check(void); |
27 | #endif /* CONFIG_X86_MCE */ | 34 | #endif /* CONFIG_X86_MCE */ |
35 | asmlinkage void simd_coprocessor_error(void); | ||
28 | 36 | ||
29 | void do_divide_error(struct pt_regs *, long); | 37 | dotraplinkage void do_divide_error(struct pt_regs *, long); |
30 | void do_overflow(struct pt_regs *, long); | 38 | dotraplinkage void do_debug(struct pt_regs *, long); |
31 | void do_bounds(struct pt_regs *, long); | 39 | dotraplinkage void do_nmi(struct pt_regs *, long); |
32 | void do_coprocessor_segment_overrun(struct pt_regs *, long); | 40 | dotraplinkage void do_int3(struct pt_regs *, long); |
33 | void do_invalid_TSS(struct pt_regs *, long); | 41 | dotraplinkage void do_overflow(struct pt_regs *, long); |
34 | void do_segment_not_present(struct pt_regs *, long); | 42 | dotraplinkage void do_bounds(struct pt_regs *, long); |
35 | void do_stack_segment(struct pt_regs *, long); | 43 | dotraplinkage void do_invalid_op(struct pt_regs *, long); |
36 | void do_alignment_check(struct pt_regs *, long); | 44 | dotraplinkage void do_device_not_available(struct pt_regs *, long); |
37 | void do_invalid_op(struct pt_regs *, long); | 45 | dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long); |
38 | void do_general_protection(struct pt_regs *, long); | 46 | dotraplinkage void do_invalid_TSS(struct pt_regs *, long); |
39 | void do_nmi(struct pt_regs *, long); | 47 | dotraplinkage void do_segment_not_present(struct pt_regs *, long); |
48 | dotraplinkage void do_stack_segment(struct pt_regs *, long); | ||
49 | dotraplinkage void do_general_protection(struct pt_regs *, long); | ||
50 | dotraplinkage void do_page_fault(struct pt_regs *, unsigned long); | ||
51 | dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long); | ||
52 | dotraplinkage void do_coprocessor_error(struct pt_regs *, long); | ||
53 | dotraplinkage void do_alignment_check(struct pt_regs *, long); | ||
54 | #ifdef CONFIG_X86_MCE | ||
55 | dotraplinkage void do_machine_check(struct pt_regs *, long); | ||
56 | #endif | ||
57 | dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); | ||
58 | #ifdef CONFIG_X86_32 | ||
59 | dotraplinkage void do_iret_error(struct pt_regs *, long); | ||
60 | #endif | ||
40 | 61 | ||
41 | static inline int get_si_code(unsigned long condition) | 62 | static inline int get_si_code(unsigned long condition) |
42 | { | 63 | { |
@@ -52,31 +73,9 @@ extern int panic_on_unrecovered_nmi; | |||
52 | extern int kstack_depth_to_print; | 73 | extern int kstack_depth_to_print; |
53 | 74 | ||
54 | #ifdef CONFIG_X86_32 | 75 | #ifdef CONFIG_X86_32 |
55 | |||
56 | void do_iret_error(struct pt_regs *, long); | ||
57 | void do_int3(struct pt_regs *, long); | ||
58 | void do_debug(struct pt_regs *, long); | ||
59 | void math_error(void __user *); | 76 | void math_error(void __user *); |
60 | void do_coprocessor_error(struct pt_regs *, long); | ||
61 | void do_simd_coprocessor_error(struct pt_regs *, long); | ||
62 | void do_spurious_interrupt_bug(struct pt_regs *, long); | ||
63 | unsigned long patch_espfix_desc(unsigned long, unsigned long); | 77 | unsigned long patch_espfix_desc(unsigned long, unsigned long); |
64 | asmlinkage void math_emulate(long); | 78 | asmlinkage void math_emulate(long); |
79 | #endif | ||
65 | 80 | ||
66 | void do_page_fault(struct pt_regs *regs, unsigned long error_code); | ||
67 | |||
68 | #else /* CONFIG_X86_32 */ | ||
69 | |||
70 | asmlinkage void double_fault(void); | ||
71 | |||
72 | asmlinkage void do_int3(struct pt_regs *, long); | ||
73 | asmlinkage void do_stack_segment(struct pt_regs *, long); | ||
74 | asmlinkage void do_debug(struct pt_regs *, unsigned long); | ||
75 | asmlinkage void do_coprocessor_error(struct pt_regs *); | ||
76 | asmlinkage void do_simd_coprocessor_error(struct pt_regs *); | ||
77 | asmlinkage void do_spurious_interrupt_bug(struct pt_regs *); | ||
78 | |||
79 | asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code); | ||
80 | |||
81 | #endif /* CONFIG_X86_32 */ | ||
82 | #endif /* ASM_X86__TRAPS_H */ | 81 | #endif /* ASM_X86__TRAPS_H */ |
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h deleted file mode 100644 index fdf13702924a..000000000000 --- a/include/asm-xtensa/a.out.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* | ||
2 | * include/asm-xtensa/a.out.h | ||
3 | * | ||
4 | * Dummy a.out file. Xtensa does not support the a.out format, but the kernel | ||
5 | * seems to depend on it. | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | * | ||
11 | * Copyright (C) 2001 - 2005 Tensilica Inc. | ||
12 | */ | ||
13 | |||
14 | #ifndef _XTENSA_A_OUT_H | ||
15 | #define _XTENSA_A_OUT_H | ||
16 | |||
17 | struct exec | ||
18 | { | ||
19 | unsigned long a_info; | ||
20 | unsigned a_text; | ||
21 | unsigned a_data; | ||
22 | unsigned a_bss; | ||
23 | unsigned a_syms; | ||
24 | unsigned a_entry; | ||
25 | unsigned a_trsize; | ||
26 | unsigned a_drsize; | ||
27 | }; | ||
28 | |||
29 | #endif /* _XTENSA_A_OUT_H */ | ||
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h index 154769cad3f3..5ce0e5fd712e 100644 --- a/include/linux/devpts_fs.h +++ b/include/linux/devpts_fs.h | |||
@@ -17,20 +17,31 @@ | |||
17 | 17 | ||
18 | #ifdef CONFIG_UNIX98_PTYS | 18 | #ifdef CONFIG_UNIX98_PTYS |
19 | 19 | ||
20 | int devpts_new_index(void); | 20 | int devpts_new_index(struct inode *ptmx_inode); |
21 | void devpts_kill_index(int idx); | 21 | void devpts_kill_index(struct inode *ptmx_inode, int idx); |
22 | int devpts_pty_new(struct tty_struct *tty); /* mknod in devpts */ | 22 | /* mknod in devpts */ |
23 | struct tty_struct *devpts_get_tty(int number); /* get tty structure */ | 23 | int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty); |
24 | void devpts_pty_kill(int number); /* unlink */ | 24 | /* get tty structure */ |
25 | struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number); | ||
26 | /* unlink */ | ||
27 | void devpts_pty_kill(struct tty_struct *tty); | ||
25 | 28 | ||
26 | #else | 29 | #else |
27 | 30 | ||
28 | /* Dummy stubs in the no-pty case */ | 31 | /* Dummy stubs in the no-pty case */ |
29 | static inline int devpts_new_index(void) { return -EINVAL; } | 32 | static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } |
30 | static inline void devpts_kill_index(int idx) { } | 33 | static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } |
31 | static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; } | 34 | static inline int devpts_pty_new(struct inode *ptmx_inode, |
32 | static inline struct tty_struct *devpts_get_tty(int number) { return NULL; } | 35 | struct tty_struct *tty) |
33 | static inline void devpts_pty_kill(int number) { } | 36 | { |
37 | return -EINVAL; | ||
38 | } | ||
39 | static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode, | ||
40 | int number) | ||
41 | { | ||
42 | return NULL; | ||
43 | } | ||
44 | static inline void devpts_pty_kill(struct tty_struct *tty) { } | ||
34 | 45 | ||
35 | #endif | 46 | #endif |
36 | 47 | ||
diff --git a/include/linux/dmi.h b/include/linux/dmi.h index 2a063b64133f..e5084eb5943a 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h | |||
@@ -2,29 +2,9 @@ | |||
2 | #define __DMI_H__ | 2 | #define __DMI_H__ |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <linux/mod_devicetable.h> | ||
5 | 6 | ||
6 | enum dmi_field { | 7 | /* enum dmi_field is in mod_devicetable.h */ |
7 | DMI_NONE, | ||
8 | DMI_BIOS_VENDOR, | ||
9 | DMI_BIOS_VERSION, | ||
10 | DMI_BIOS_DATE, | ||
11 | DMI_SYS_VENDOR, | ||
12 | DMI_PRODUCT_NAME, | ||
13 | DMI_PRODUCT_VERSION, | ||
14 | DMI_PRODUCT_SERIAL, | ||
15 | DMI_PRODUCT_UUID, | ||
16 | DMI_BOARD_VENDOR, | ||
17 | DMI_BOARD_NAME, | ||
18 | DMI_BOARD_VERSION, | ||
19 | DMI_BOARD_SERIAL, | ||
20 | DMI_BOARD_ASSET_TAG, | ||
21 | DMI_CHASSIS_VENDOR, | ||
22 | DMI_CHASSIS_TYPE, | ||
23 | DMI_CHASSIS_VERSION, | ||
24 | DMI_CHASSIS_SERIAL, | ||
25 | DMI_CHASSIS_ASSET_TAG, | ||
26 | DMI_STRING_MAX, | ||
27 | }; | ||
28 | 8 | ||
29 | enum dmi_device_type { | 9 | enum dmi_device_type { |
30 | DMI_DEV_TYPE_ANY = 0, | 10 | DMI_DEV_TYPE_ANY = 0, |
@@ -48,23 +28,6 @@ struct dmi_header { | |||
48 | u16 handle; | 28 | u16 handle; |
49 | }; | 29 | }; |
50 | 30 | ||
51 | /* | ||
52 | * DMI callbacks for problem boards | ||
53 | */ | ||
54 | struct dmi_strmatch { | ||
55 | u8 slot; | ||
56 | char *substr; | ||
57 | }; | ||
58 | |||
59 | struct dmi_system_id { | ||
60 | int (*callback)(const struct dmi_system_id *); | ||
61 | const char *ident; | ||
62 | struct dmi_strmatch matches[4]; | ||
63 | void *driver_data; | ||
64 | }; | ||
65 | |||
66 | #define DMI_MATCH(a, b) { a, b } | ||
67 | |||
68 | struct dmi_device { | 31 | struct dmi_device { |
69 | struct list_head list; | 32 | struct list_head list; |
70 | int type; | 33 | int type; |
diff --git a/include/linux/hpet.h b/include/linux/hpet.h index 2dc29ce6c8e4..79f63a27bcef 100644 --- a/include/linux/hpet.h +++ b/include/linux/hpet.h | |||
@@ -37,6 +37,7 @@ struct hpet { | |||
37 | #define hpet_compare _u1._hpet_compare | 37 | #define hpet_compare _u1._hpet_compare |
38 | 38 | ||
39 | #define HPET_MAX_TIMERS (32) | 39 | #define HPET_MAX_TIMERS (32) |
40 | #define HPET_MAX_IRQ (32) | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * HPET general capabilities register | 43 | * HPET general capabilities register |
@@ -64,7 +65,7 @@ struct hpet { | |||
64 | */ | 65 | */ |
65 | 66 | ||
66 | #define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL) | 67 | #define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL) |
67 | #define Tn_INI_ROUTE_CAP_SHIFT (32UL) | 68 | #define Tn_INT_ROUTE_CAP_SHIFT (32UL) |
68 | #define Tn_FSB_INT_DELCAP_MASK (0x8000UL) | 69 | #define Tn_FSB_INT_DELCAP_MASK (0x8000UL) |
69 | #define Tn_FSB_INT_DELCAP_SHIFT (15) | 70 | #define Tn_FSB_INT_DELCAP_SHIFT (15) |
70 | #define Tn_FSB_EN_CNF_MASK (0x4000UL) | 71 | #define Tn_FSB_EN_CNF_MASK (0x4000UL) |
@@ -91,23 +92,14 @@ struct hpet { | |||
91 | * exported interfaces | 92 | * exported interfaces |
92 | */ | 93 | */ |
93 | 94 | ||
94 | struct hpet_task { | ||
95 | void (*ht_func) (void *); | ||
96 | void *ht_data; | ||
97 | void *ht_opaque; | ||
98 | }; | ||
99 | |||
100 | struct hpet_data { | 95 | struct hpet_data { |
101 | unsigned long hd_phys_address; | 96 | unsigned long hd_phys_address; |
102 | void __iomem *hd_address; | 97 | void __iomem *hd_address; |
103 | unsigned short hd_nirqs; | 98 | unsigned short hd_nirqs; |
104 | unsigned short hd_flags; | ||
105 | unsigned int hd_state; /* timer allocated */ | 99 | unsigned int hd_state; /* timer allocated */ |
106 | unsigned int hd_irq[HPET_MAX_TIMERS]; | 100 | unsigned int hd_irq[HPET_MAX_TIMERS]; |
107 | }; | 101 | }; |
108 | 102 | ||
109 | #define HPET_DATA_PLATFORM 0x0001 /* platform call to hpet_alloc */ | ||
110 | |||
111 | static inline void hpet_reserve_timer(struct hpet_data *hd, int timer) | 103 | static inline void hpet_reserve_timer(struct hpet_data *hd, int timer) |
112 | { | 104 | { |
113 | hd->hd_state |= (1 << timer); | 105 | hd->hd_state |= (1 << timer); |
@@ -125,7 +117,7 @@ struct hpet_info { | |||
125 | unsigned short hi_timer; | 117 | unsigned short hi_timer; |
126 | }; | 118 | }; |
127 | 119 | ||
128 | #define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */ | 120 | #define HPET_INFO_PERIODIC 0x0010 /* periodic-capable comparator */ |
129 | 121 | ||
130 | #define HPET_IE_ON _IO('h', 0x01) /* interrupt on */ | 122 | #define HPET_IE_ON _IO('h', 0x01) /* interrupt on */ |
131 | #define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */ | 123 | #define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */ |
diff --git a/include/linux/magic.h b/include/linux/magic.h index 1fa0c2ce4dec..f7f3fdddbef0 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h | |||
@@ -6,6 +6,10 @@ | |||
6 | #define AFS_SUPER_MAGIC 0x5346414F | 6 | #define AFS_SUPER_MAGIC 0x5346414F |
7 | #define AUTOFS_SUPER_MAGIC 0x0187 | 7 | #define AUTOFS_SUPER_MAGIC 0x0187 |
8 | #define CODA_SUPER_MAGIC 0x73757245 | 8 | #define CODA_SUPER_MAGIC 0x73757245 |
9 | #define DEBUGFS_MAGIC 0x64626720 | ||
10 | #define SYSFS_MAGIC 0x62656572 | ||
11 | #define SECURITYFS_MAGIC 0x73636673 | ||
12 | #define TMPFS_MAGIC 0x01021994 | ||
9 | #define EFS_SUPER_MAGIC 0x414A53 | 13 | #define EFS_SUPER_MAGIC 0x414A53 |
10 | #define EXT2_SUPER_MAGIC 0xEF53 | 14 | #define EXT2_SUPER_MAGIC 0xEF53 |
11 | #define EXT3_SUPER_MAGIC 0xEF53 | 15 | #define EXT3_SUPER_MAGIC 0xEF53 |
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index c4db5827963d..3481a7d5bc0a 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h | |||
@@ -388,5 +388,52 @@ struct i2c_device_id { | |||
388 | __attribute__((aligned(sizeof(kernel_ulong_t)))); | 388 | __attribute__((aligned(sizeof(kernel_ulong_t)))); |
389 | }; | 389 | }; |
390 | 390 | ||
391 | /* dmi */ | ||
392 | enum dmi_field { | ||
393 | DMI_NONE, | ||
394 | DMI_BIOS_VENDOR, | ||
395 | DMI_BIOS_VERSION, | ||
396 | DMI_BIOS_DATE, | ||
397 | DMI_SYS_VENDOR, | ||
398 | DMI_PRODUCT_NAME, | ||
399 | DMI_PRODUCT_VERSION, | ||
400 | DMI_PRODUCT_SERIAL, | ||
401 | DMI_PRODUCT_UUID, | ||
402 | DMI_BOARD_VENDOR, | ||
403 | DMI_BOARD_NAME, | ||
404 | DMI_BOARD_VERSION, | ||
405 | DMI_BOARD_SERIAL, | ||
406 | DMI_BOARD_ASSET_TAG, | ||
407 | DMI_CHASSIS_VENDOR, | ||
408 | DMI_CHASSIS_TYPE, | ||
409 | DMI_CHASSIS_VERSION, | ||
410 | DMI_CHASSIS_SERIAL, | ||
411 | DMI_CHASSIS_ASSET_TAG, | ||
412 | DMI_STRING_MAX, | ||
413 | }; | ||
414 | |||
415 | struct dmi_strmatch { | ||
416 | unsigned char slot; | ||
417 | char substr[79]; | ||
418 | }; | ||
419 | |||
420 | #ifndef __KERNEL__ | ||
421 | struct dmi_system_id { | ||
422 | kernel_ulong_t callback; | ||
423 | kernel_ulong_t ident; | ||
424 | struct dmi_strmatch matches[4]; | ||
425 | kernel_ulong_t driver_data | ||
426 | __attribute__((aligned(sizeof(kernel_ulong_t)))); | ||
427 | }; | ||
428 | #else | ||
429 | struct dmi_system_id { | ||
430 | int (*callback)(const struct dmi_system_id *); | ||
431 | const char *ident; | ||
432 | struct dmi_strmatch matches[4]; | ||
433 | void *driver_data; | ||
434 | }; | ||
435 | #endif | ||
436 | |||
437 | #define DMI_MATCH(a, b) { a, b } | ||
391 | 438 | ||
392 | #endif /* LINUX_MOD_DEVICETABLE_H */ | 439 | #endif /* LINUX_MOD_DEVICETABLE_H */ |
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 041bb31100f4..bcb8f725427c 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h | |||
@@ -36,6 +36,8 @@ | |||
36 | #define XEN_ENTER_SWITCH_CODE 10 | 36 | #define XEN_ENTER_SWITCH_CODE 10 |
37 | #define SPU_PROFILING_CODE 11 | 37 | #define SPU_PROFILING_CODE 11 |
38 | #define SPU_CTX_SWITCH_CODE 12 | 38 | #define SPU_CTX_SWITCH_CODE 12 |
39 | #define IBS_FETCH_CODE 13 | ||
40 | #define IBS_OP_CODE 14 | ||
39 | 41 | ||
40 | struct super_block; | 42 | struct super_block; |
41 | struct dentry; | 43 | struct dentry; |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f63b5455801c..1176f1f177e2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -1533,7 +1533,9 @@ | |||
1533 | #define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 | 1533 | #define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 |
1534 | #define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 | 1534 | #define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 |
1535 | #define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 | 1535 | #define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 |
1536 | #define PCI_DEVICE_ID_MARVELL_CAFE_SD 0x4101 | 1536 | #define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100 |
1537 | #define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101 | ||
1538 | #define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102 | ||
1537 | 1539 | ||
1538 | #define PCI_VENDOR_ID_V3 0x11b0 | 1540 | #define PCI_VENDOR_ID_V3 0x11b0 |
1539 | #define PCI_DEVICE_ID_V3_V960 0x0001 | 1541 | #define PCI_DEVICE_ID_V3_V960 0x0001 |
diff --git a/include/linux/serial.h b/include/linux/serial.h index deb714314fb1..1ea8d9265bf6 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h | |||
@@ -173,6 +173,22 @@ struct serial_icounter_struct { | |||
173 | int reserved[9]; | 173 | int reserved[9]; |
174 | }; | 174 | }; |
175 | 175 | ||
176 | /* | ||
177 | * Serial interface for controlling RS485 settings on chips with suitable | ||
178 | * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your | ||
179 | * platform. The set function returns the new state, with any unsupported bits | ||
180 | * reverted appropriately. | ||
181 | */ | ||
182 | |||
183 | struct serial_rs485 { | ||
184 | __u32 flags; /* RS485 feature flags */ | ||
185 | #define SER_RS485_ENABLED (1 << 0) | ||
186 | #define SER_RS485_RTS_ON_SEND (1 << 1) | ||
187 | #define SER_RS485_RTS_AFTER_SEND (1 << 2) | ||
188 | __u32 delay_rts_before_send; /* Milliseconds */ | ||
189 | __u32 padding[6]; /* Memory is cheap, new structs | ||
190 | are a royal PITA .. */ | ||
191 | }; | ||
176 | 192 | ||
177 | #ifdef __KERNEL__ | 193 | #ifdef __KERNEL__ |
178 | #include <linux/compiler.h> | 194 | #include <linux/compiler.h> |
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 3b2f6c04855e..e27f216361fc 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
@@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t; | |||
241 | 241 | ||
242 | struct uart_port { | 242 | struct uart_port { |
243 | spinlock_t lock; /* port lock */ | 243 | spinlock_t lock; /* port lock */ |
244 | unsigned int iobase; /* in/out[bwl] */ | 244 | unsigned long iobase; /* in/out[bwl] */ |
245 | unsigned char __iomem *membase; /* read/write[bwl] */ | 245 | unsigned char __iomem *membase; /* read/write[bwl] */ |
246 | unsigned int irq; /* irq number */ | 246 | unsigned int irq; /* irq number */ |
247 | unsigned int uartclk; /* base uart clock */ | 247 | unsigned int uartclk; /* base uart clock */ |
diff --git a/include/linux/termios.h b/include/linux/termios.h index 478662889f48..2acd0c1f8a2a 100644 --- a/include/linux/termios.h +++ b/include/linux/termios.h | |||
@@ -4,4 +4,19 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <asm/termios.h> | 5 | #include <asm/termios.h> |
6 | 6 | ||
7 | #define NFF 5 | ||
8 | |||
9 | struct termiox | ||
10 | { | ||
11 | __u16 x_hflag; | ||
12 | __u16 x_cflag; | ||
13 | __u16 x_rflag[NFF]; | ||
14 | __u16 x_sflag; | ||
15 | }; | ||
16 | |||
17 | #define RTSXOFF 0x0001 /* RTS flow control on input */ | ||
18 | #define CTSXON 0x0002 /* CTS flow control on output */ | ||
19 | #define DTRXOFF 0x0004 /* DTR flow control on input */ | ||
20 | #define DSRXON 0x0008 /* DCD flow control on output */ | ||
21 | |||
7 | #endif | 22 | #endif |
diff --git a/include/linux/tty.h b/include/linux/tty.h index 0cbec74ec086..3b8121d4e36f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ | 24 | #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ |
25 | #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ | 25 | #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ |
26 | #define NR_LDISCS 18 | 26 | #define NR_LDISCS 19 |
27 | 27 | ||
28 | /* line disciplines */ | 28 | /* line disciplines */ |
29 | #define N_TTY 0 | 29 | #define N_TTY 0 |
@@ -45,6 +45,7 @@ | |||
45 | #define N_HCI 15 /* Bluetooth HCI UART */ | 45 | #define N_HCI 15 /* Bluetooth HCI UART */ |
46 | #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ | 46 | #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ |
47 | #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ | 47 | #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ |
48 | #define N_PPS 18 /* Pulse per Second */ | ||
48 | 49 | ||
49 | /* | 50 | /* |
50 | * This character is the same as _POSIX_VDISABLE: it cannot be used as | 51 | * This character is the same as _POSIX_VDISABLE: it cannot be used as |
@@ -181,6 +182,7 @@ struct signal_struct; | |||
181 | 182 | ||
182 | struct tty_port { | 183 | struct tty_port { |
183 | struct tty_struct *tty; /* Back pointer */ | 184 | struct tty_struct *tty; /* Back pointer */ |
185 | spinlock_t lock; /* Lock protecting tty field */ | ||
184 | int blocked_open; /* Waiting to open */ | 186 | int blocked_open; /* Waiting to open */ |
185 | int count; /* Usage count */ | 187 | int count; /* Usage count */ |
186 | wait_queue_head_t open_wait; /* Open waiters */ | 188 | wait_queue_head_t open_wait; /* Open waiters */ |
@@ -208,6 +210,7 @@ struct tty_operations; | |||
208 | 210 | ||
209 | struct tty_struct { | 211 | struct tty_struct { |
210 | int magic; | 212 | int magic; |
213 | struct kref kref; | ||
211 | struct tty_driver *driver; | 214 | struct tty_driver *driver; |
212 | const struct tty_operations *ops; | 215 | const struct tty_operations *ops; |
213 | int index; | 216 | int index; |
@@ -217,6 +220,7 @@ struct tty_struct { | |||
217 | spinlock_t ctrl_lock; | 220 | spinlock_t ctrl_lock; |
218 | /* Termios values are protected by the termios mutex */ | 221 | /* Termios values are protected by the termios mutex */ |
219 | struct ktermios *termios, *termios_locked; | 222 | struct ktermios *termios, *termios_locked; |
223 | struct termiox *termiox; /* May be NULL for unsupported */ | ||
220 | char name[64]; | 224 | char name[64]; |
221 | struct pid *pgrp; /* Protected by ctrl lock */ | 225 | struct pid *pgrp; /* Protected by ctrl lock */ |
222 | struct pid *session; | 226 | struct pid *session; |
@@ -310,6 +314,25 @@ extern int kmsg_redirect; | |||
310 | extern void console_init(void); | 314 | extern void console_init(void); |
311 | extern int vcs_init(void); | 315 | extern int vcs_init(void); |
312 | 316 | ||
317 | extern struct class *tty_class; | ||
318 | |||
319 | /** | ||
320 | * tty_kref_get - get a tty reference | ||
321 | * @tty: tty device | ||
322 | * | ||
323 | * Return a new reference to a tty object. The caller must hold | ||
324 | * sufficient locks/counts to ensure that their existing reference cannot | ||
325 | * go away | ||
326 | */ | ||
327 | |||
328 | extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty) | ||
329 | { | ||
330 | if (tty) | ||
331 | kref_get(&tty->kref); | ||
332 | return tty; | ||
333 | } | ||
334 | extern void tty_kref_put(struct tty_struct *tty); | ||
335 | |||
313 | extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, | 336 | extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, |
314 | const char *routine); | 337 | const char *routine); |
315 | extern char *tty_name(struct tty_struct *tty, char *buf); | 338 | extern char *tty_name(struct tty_struct *tty, char *buf); |
@@ -333,13 +356,15 @@ extern void tty_throttle(struct tty_struct *tty); | |||
333 | extern void tty_unthrottle(struct tty_struct *tty); | 356 | extern void tty_unthrottle(struct tty_struct *tty); |
334 | extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, | 357 | extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, |
335 | struct winsize *ws); | 358 | struct winsize *ws); |
336 | 359 | extern void tty_shutdown(struct tty_struct *tty); | |
360 | extern void tty_free_termios(struct tty_struct *tty); | ||
337 | extern int is_current_pgrp_orphaned(void); | 361 | extern int is_current_pgrp_orphaned(void); |
338 | extern struct pid *tty_get_pgrp(struct tty_struct *tty); | 362 | extern struct pid *tty_get_pgrp(struct tty_struct *tty); |
339 | extern int is_ignored(int sig); | 363 | extern int is_ignored(int sig); |
340 | extern int tty_signal(int sig, struct tty_struct *tty); | 364 | extern int tty_signal(int sig, struct tty_struct *tty); |
341 | extern void tty_hangup(struct tty_struct *tty); | 365 | extern void tty_hangup(struct tty_struct *tty); |
342 | extern void tty_vhangup(struct tty_struct *tty); | 366 | extern void tty_vhangup(struct tty_struct *tty); |
367 | extern void tty_vhangup_self(void); | ||
343 | extern void tty_unhangup(struct file *filp); | 368 | extern void tty_unhangup(struct file *filp); |
344 | extern int tty_hung_up_p(struct file *filp); | 369 | extern int tty_hung_up_p(struct file *filp); |
345 | extern void do_SAK(struct tty_struct *tty); | 370 | extern void do_SAK(struct tty_struct *tty); |
@@ -347,6 +372,9 @@ extern void __do_SAK(struct tty_struct *tty); | |||
347 | extern void disassociate_ctty(int priv); | 372 | extern void disassociate_ctty(int priv); |
348 | extern void no_tty(void); | 373 | extern void no_tty(void); |
349 | extern void tty_flip_buffer_push(struct tty_struct *tty); | 374 | extern void tty_flip_buffer_push(struct tty_struct *tty); |
375 | extern void tty_buffer_free_all(struct tty_struct *tty); | ||
376 | extern void tty_buffer_flush(struct tty_struct *tty); | ||
377 | extern void tty_buffer_init(struct tty_struct *tty); | ||
350 | extern speed_t tty_get_baud_rate(struct tty_struct *tty); | 378 | extern speed_t tty_get_baud_rate(struct tty_struct *tty); |
351 | extern speed_t tty_termios_baud_rate(struct ktermios *termios); | 379 | extern speed_t tty_termios_baud_rate(struct ktermios *termios); |
352 | extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); | 380 | extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); |
@@ -372,6 +400,15 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); | |||
372 | extern dev_t tty_devnum(struct tty_struct *tty); | 400 | extern dev_t tty_devnum(struct tty_struct *tty); |
373 | extern void proc_clear_tty(struct task_struct *p); | 401 | extern void proc_clear_tty(struct task_struct *p); |
374 | extern struct tty_struct *get_current_tty(void); | 402 | extern struct tty_struct *get_current_tty(void); |
403 | extern void tty_default_fops(struct file_operations *fops); | ||
404 | extern struct tty_struct *alloc_tty_struct(void); | ||
405 | extern void free_tty_struct(struct tty_struct *tty); | ||
406 | extern void initialize_tty_struct(struct tty_struct *tty, | ||
407 | struct tty_driver *driver, int idx); | ||
408 | extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, | ||
409 | int first_ok); | ||
410 | extern void tty_release_dev(struct file *filp); | ||
411 | extern int tty_init_termios(struct tty_struct *tty); | ||
375 | 412 | ||
376 | extern struct mutex tty_mutex; | 413 | extern struct mutex tty_mutex; |
377 | 414 | ||
@@ -382,6 +419,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay); | |||
382 | extern void tty_port_init(struct tty_port *port); | 419 | extern void tty_port_init(struct tty_port *port); |
383 | extern int tty_port_alloc_xmit_buf(struct tty_port *port); | 420 | extern int tty_port_alloc_xmit_buf(struct tty_port *port); |
384 | extern void tty_port_free_xmit_buf(struct tty_port *port); | 421 | extern void tty_port_free_xmit_buf(struct tty_port *port); |
422 | extern struct tty_struct *tty_port_tty_get(struct tty_port *port); | ||
423 | extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); | ||
385 | 424 | ||
386 | extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); | 425 | extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); |
387 | extern int tty_unregister_ldisc(int disc); | 426 | extern int tty_unregister_ldisc(int disc); |
@@ -427,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk, | |||
427 | #endif | 466 | #endif |
428 | 467 | ||
429 | /* tty_ioctl.c */ | 468 | /* tty_ioctl.c */ |
430 | extern int n_tty_ioctl(struct tty_struct *tty, struct file *file, | 469 | extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, |
431 | unsigned int cmd, unsigned long arg); | 470 | unsigned int cmd, unsigned long arg); |
432 | 471 | ||
433 | /* serial.c */ | 472 | /* serial.c */ |
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 16d27944c321..78416b901589 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h | |||
@@ -7,6 +7,28 @@ | |||
7 | * defined; unless noted otherwise, they are optional, and can be | 7 | * defined; unless noted otherwise, they are optional, and can be |
8 | * filled in with a null pointer. | 8 | * filled in with a null pointer. |
9 | * | 9 | * |
10 | * struct tty_struct * (*lookup)(struct tty_driver *self, int idx) | ||
11 | * | ||
12 | * Return the tty device corresponding to idx, NULL if there is not | ||
13 | * one currently in use and an ERR_PTR value on error. Called under | ||
14 | * tty_mutex (for now!) | ||
15 | * | ||
16 | * Optional method. Default behaviour is to use the ttys array | ||
17 | * | ||
18 | * int (*install)(struct tty_driver *self, struct tty_struct *tty) | ||
19 | * | ||
20 | * Install a new tty into the tty driver internal tables. Used in | ||
21 | * conjunction with lookup and remove methods. | ||
22 | * | ||
23 | * Optional method. Default behaviour is to use the ttys array | ||
24 | * | ||
25 | * void (*remove)(struct tty_driver *self, struct tty_struct *tty) | ||
26 | * | ||
27 | * Remove a closed tty from the tty driver internal tables. Used in | ||
28 | * conjunction with lookup and remove methods. | ||
29 | * | ||
30 | * Optional method. Default behaviour is to use the ttys array | ||
31 | * | ||
10 | * int (*open)(struct tty_struct * tty, struct file * filp); | 32 | * int (*open)(struct tty_struct * tty, struct file * filp); |
11 | * | 33 | * |
12 | * This routine is called when a particular tty device is opened. | 34 | * This routine is called when a particular tty device is opened. |
@@ -21,6 +43,11 @@ | |||
21 | * | 43 | * |
22 | * Required method. | 44 | * Required method. |
23 | * | 45 | * |
46 | * void (*shutdown)(struct tty_struct * tty); | ||
47 | * | ||
48 | * This routine is called when a particular tty device is closed for | ||
49 | * the last time freeing up the resources. | ||
50 | * | ||
24 | * int (*write)(struct tty_struct * tty, | 51 | * int (*write)(struct tty_struct * tty, |
25 | * const unsigned char *buf, int count); | 52 | * const unsigned char *buf, int count); |
26 | * | 53 | * |
@@ -180,6 +207,14 @@ | |||
180 | * not force errors here if they are not resizable objects (eg a serial | 207 | * not force errors here if they are not resizable objects (eg a serial |
181 | * line). See tty_do_resize() if you need to wrap the standard method | 208 | * line). See tty_do_resize() if you need to wrap the standard method |
182 | * in your own logic - the usual case. | 209 | * in your own logic - the usual case. |
210 | * | ||
211 | * void (*set_termiox)(struct tty_struct *tty, struct termiox *new); | ||
212 | * | ||
213 | * Called when the device receives a termiox based ioctl. Passes down | ||
214 | * the requested data from user space. This method will not be invoked | ||
215 | * unless the tty also has a valid tty->termiox pointer. | ||
216 | * | ||
217 | * Optional: Called under the termios lock | ||
183 | */ | 218 | */ |
184 | 219 | ||
185 | #include <linux/fs.h> | 220 | #include <linux/fs.h> |
@@ -190,8 +225,13 @@ struct tty_struct; | |||
190 | struct tty_driver; | 225 | struct tty_driver; |
191 | 226 | ||
192 | struct tty_operations { | 227 | struct tty_operations { |
228 | struct tty_struct * (*lookup)(struct tty_driver *driver, | ||
229 | struct inode *inode, int idx); | ||
230 | int (*install)(struct tty_driver *driver, struct tty_struct *tty); | ||
231 | void (*remove)(struct tty_driver *driver, struct tty_struct *tty); | ||
193 | int (*open)(struct tty_struct * tty, struct file * filp); | 232 | int (*open)(struct tty_struct * tty, struct file * filp); |
194 | void (*close)(struct tty_struct * tty, struct file * filp); | 233 | void (*close)(struct tty_struct * tty, struct file * filp); |
234 | void (*shutdown)(struct tty_struct *tty); | ||
195 | int (*write)(struct tty_struct * tty, | 235 | int (*write)(struct tty_struct * tty, |
196 | const unsigned char *buf, int count); | 236 | const unsigned char *buf, int count); |
197 | int (*put_char)(struct tty_struct *tty, unsigned char ch); | 237 | int (*put_char)(struct tty_struct *tty, unsigned char ch); |
@@ -220,6 +260,7 @@ struct tty_operations { | |||
220 | unsigned int set, unsigned int clear); | 260 | unsigned int set, unsigned int clear); |
221 | int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, | 261 | int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, |
222 | struct winsize *ws); | 262 | struct winsize *ws); |
263 | int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); | ||
223 | #ifdef CONFIG_CONSOLE_POLL | 264 | #ifdef CONFIG_CONSOLE_POLL |
224 | int (*poll_init)(struct tty_driver *driver, int line, char *options); | 265 | int (*poll_init)(struct tty_driver *driver, int line, char *options); |
225 | int (*poll_get_char)(struct tty_driver *driver, int line); | 266 | int (*poll_get_char)(struct tty_driver *driver, int line); |
@@ -229,6 +270,7 @@ struct tty_operations { | |||
229 | 270 | ||
230 | struct tty_driver { | 271 | struct tty_driver { |
231 | int magic; /* magic number for this structure */ | 272 | int magic; /* magic number for this structure */ |
273 | struct kref kref; /* Reference management */ | ||
232 | struct cdev cdev; | 274 | struct cdev cdev; |
233 | struct module *owner; | 275 | struct module *owner; |
234 | const char *driver_name; | 276 | const char *driver_name; |
@@ -242,7 +284,6 @@ struct tty_driver { | |||
242 | short subtype; /* subtype of tty driver */ | 284 | short subtype; /* subtype of tty driver */ |
243 | struct ktermios init_termios; /* Initial termios */ | 285 | struct ktermios init_termios; /* Initial termios */ |
244 | int flags; /* tty driver flags */ | 286 | int flags; /* tty driver flags */ |
245 | int refcount; /* for loadable tty drivers */ | ||
246 | struct proc_dir_entry *proc_entry; /* /proc fs entry */ | 287 | struct proc_dir_entry *proc_entry; /* /proc fs entry */ |
247 | struct tty_driver *other; /* only used for the PTY driver */ | 288 | struct tty_driver *other; /* only used for the PTY driver */ |
248 | 289 | ||
@@ -264,12 +305,19 @@ struct tty_driver { | |||
264 | 305 | ||
265 | extern struct list_head tty_drivers; | 306 | extern struct list_head tty_drivers; |
266 | 307 | ||
267 | struct tty_driver *alloc_tty_driver(int lines); | 308 | extern struct tty_driver *alloc_tty_driver(int lines); |
268 | void put_tty_driver(struct tty_driver *driver); | 309 | extern void put_tty_driver(struct tty_driver *driver); |
269 | void tty_set_operations(struct tty_driver *driver, | 310 | extern void tty_set_operations(struct tty_driver *driver, |
270 | const struct tty_operations *op); | 311 | const struct tty_operations *op); |
271 | extern struct tty_driver *tty_find_polling_driver(char *name, int *line); | 312 | extern struct tty_driver *tty_find_polling_driver(char *name, int *line); |
272 | 313 | ||
314 | extern void tty_driver_kref_put(struct tty_driver *driver); | ||
315 | extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) | ||
316 | { | ||
317 | kref_get(&d->kref); | ||
318 | return d; | ||
319 | } | ||
320 | |||
273 | /* tty driver magic number */ | 321 | /* tty driver magic number */ |
274 | #define TTY_DRIVER_MAGIC 0x5402 | 322 | #define TTY_DRIVER_MAGIC 0x5402 |
275 | 323 | ||
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 1cbd0a7db4e6..2f1113467f70 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h | |||
@@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc); | |||
96 | void reset_vc(struct vc_data *vc); | 96 | void reset_vc(struct vc_data *vc); |
97 | extern int unbind_con_driver(const struct consw *csw, int first, int last, | 97 | extern int unbind_con_driver(const struct consw *csw, int first, int last, |
98 | int deflt); | 98 | int deflt); |
99 | int vty_init(void); | 99 | int vty_init(const struct file_operations *console_fops); |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * vc_screen.c shares this temporary buffer with the console write code so that | 102 | * vc_screen.c shares this temporary buffer with the console write code so that |
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index a6bb94530cfd..9909774eb998 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h | |||
@@ -40,11 +40,12 @@ | |||
40 | #include <linux/net.h> | 40 | #include <linux/net.h> |
41 | #include <linux/skbuff.h> | 41 | #include <linux/skbuff.h> |
42 | #include <net/netlabel.h> | 42 | #include <net/netlabel.h> |
43 | #include <asm/atomic.h> | ||
43 | 44 | ||
44 | /* known doi values */ | 45 | /* known doi values */ |
45 | #define CIPSO_V4_DOI_UNKNOWN 0x00000000 | 46 | #define CIPSO_V4_DOI_UNKNOWN 0x00000000 |
46 | 47 | ||
47 | /* tag types */ | 48 | /* standard tag types */ |
48 | #define CIPSO_V4_TAG_INVALID 0 | 49 | #define CIPSO_V4_TAG_INVALID 0 |
49 | #define CIPSO_V4_TAG_RBITMAP 1 | 50 | #define CIPSO_V4_TAG_RBITMAP 1 |
50 | #define CIPSO_V4_TAG_ENUM 2 | 51 | #define CIPSO_V4_TAG_ENUM 2 |
@@ -52,10 +53,14 @@ | |||
52 | #define CIPSO_V4_TAG_PBITMAP 6 | 53 | #define CIPSO_V4_TAG_PBITMAP 6 |
53 | #define CIPSO_V4_TAG_FREEFORM 7 | 54 | #define CIPSO_V4_TAG_FREEFORM 7 |
54 | 55 | ||
56 | /* non-standard tag types (tags > 127) */ | ||
57 | #define CIPSO_V4_TAG_LOCAL 128 | ||
58 | |||
55 | /* doi mapping types */ | 59 | /* doi mapping types */ |
56 | #define CIPSO_V4_MAP_UNKNOWN 0 | 60 | #define CIPSO_V4_MAP_UNKNOWN 0 |
57 | #define CIPSO_V4_MAP_STD 1 | 61 | #define CIPSO_V4_MAP_TRANS 1 |
58 | #define CIPSO_V4_MAP_PASS 2 | 62 | #define CIPSO_V4_MAP_PASS 2 |
63 | #define CIPSO_V4_MAP_LOCAL 3 | ||
59 | 64 | ||
60 | /* limits */ | 65 | /* limits */ |
61 | #define CIPSO_V4_MAX_REM_LVLS 255 | 66 | #define CIPSO_V4_MAX_REM_LVLS 255 |
@@ -79,10 +84,9 @@ struct cipso_v4_doi { | |||
79 | } map; | 84 | } map; |
80 | u8 tags[CIPSO_V4_TAG_MAXCNT]; | 85 | u8 tags[CIPSO_V4_TAG_MAXCNT]; |
81 | 86 | ||
82 | u32 valid; | 87 | atomic_t refcount; |
83 | struct list_head list; | 88 | struct list_head list; |
84 | struct rcu_head rcu; | 89 | struct rcu_head rcu; |
85 | struct list_head dom_list; | ||
86 | }; | 90 | }; |
87 | 91 | ||
88 | /* Standard CIPSO mapping table */ | 92 | /* Standard CIPSO mapping table */ |
@@ -128,25 +132,26 @@ extern int cipso_v4_rbm_strictvalid; | |||
128 | 132 | ||
129 | #ifdef CONFIG_NETLABEL | 133 | #ifdef CONFIG_NETLABEL |
130 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); | 134 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); |
131 | int cipso_v4_doi_remove(u32 doi, | 135 | void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); |
132 | struct netlbl_audit *audit_info, | 136 | int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); |
133 | void (*callback) (struct rcu_head * head)); | ||
134 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); | 137 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); |
138 | void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def); | ||
135 | int cipso_v4_doi_walk(u32 *skip_cnt, | 139 | int cipso_v4_doi_walk(u32 *skip_cnt, |
136 | int (*callback) (struct cipso_v4_doi *doi_def, void *arg), | 140 | int (*callback) (struct cipso_v4_doi *doi_def, void *arg), |
137 | void *cb_arg); | 141 | void *cb_arg); |
138 | int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain); | ||
139 | int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, | ||
140 | const char *domain); | ||
141 | #else | 142 | #else |
142 | static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | 143 | static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) |
143 | { | 144 | { |
144 | return -ENOSYS; | 145 | return -ENOSYS; |
145 | } | 146 | } |
146 | 147 | ||
148 | static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) | ||
149 | { | ||
150 | return; | ||
151 | } | ||
152 | |||
147 | static inline int cipso_v4_doi_remove(u32 doi, | 153 | static inline int cipso_v4_doi_remove(u32 doi, |
148 | struct netlbl_audit *audit_info, | 154 | struct netlbl_audit *audit_info) |
149 | void (*callback) (struct rcu_head * head)) | ||
150 | { | 155 | { |
151 | return 0; | 156 | return 0; |
152 | } | 157 | } |
@@ -206,10 +211,15 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); | |||
206 | int cipso_v4_sock_setattr(struct sock *sk, | 211 | int cipso_v4_sock_setattr(struct sock *sk, |
207 | const struct cipso_v4_doi *doi_def, | 212 | const struct cipso_v4_doi *doi_def, |
208 | const struct netlbl_lsm_secattr *secattr); | 213 | const struct netlbl_lsm_secattr *secattr); |
214 | void cipso_v4_sock_delattr(struct sock *sk); | ||
209 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); | 215 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); |
216 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, | ||
217 | const struct cipso_v4_doi *doi_def, | ||
218 | const struct netlbl_lsm_secattr *secattr); | ||
219 | int cipso_v4_skbuff_delattr(struct sk_buff *skb); | ||
210 | int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | 220 | int cipso_v4_skbuff_getattr(const struct sk_buff *skb, |
211 | struct netlbl_lsm_secattr *secattr); | 221 | struct netlbl_lsm_secattr *secattr); |
212 | int cipso_v4_validate(unsigned char **option); | 222 | int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); |
213 | #else | 223 | #else |
214 | static inline void cipso_v4_error(struct sk_buff *skb, | 224 | static inline void cipso_v4_error(struct sk_buff *skb, |
215 | int error, | 225 | int error, |
@@ -225,19 +235,36 @@ static inline int cipso_v4_sock_setattr(struct sock *sk, | |||
225 | return -ENOSYS; | 235 | return -ENOSYS; |
226 | } | 236 | } |
227 | 237 | ||
238 | static inline void cipso_v4_sock_delattr(struct sock *sk) | ||
239 | { | ||
240 | } | ||
241 | |||
228 | static inline int cipso_v4_sock_getattr(struct sock *sk, | 242 | static inline int cipso_v4_sock_getattr(struct sock *sk, |
229 | struct netlbl_lsm_secattr *secattr) | 243 | struct netlbl_lsm_secattr *secattr) |
230 | { | 244 | { |
231 | return -ENOSYS; | 245 | return -ENOSYS; |
232 | } | 246 | } |
233 | 247 | ||
248 | static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, | ||
249 | const struct cipso_v4_doi *doi_def, | ||
250 | const struct netlbl_lsm_secattr *secattr) | ||
251 | { | ||
252 | return -ENOSYS; | ||
253 | } | ||
254 | |||
255 | static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb) | ||
256 | { | ||
257 | return -ENOSYS; | ||
258 | } | ||
259 | |||
234 | static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | 260 | static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, |
235 | struct netlbl_lsm_secattr *secattr) | 261 | struct netlbl_lsm_secattr *secattr) |
236 | { | 262 | { |
237 | return -ENOSYS; | 263 | return -ENOSYS; |
238 | } | 264 | } |
239 | 265 | ||
240 | static inline int cipso_v4_validate(unsigned char **option) | 266 | static inline int cipso_v4_validate(const struct sk_buff *skb, |
267 | unsigned char **option) | ||
241 | { | 268 | { |
242 | return -ENOSYS; | 269 | return -ENOSYS; |
243 | } | 270 | } |
diff --git a/include/net/netlabel.h b/include/net/netlabel.h index e4d2d6baa983..17c442a4514e 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h | |||
@@ -9,7 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* | 11 | /* |
12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -72,8 +72,10 @@ struct cipso_v4_doi; | |||
72 | /* NetLabel NETLINK protocol version | 72 | /* NetLabel NETLINK protocol version |
73 | * 1: initial version | 73 | * 1: initial version |
74 | * 2: added static labels for unlabeled connections | 74 | * 2: added static labels for unlabeled connections |
75 | * 3: network selectors added to the NetLabel/LSM domain mapping and the | ||
76 | * CIPSO_V4_MAP_LOCAL CIPSO mapping was added | ||
75 | */ | 77 | */ |
76 | #define NETLBL_PROTO_VERSION 2 | 78 | #define NETLBL_PROTO_VERSION 3 |
77 | 79 | ||
78 | /* NetLabel NETLINK types/families */ | 80 | /* NetLabel NETLINK types/families */ |
79 | #define NETLBL_NLTYPE_NONE 0 | 81 | #define NETLBL_NLTYPE_NONE 0 |
@@ -87,6 +89,8 @@ struct cipso_v4_doi; | |||
87 | #define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" | 89 | #define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" |
88 | #define NETLBL_NLTYPE_UNLABELED 5 | 90 | #define NETLBL_NLTYPE_UNLABELED 5 |
89 | #define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" | 91 | #define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" |
92 | #define NETLBL_NLTYPE_ADDRSELECT 6 | ||
93 | #define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL" | ||
90 | 94 | ||
91 | /* | 95 | /* |
92 | * NetLabel - Kernel API for accessing the network packet label mappings. | 96 | * NetLabel - Kernel API for accessing the network packet label mappings. |
@@ -200,7 +204,7 @@ struct netlbl_lsm_secattr { | |||
200 | u32 type; | 204 | u32 type; |
201 | char *domain; | 205 | char *domain; |
202 | struct netlbl_lsm_cache *cache; | 206 | struct netlbl_lsm_cache *cache; |
203 | union { | 207 | struct { |
204 | struct { | 208 | struct { |
205 | struct netlbl_lsm_secattr_catmap *cat; | 209 | struct netlbl_lsm_secattr_catmap *cat; |
206 | u32 lvl; | 210 | u32 lvl; |
@@ -352,12 +356,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr) | |||
352 | int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info); | 356 | int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info); |
353 | int netlbl_cfg_unlbl_add_map(const char *domain, | 357 | int netlbl_cfg_unlbl_add_map(const char *domain, |
354 | struct netlbl_audit *audit_info); | 358 | struct netlbl_audit *audit_info); |
355 | int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, | ||
356 | struct netlbl_audit *audit_info); | ||
357 | int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | 359 | int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, |
358 | const char *domain, | 360 | const char *domain, |
359 | struct netlbl_audit *audit_info); | 361 | struct netlbl_audit *audit_info); |
360 | int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info); | ||
361 | 362 | ||
362 | /* | 363 | /* |
363 | * LSM security attribute operations | 364 | * LSM security attribute operations |
@@ -380,12 +381,19 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | |||
380 | int netlbl_enabled(void); | 381 | int netlbl_enabled(void); |
381 | int netlbl_sock_setattr(struct sock *sk, | 382 | int netlbl_sock_setattr(struct sock *sk, |
382 | const struct netlbl_lsm_secattr *secattr); | 383 | const struct netlbl_lsm_secattr *secattr); |
384 | void netlbl_sock_delattr(struct sock *sk); | ||
383 | int netlbl_sock_getattr(struct sock *sk, | 385 | int netlbl_sock_getattr(struct sock *sk, |
384 | struct netlbl_lsm_secattr *secattr); | 386 | struct netlbl_lsm_secattr *secattr); |
387 | int netlbl_conn_setattr(struct sock *sk, | ||
388 | struct sockaddr *addr, | ||
389 | const struct netlbl_lsm_secattr *secattr); | ||
390 | int netlbl_skbuff_setattr(struct sk_buff *skb, | ||
391 | u16 family, | ||
392 | const struct netlbl_lsm_secattr *secattr); | ||
385 | int netlbl_skbuff_getattr(const struct sk_buff *skb, | 393 | int netlbl_skbuff_getattr(const struct sk_buff *skb, |
386 | u16 family, | 394 | u16 family, |
387 | struct netlbl_lsm_secattr *secattr); | 395 | struct netlbl_lsm_secattr *secattr); |
388 | void netlbl_skbuff_err(struct sk_buff *skb, int error); | 396 | void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway); |
389 | 397 | ||
390 | /* | 398 | /* |
391 | * LSM label mapping cache operations | 399 | * LSM label mapping cache operations |
@@ -404,22 +412,12 @@ static inline int netlbl_cfg_unlbl_add_map(const char *domain, | |||
404 | { | 412 | { |
405 | return -ENOSYS; | 413 | return -ENOSYS; |
406 | } | 414 | } |
407 | static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, | ||
408 | struct netlbl_audit *audit_info) | ||
409 | { | ||
410 | return -ENOSYS; | ||
411 | } | ||
412 | static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | 415 | static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, |
413 | const char *domain, | 416 | const char *domain, |
414 | struct netlbl_audit *audit_info) | 417 | struct netlbl_audit *audit_info) |
415 | { | 418 | { |
416 | return -ENOSYS; | 419 | return -ENOSYS; |
417 | } | 420 | } |
418 | static inline int netlbl_cfg_cipsov4_del(u32 doi, | ||
419 | struct netlbl_audit *audit_info) | ||
420 | { | ||
421 | return -ENOSYS; | ||
422 | } | ||
423 | static inline int netlbl_secattr_catmap_walk( | 421 | static inline int netlbl_secattr_catmap_walk( |
424 | struct netlbl_lsm_secattr_catmap *catmap, | 422 | struct netlbl_lsm_secattr_catmap *catmap, |
425 | u32 offset) | 423 | u32 offset) |
@@ -456,18 +454,35 @@ static inline int netlbl_sock_setattr(struct sock *sk, | |||
456 | { | 454 | { |
457 | return -ENOSYS; | 455 | return -ENOSYS; |
458 | } | 456 | } |
457 | static inline void netlbl_sock_delattr(struct sock *sk) | ||
458 | { | ||
459 | } | ||
459 | static inline int netlbl_sock_getattr(struct sock *sk, | 460 | static inline int netlbl_sock_getattr(struct sock *sk, |
460 | struct netlbl_lsm_secattr *secattr) | 461 | struct netlbl_lsm_secattr *secattr) |
461 | { | 462 | { |
462 | return -ENOSYS; | 463 | return -ENOSYS; |
463 | } | 464 | } |
465 | static inline int netlbl_conn_setattr(struct sock *sk, | ||
466 | struct sockaddr *addr, | ||
467 | const struct netlbl_lsm_secattr *secattr) | ||
468 | { | ||
469 | return -ENOSYS; | ||
470 | } | ||
471 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, | ||
472 | u16 family, | ||
473 | const struct netlbl_lsm_secattr *secattr) | ||
474 | { | ||
475 | return -ENOSYS; | ||
476 | } | ||
464 | static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, | 477 | static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, |
465 | u16 family, | 478 | u16 family, |
466 | struct netlbl_lsm_secattr *secattr) | 479 | struct netlbl_lsm_secattr *secattr) |
467 | { | 480 | { |
468 | return -ENOSYS; | 481 | return -ENOSYS; |
469 | } | 482 | } |
470 | static inline void netlbl_skbuff_err(struct sk_buff *skb, int error) | 483 | static inline void netlbl_skbuff_err(struct sk_buff *skb, |
484 | int error, | ||
485 | int gateway) | ||
471 | { | 486 | { |
472 | return; | 487 | return; |
473 | } | 488 | } |
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c1b26fcc0b5c..ca699a3017f3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -240,6 +240,7 @@ int snd_soc_dapm_sys_add(struct device *dev); | |||
240 | /* dapm audio pin control and status */ | 240 | /* dapm audio pin control and status */ |
241 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin); | 241 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin); |
242 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin); | 242 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin); |
243 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin); | ||
243 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin); | 244 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin); |
244 | int snd_soc_dapm_sync(struct snd_soc_codec *codec); | 245 | int snd_soc_dapm_sync(struct snd_soc_codec *codec); |
245 | 246 | ||
diff --git a/init/Kconfig b/init/Kconfig index c11da38837e5..8a8e2d00c40e 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -779,16 +779,6 @@ config MARKERS | |||
779 | 779 | ||
780 | source "arch/Kconfig" | 780 | source "arch/Kconfig" |
781 | 781 | ||
782 | config PROC_PAGE_MONITOR | ||
783 | default y | ||
784 | depends on PROC_FS && MMU | ||
785 | bool "Enable /proc page monitoring" if EMBEDDED | ||
786 | help | ||
787 | Various /proc files exist to monitor process memory utilization: | ||
788 | /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, | ||
789 | /proc/kpagecount, and /proc/kpageflags. Disabling these | ||
790 | interfaces will reduce the size of the kernel by approximately 4kb. | ||
791 | |||
792 | endmenu # General setup | 782 | endmenu # General setup |
793 | 783 | ||
794 | config HAVE_GENERIC_DMA_COHERENT | 784 | config HAVE_GENERIC_DMA_COHERENT |
diff --git a/kernel/acct.c b/kernel/acct.c index dd68b9059418..f6006a60df5d 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
@@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct, | |||
548 | #endif | 548 | #endif |
549 | 549 | ||
550 | spin_lock_irq(¤t->sighand->siglock); | 550 | spin_lock_irq(¤t->sighand->siglock); |
551 | tty = current->signal->tty; | 551 | tty = current->signal->tty; /* Safe as we hold the siglock */ |
552 | ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0; | 552 | ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0; |
553 | ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime))); | 553 | ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime))); |
554 | ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime))); | 554 | ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime))); |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 59cedfb040e7..cf5bc2f5f9c3 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask) | |||
246 | unsigned n; | 246 | unsigned n; |
247 | if (unlikely(!ctx)) | 247 | if (unlikely(!ctx)) |
248 | return 0; | 248 | return 0; |
249 | |||
250 | n = ctx->major; | 249 | n = ctx->major; |
250 | |||
251 | switch (audit_classify_syscall(ctx->arch, n)) { | 251 | switch (audit_classify_syscall(ctx->arch, n)) { |
252 | case 0: /* native */ | 252 | case 0: /* native */ |
253 | if ((mask & AUDIT_PERM_WRITE) && | 253 | if ((mask & AUDIT_PERM_WRITE) && |
@@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1204 | (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", | 1204 | (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", |
1205 | context->return_code); | 1205 | context->return_code); |
1206 | 1206 | ||
1207 | mutex_lock(&tty_mutex); | 1207 | spin_lock_irq(&tsk->sighand->siglock); |
1208 | read_lock(&tasklist_lock); | ||
1209 | if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) | 1208 | if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) |
1210 | tty = tsk->signal->tty->name; | 1209 | tty = tsk->signal->tty->name; |
1211 | else | 1210 | else |
1212 | tty = "(none)"; | 1211 | tty = "(none)"; |
1213 | read_unlock(&tasklist_lock); | 1212 | spin_unlock_irq(&tsk->sighand->siglock); |
1213 | |||
1214 | audit_log_format(ab, | 1214 | audit_log_format(ab, |
1215 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" | 1215 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" |
1216 | " ppid=%d pid=%d auid=%u uid=%u gid=%u" | 1216 | " ppid=%d pid=%d auid=%u uid=%u gid=%u" |
@@ -1230,7 +1230,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1230 | context->egid, context->sgid, context->fsgid, tty, | 1230 | context->egid, context->sgid, context->fsgid, tty, |
1231 | tsk->sessionid); | 1231 | tsk->sessionid); |
1232 | 1232 | ||
1233 | mutex_unlock(&tty_mutex); | ||
1234 | 1233 | ||
1235 | audit_log_task_info(ab, tsk); | 1234 | audit_log_task_info(ab, tsk); |
1236 | if (context->filterkey) { | 1235 | if (context->filterkey) { |
diff --git a/kernel/fork.c b/kernel/fork.c index 7ce2ebe84796..30de644a40c4 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
802 | 802 | ||
803 | sig->leader = 0; /* session leadership doesn't inherit */ | 803 | sig->leader = 0; /* session leadership doesn't inherit */ |
804 | sig->tty_old_pgrp = NULL; | 804 | sig->tty_old_pgrp = NULL; |
805 | sig->tty = NULL; | ||
805 | 806 | ||
806 | sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; | 807 | sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; |
807 | sig->gtime = cputime_zero; | 808 | sig->gtime = cputime_zero; |
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
838 | void __cleanup_signal(struct signal_struct *sig) | 839 | void __cleanup_signal(struct signal_struct *sig) |
839 | { | 840 | { |
840 | exit_thread_group_keys(sig); | 841 | exit_thread_group_keys(sig); |
842 | tty_kref_put(sig->tty); | ||
841 | kmem_cache_free(signal_cachep, sig); | 843 | kmem_cache_free(signal_cachep, sig); |
842 | } | 844 | } |
843 | 845 | ||
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1227 | p->nsproxy->pid_ns->child_reaper = p; | 1229 | p->nsproxy->pid_ns->child_reaper = p; |
1228 | 1230 | ||
1229 | p->signal->leader_pid = pid; | 1231 | p->signal->leader_pid = pid; |
1230 | p->signal->tty = current->signal->tty; | 1232 | tty_kref_put(p->signal->tty); |
1233 | p->signal->tty = tty_kref_get(current->signal->tty); | ||
1231 | set_task_pgrp(p, task_pgrp_nr(current)); | 1234 | set_task_pgrp(p, task_pgrp_nr(current)); |
1232 | set_task_session(p, task_session_nr(current)); | 1235 | set_task_session(p, task_session_nr(current)); |
1233 | attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); | 1236 | attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); |
diff --git a/kernel/printk.c b/kernel/printk.c index b51b1567bb55..a430fd04008b 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -1291,22 +1291,6 @@ static int __init disable_boot_consoles(void) | |||
1291 | } | 1291 | } |
1292 | late_initcall(disable_boot_consoles); | 1292 | late_initcall(disable_boot_consoles); |
1293 | 1293 | ||
1294 | /** | ||
1295 | * tty_write_message - write a message to a certain tty, not just the console. | ||
1296 | * @tty: the destination tty_struct | ||
1297 | * @msg: the message to write | ||
1298 | * | ||
1299 | * This is used for messages that need to be redirected to a specific tty. | ||
1300 | * We don't put it into the syslog queue right now maybe in the future if | ||
1301 | * really needed. | ||
1302 | */ | ||
1303 | void tty_write_message(struct tty_struct *tty, char *msg) | ||
1304 | { | ||
1305 | if (tty && tty->ops->write) | ||
1306 | tty->ops->write(tty, msg, strlen(msg)); | ||
1307 | return; | ||
1308 | } | ||
1309 | |||
1310 | #if defined CONFIG_PRINTK | 1294 | #if defined CONFIG_PRINTK |
1311 | 1295 | ||
1312 | /* | 1296 | /* |
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index bbe6b31c3c56..ad958c1ec708 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c | |||
@@ -333,12 +333,10 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) | |||
333 | unsigned long flags; | 333 | unsigned long flags; |
334 | int num_threads = 1; | 334 | int num_threads = 1; |
335 | 335 | ||
336 | rcu_read_lock(); | ||
337 | if (lock_task_sighand(p, &flags)) { | 336 | if (lock_task_sighand(p, &flags)) { |
338 | num_threads = atomic_read(&p->signal->count); | 337 | num_threads = atomic_read(&p->signal->count); |
339 | unlock_task_sighand(p, &flags); | 338 | unlock_task_sighand(p, &flags); |
340 | } | 339 | } |
341 | rcu_read_unlock(); | ||
342 | 340 | ||
343 | SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads); | 341 | SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads); |
344 | SEQ_printf(m, | 342 | SEQ_printf(m, |
diff --git a/kernel/sys.c b/kernel/sys.c index 038a7bc0901d..234d9454294e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void) | |||
1060 | group_leader->signal->leader = 1; | 1060 | group_leader->signal->leader = 1; |
1061 | __set_special_pids(sid); | 1061 | __set_special_pids(sid); |
1062 | 1062 | ||
1063 | spin_lock(&group_leader->sighand->siglock); | 1063 | proc_clear_tty(group_leader); |
1064 | group_leader->signal->tty = NULL; | ||
1065 | spin_unlock(&group_leader->sighand->siglock); | ||
1066 | 1064 | ||
1067 | err = session; | 1065 | err = session; |
1068 | out: | 1066 | out: |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 1bf369bd4423..c468c3c6dfc5 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -80,7 +80,6 @@ extern int pid_max_min, pid_max_max; | |||
80 | extern int sysctl_drop_caches; | 80 | extern int sysctl_drop_caches; |
81 | extern int percpu_pagelist_fraction; | 81 | extern int percpu_pagelist_fraction; |
82 | extern int compat_log; | 82 | extern int compat_log; |
83 | extern int maps_protect; | ||
84 | extern int latencytop_enabled; | 83 | extern int latencytop_enabled; |
85 | extern int sysctl_nr_open_min, sysctl_nr_open_max; | 84 | extern int sysctl_nr_open_min, sysctl_nr_open_max; |
86 | #ifdef CONFIG_RCU_TORTURE_TEST | 85 | #ifdef CONFIG_RCU_TORTURE_TEST |
@@ -808,16 +807,6 @@ static struct ctl_table kern_table[] = { | |||
808 | .proc_handler = &proc_dointvec, | 807 | .proc_handler = &proc_dointvec, |
809 | }, | 808 | }, |
810 | #endif | 809 | #endif |
811 | #ifdef CONFIG_PROC_FS | ||
812 | { | ||
813 | .ctl_name = CTL_UNNUMBERED, | ||
814 | .procname = "maps_protect", | ||
815 | .data = &maps_protect, | ||
816 | .maxlen = sizeof(int), | ||
817 | .mode = 0644, | ||
818 | .proc_handler = &proc_dointvec, | ||
819 | }, | ||
820 | #endif | ||
821 | { | 810 | { |
822 | .ctl_name = CTL_UNNUMBERED, | 811 | .ctl_name = CTL_UNNUMBERED, |
823 | .procname = "poweroff_cmd", | 812 | .procname = "poweroff_cmd", |
diff --git a/mm/shmem.c b/mm/shmem.c index 04fb4f1ab88e..bf66d0191baf 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -50,14 +50,12 @@ | |||
50 | #include <linux/migrate.h> | 50 | #include <linux/migrate.h> |
51 | #include <linux/highmem.h> | 51 | #include <linux/highmem.h> |
52 | #include <linux/seq_file.h> | 52 | #include <linux/seq_file.h> |
53 | #include <linux/magic.h> | ||
53 | 54 | ||
54 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
55 | #include <asm/div64.h> | 56 | #include <asm/div64.h> |
56 | #include <asm/pgtable.h> | 57 | #include <asm/pgtable.h> |
57 | 58 | ||
58 | /* This magic number is used in glibc for posix shared memory */ | ||
59 | #define TMPFS_MAGIC 0x01021994 | ||
60 | |||
61 | #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) | 59 | #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) |
62 | #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) | 60 | #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) |
63 | #define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) | 61 | #define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 2c0e4572cc90..490e035c6d90 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* | 15 | /* |
16 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 16 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
17 | * | 17 | * |
18 | * This program is free software; you can redistribute it and/or modify | 18 | * This program is free software; you can redistribute it and/or modify |
19 | * it under the terms of the GNU General Public License as published by | 19 | * it under the terms of the GNU General Public License as published by |
@@ -47,17 +47,7 @@ | |||
47 | #include <asm/bug.h> | 47 | #include <asm/bug.h> |
48 | #include <asm/unaligned.h> | 48 | #include <asm/unaligned.h> |
49 | 49 | ||
50 | struct cipso_v4_domhsh_entry { | ||
51 | char *domain; | ||
52 | u32 valid; | ||
53 | struct list_head list; | ||
54 | struct rcu_head rcu; | ||
55 | }; | ||
56 | |||
57 | /* List of available DOI definitions */ | 50 | /* List of available DOI definitions */ |
58 | /* XXX - Updates should be minimal so having a single lock for the | ||
59 | * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be | ||
60 | * okay. */ | ||
61 | /* XXX - This currently assumes a minimal number of different DOIs in use, | 51 | /* XXX - This currently assumes a minimal number of different DOIs in use, |
62 | * if in practice there are a lot of different DOIs this list should | 52 | * if in practice there are a lot of different DOIs this list should |
63 | * probably be turned into a hash table or something similar so we | 53 | * probably be turned into a hash table or something similar so we |
@@ -119,6 +109,19 @@ int cipso_v4_rbm_strictvalid = 1; | |||
119 | * be omitted. */ | 109 | * be omitted. */ |
120 | #define CIPSO_V4_TAG_RNG_CAT_MAX 8 | 110 | #define CIPSO_V4_TAG_RNG_CAT_MAX 8 |
121 | 111 | ||
112 | /* Base length of the local tag (non-standard tag). | ||
113 | * Tag definition (may change between kernel versions) | ||
114 | * | ||
115 | * 0 8 16 24 32 | ||
116 | * +----------+----------+----------+----------+ | ||
117 | * | 10000000 | 00000110 | 32-bit secid value | | ||
118 | * +----------+----------+----------+----------+ | ||
119 | * | in (host byte order)| | ||
120 | * +----------+----------+ | ||
121 | * | ||
122 | */ | ||
123 | #define CIPSO_V4_TAG_LOC_BLEN 6 | ||
124 | |||
122 | /* | 125 | /* |
123 | * Helper Functions | 126 | * Helper Functions |
124 | */ | 127 | */ |
@@ -194,25 +197,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap, | |||
194 | } | 197 | } |
195 | 198 | ||
196 | /** | 199 | /** |
197 | * cipso_v4_doi_domhsh_free - Frees a domain list entry | ||
198 | * @entry: the entry's RCU field | ||
199 | * | ||
200 | * Description: | ||
201 | * This function is designed to be used as a callback to the call_rcu() | ||
202 | * function so that the memory allocated to a domain list entry can be released | ||
203 | * safely. | ||
204 | * | ||
205 | */ | ||
206 | static void cipso_v4_doi_domhsh_free(struct rcu_head *entry) | ||
207 | { | ||
208 | struct cipso_v4_domhsh_entry *ptr; | ||
209 | |||
210 | ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu); | ||
211 | kfree(ptr->domain); | ||
212 | kfree(ptr); | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * cipso_v4_cache_entry_free - Frees a cache entry | 200 | * cipso_v4_cache_entry_free - Frees a cache entry |
217 | * @entry: the entry to free | 201 | * @entry: the entry to free |
218 | * | 202 | * |
@@ -457,7 +441,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) | |||
457 | struct cipso_v4_doi *iter; | 441 | struct cipso_v4_doi *iter; |
458 | 442 | ||
459 | list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) | 443 | list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) |
460 | if (iter->doi == doi && iter->valid) | 444 | if (iter->doi == doi && atomic_read(&iter->refcount)) |
461 | return iter; | 445 | return iter; |
462 | return NULL; | 446 | return NULL; |
463 | } | 447 | } |
@@ -496,14 +480,17 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | |||
496 | if (doi_def->type != CIPSO_V4_MAP_PASS) | 480 | if (doi_def->type != CIPSO_V4_MAP_PASS) |
497 | return -EINVAL; | 481 | return -EINVAL; |
498 | break; | 482 | break; |
483 | case CIPSO_V4_TAG_LOCAL: | ||
484 | if (doi_def->type != CIPSO_V4_MAP_LOCAL) | ||
485 | return -EINVAL; | ||
486 | break; | ||
499 | default: | 487 | default: |
500 | return -EINVAL; | 488 | return -EINVAL; |
501 | } | 489 | } |
502 | } | 490 | } |
503 | 491 | ||
504 | doi_def->valid = 1; | 492 | atomic_set(&doi_def->refcount, 1); |
505 | INIT_RCU_HEAD(&doi_def->rcu); | 493 | INIT_RCU_HEAD(&doi_def->rcu); |
506 | INIT_LIST_HEAD(&doi_def->dom_list); | ||
507 | 494 | ||
508 | spin_lock(&cipso_v4_doi_list_lock); | 495 | spin_lock(&cipso_v4_doi_list_lock); |
509 | if (cipso_v4_doi_search(doi_def->doi) != NULL) | 496 | if (cipso_v4_doi_search(doi_def->doi) != NULL) |
@@ -519,59 +506,129 @@ doi_add_failure: | |||
519 | } | 506 | } |
520 | 507 | ||
521 | /** | 508 | /** |
509 | * cipso_v4_doi_free - Frees a DOI definition | ||
510 | * @entry: the entry's RCU field | ||
511 | * | ||
512 | * Description: | ||
513 | * This function frees all of the memory associated with a DOI definition. | ||
514 | * | ||
515 | */ | ||
516 | void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) | ||
517 | { | ||
518 | if (doi_def == NULL) | ||
519 | return; | ||
520 | |||
521 | switch (doi_def->type) { | ||
522 | case CIPSO_V4_MAP_TRANS: | ||
523 | kfree(doi_def->map.std->lvl.cipso); | ||
524 | kfree(doi_def->map.std->lvl.local); | ||
525 | kfree(doi_def->map.std->cat.cipso); | ||
526 | kfree(doi_def->map.std->cat.local); | ||
527 | break; | ||
528 | } | ||
529 | kfree(doi_def); | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer | ||
534 | * @entry: the entry's RCU field | ||
535 | * | ||
536 | * Description: | ||
537 | * This function is designed to be used as a callback to the call_rcu() | ||
538 | * function so that the memory allocated to the DOI definition can be released | ||
539 | * safely. | ||
540 | * | ||
541 | */ | ||
542 | static void cipso_v4_doi_free_rcu(struct rcu_head *entry) | ||
543 | { | ||
544 | struct cipso_v4_doi *doi_def; | ||
545 | |||
546 | doi_def = container_of(entry, struct cipso_v4_doi, rcu); | ||
547 | cipso_v4_doi_free(doi_def); | ||
548 | } | ||
549 | |||
550 | /** | ||
522 | * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine | 551 | * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine |
523 | * @doi: the DOI value | 552 | * @doi: the DOI value |
524 | * @audit_secid: the LSM secid to use in the audit message | 553 | * @audit_secid: the LSM secid to use in the audit message |
525 | * @callback: the DOI cleanup/free callback | ||
526 | * | 554 | * |
527 | * Description: | 555 | * Description: |
528 | * Removes a DOI definition from the CIPSO engine, @callback is called to | 556 | * Removes a DOI definition from the CIPSO engine. The NetLabel routines will |
529 | * free any memory. The NetLabel routines will be called to release their own | 557 | * be called to release their own LSM domain mappings as well as our own |
530 | * LSM domain mappings as well as our own domain list. Returns zero on | 558 | * domain list. Returns zero on success and negative values on failure. |
531 | * success and negative values on failure. | ||
532 | * | 559 | * |
533 | */ | 560 | */ |
534 | int cipso_v4_doi_remove(u32 doi, | 561 | int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) |
535 | struct netlbl_audit *audit_info, | ||
536 | void (*callback) (struct rcu_head * head)) | ||
537 | { | 562 | { |
538 | struct cipso_v4_doi *doi_def; | 563 | struct cipso_v4_doi *doi_def; |
539 | struct cipso_v4_domhsh_entry *dom_iter; | ||
540 | 564 | ||
541 | spin_lock(&cipso_v4_doi_list_lock); | 565 | spin_lock(&cipso_v4_doi_list_lock); |
542 | doi_def = cipso_v4_doi_search(doi); | 566 | doi_def = cipso_v4_doi_search(doi); |
543 | if (doi_def != NULL) { | 567 | if (doi_def == NULL) { |
544 | doi_def->valid = 0; | ||
545 | list_del_rcu(&doi_def->list); | ||
546 | spin_unlock(&cipso_v4_doi_list_lock); | 568 | spin_unlock(&cipso_v4_doi_list_lock); |
547 | rcu_read_lock(); | 569 | return -ENOENT; |
548 | list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) | 570 | } |
549 | if (dom_iter->valid) | 571 | if (!atomic_dec_and_test(&doi_def->refcount)) { |
550 | netlbl_cfg_map_del(dom_iter->domain, | 572 | spin_unlock(&cipso_v4_doi_list_lock); |
551 | audit_info); | 573 | return -EBUSY; |
552 | rcu_read_unlock(); | ||
553 | cipso_v4_cache_invalidate(); | ||
554 | call_rcu(&doi_def->rcu, callback); | ||
555 | return 0; | ||
556 | } | 574 | } |
575 | list_del_rcu(&doi_def->list); | ||
557 | spin_unlock(&cipso_v4_doi_list_lock); | 576 | spin_unlock(&cipso_v4_doi_list_lock); |
558 | 577 | ||
559 | return -ENOENT; | 578 | cipso_v4_cache_invalidate(); |
579 | call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); | ||
580 | |||
581 | return 0; | ||
560 | } | 582 | } |
561 | 583 | ||
562 | /** | 584 | /** |
563 | * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition | 585 | * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition |
564 | * @doi: the DOI value | 586 | * @doi: the DOI value |
565 | * | 587 | * |
566 | * Description: | 588 | * Description: |
567 | * Searches for a valid DOI definition and if one is found it is returned to | 589 | * Searches for a valid DOI definition and if one is found it is returned to |
568 | * the caller. Otherwise NULL is returned. The caller must ensure that | 590 | * the caller. Otherwise NULL is returned. The caller must ensure that |
569 | * rcu_read_lock() is held while accessing the returned definition. | 591 | * rcu_read_lock() is held while accessing the returned definition and the DOI |
592 | * definition reference count is decremented when the caller is done. | ||
570 | * | 593 | * |
571 | */ | 594 | */ |
572 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) | 595 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) |
573 | { | 596 | { |
574 | return cipso_v4_doi_search(doi); | 597 | struct cipso_v4_doi *doi_def; |
598 | |||
599 | rcu_read_lock(); | ||
600 | doi_def = cipso_v4_doi_search(doi); | ||
601 | if (doi_def == NULL) | ||
602 | goto doi_getdef_return; | ||
603 | if (!atomic_inc_not_zero(&doi_def->refcount)) | ||
604 | doi_def = NULL; | ||
605 | |||
606 | doi_getdef_return: | ||
607 | rcu_read_unlock(); | ||
608 | return doi_def; | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * cipso_v4_doi_putdef - Releases a reference for the given DOI definition | ||
613 | * @doi_def: the DOI definition | ||
614 | * | ||
615 | * Description: | ||
616 | * Releases a DOI definition reference obtained from cipso_v4_doi_getdef(). | ||
617 | * | ||
618 | */ | ||
619 | void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def) | ||
620 | { | ||
621 | if (doi_def == NULL) | ||
622 | return; | ||
623 | |||
624 | if (!atomic_dec_and_test(&doi_def->refcount)) | ||
625 | return; | ||
626 | spin_lock(&cipso_v4_doi_list_lock); | ||
627 | list_del_rcu(&doi_def->list); | ||
628 | spin_unlock(&cipso_v4_doi_list_lock); | ||
629 | |||
630 | cipso_v4_cache_invalidate(); | ||
631 | call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); | ||
575 | } | 632 | } |
576 | 633 | ||
577 | /** | 634 | /** |
@@ -597,7 +654,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt, | |||
597 | 654 | ||
598 | rcu_read_lock(); | 655 | rcu_read_lock(); |
599 | list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) | 656 | list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) |
600 | if (iter_doi->valid) { | 657 | if (atomic_read(&iter_doi->refcount) > 0) { |
601 | if (doi_cnt++ < *skip_cnt) | 658 | if (doi_cnt++ < *skip_cnt) |
602 | continue; | 659 | continue; |
603 | ret_val = callback(iter_doi, cb_arg); | 660 | ret_val = callback(iter_doi, cb_arg); |
@@ -613,85 +670,6 @@ doi_walk_return: | |||
613 | return ret_val; | 670 | return ret_val; |
614 | } | 671 | } |
615 | 672 | ||
616 | /** | ||
617 | * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition | ||
618 | * @doi_def: the DOI definition | ||
619 | * @domain: the domain to add | ||
620 | * | ||
621 | * Description: | ||
622 | * Adds the @domain to the DOI specified by @doi_def, this function | ||
623 | * should only be called by external functions (i.e. NetLabel). This function | ||
624 | * does allocate memory. Returns zero on success, negative values on failure. | ||
625 | * | ||
626 | */ | ||
627 | int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain) | ||
628 | { | ||
629 | struct cipso_v4_domhsh_entry *iter; | ||
630 | struct cipso_v4_domhsh_entry *new_dom; | ||
631 | |||
632 | new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL); | ||
633 | if (new_dom == NULL) | ||
634 | return -ENOMEM; | ||
635 | if (domain) { | ||
636 | new_dom->domain = kstrdup(domain, GFP_KERNEL); | ||
637 | if (new_dom->domain == NULL) { | ||
638 | kfree(new_dom); | ||
639 | return -ENOMEM; | ||
640 | } | ||
641 | } | ||
642 | new_dom->valid = 1; | ||
643 | INIT_RCU_HEAD(&new_dom->rcu); | ||
644 | |||
645 | spin_lock(&cipso_v4_doi_list_lock); | ||
646 | list_for_each_entry(iter, &doi_def->dom_list, list) | ||
647 | if (iter->valid && | ||
648 | ((domain != NULL && iter->domain != NULL && | ||
649 | strcmp(iter->domain, domain) == 0) || | ||
650 | (domain == NULL && iter->domain == NULL))) { | ||
651 | spin_unlock(&cipso_v4_doi_list_lock); | ||
652 | kfree(new_dom->domain); | ||
653 | kfree(new_dom); | ||
654 | return -EEXIST; | ||
655 | } | ||
656 | list_add_tail_rcu(&new_dom->list, &doi_def->dom_list); | ||
657 | spin_unlock(&cipso_v4_doi_list_lock); | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /** | ||
663 | * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition | ||
664 | * @doi_def: the DOI definition | ||
665 | * @domain: the domain to remove | ||
666 | * | ||
667 | * Description: | ||
668 | * Removes the @domain from the DOI specified by @doi_def, this function | ||
669 | * should only be called by external functions (i.e. NetLabel). Returns zero | ||
670 | * on success and negative values on error. | ||
671 | * | ||
672 | */ | ||
673 | int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, | ||
674 | const char *domain) | ||
675 | { | ||
676 | struct cipso_v4_domhsh_entry *iter; | ||
677 | |||
678 | spin_lock(&cipso_v4_doi_list_lock); | ||
679 | list_for_each_entry(iter, &doi_def->dom_list, list) | ||
680 | if (iter->valid && | ||
681 | ((domain != NULL && iter->domain != NULL && | ||
682 | strcmp(iter->domain, domain) == 0) || | ||
683 | (domain == NULL && iter->domain == NULL))) { | ||
684 | iter->valid = 0; | ||
685 | list_del_rcu(&iter->list); | ||
686 | spin_unlock(&cipso_v4_doi_list_lock); | ||
687 | call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free); | ||
688 | return 0; | ||
689 | } | ||
690 | spin_unlock(&cipso_v4_doi_list_lock); | ||
691 | |||
692 | return -ENOENT; | ||
693 | } | ||
694 | |||
695 | /* | 673 | /* |
696 | * Label Mapping Functions | 674 | * Label Mapping Functions |
697 | */ | 675 | */ |
@@ -712,7 +690,7 @@ static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level) | |||
712 | switch (doi_def->type) { | 690 | switch (doi_def->type) { |
713 | case CIPSO_V4_MAP_PASS: | 691 | case CIPSO_V4_MAP_PASS: |
714 | return 0; | 692 | return 0; |
715 | case CIPSO_V4_MAP_STD: | 693 | case CIPSO_V4_MAP_TRANS: |
716 | if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) | 694 | if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) |
717 | return 0; | 695 | return 0; |
718 | break; | 696 | break; |
@@ -741,7 +719,7 @@ static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def, | |||
741 | case CIPSO_V4_MAP_PASS: | 719 | case CIPSO_V4_MAP_PASS: |
742 | *net_lvl = host_lvl; | 720 | *net_lvl = host_lvl; |
743 | return 0; | 721 | return 0; |
744 | case CIPSO_V4_MAP_STD: | 722 | case CIPSO_V4_MAP_TRANS: |
745 | if (host_lvl < doi_def->map.std->lvl.local_size && | 723 | if (host_lvl < doi_def->map.std->lvl.local_size && |
746 | doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) { | 724 | doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) { |
747 | *net_lvl = doi_def->map.std->lvl.local[host_lvl]; | 725 | *net_lvl = doi_def->map.std->lvl.local[host_lvl]; |
@@ -775,7 +753,7 @@ static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def, | |||
775 | case CIPSO_V4_MAP_PASS: | 753 | case CIPSO_V4_MAP_PASS: |
776 | *host_lvl = net_lvl; | 754 | *host_lvl = net_lvl; |
777 | return 0; | 755 | return 0; |
778 | case CIPSO_V4_MAP_STD: | 756 | case CIPSO_V4_MAP_TRANS: |
779 | map_tbl = doi_def->map.std; | 757 | map_tbl = doi_def->map.std; |
780 | if (net_lvl < map_tbl->lvl.cipso_size && | 758 | if (net_lvl < map_tbl->lvl.cipso_size && |
781 | map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { | 759 | map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { |
@@ -812,7 +790,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, | |||
812 | switch (doi_def->type) { | 790 | switch (doi_def->type) { |
813 | case CIPSO_V4_MAP_PASS: | 791 | case CIPSO_V4_MAP_PASS: |
814 | return 0; | 792 | return 0; |
815 | case CIPSO_V4_MAP_STD: | 793 | case CIPSO_V4_MAP_TRANS: |
816 | cipso_cat_size = doi_def->map.std->cat.cipso_size; | 794 | cipso_cat_size = doi_def->map.std->cat.cipso_size; |
817 | cipso_array = doi_def->map.std->cat.cipso; | 795 | cipso_array = doi_def->map.std->cat.cipso; |
818 | for (;;) { | 796 | for (;;) { |
@@ -860,7 +838,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | |||
860 | u32 host_cat_size = 0; | 838 | u32 host_cat_size = 0; |
861 | u32 *host_cat_array = NULL; | 839 | u32 *host_cat_array = NULL; |
862 | 840 | ||
863 | if (doi_def->type == CIPSO_V4_MAP_STD) { | 841 | if (doi_def->type == CIPSO_V4_MAP_TRANS) { |
864 | host_cat_size = doi_def->map.std->cat.local_size; | 842 | host_cat_size = doi_def->map.std->cat.local_size; |
865 | host_cat_array = doi_def->map.std->cat.local; | 843 | host_cat_array = doi_def->map.std->cat.local; |
866 | } | 844 | } |
@@ -875,7 +853,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | |||
875 | case CIPSO_V4_MAP_PASS: | 853 | case CIPSO_V4_MAP_PASS: |
876 | net_spot = host_spot; | 854 | net_spot = host_spot; |
877 | break; | 855 | break; |
878 | case CIPSO_V4_MAP_STD: | 856 | case CIPSO_V4_MAP_TRANS: |
879 | if (host_spot >= host_cat_size) | 857 | if (host_spot >= host_cat_size) |
880 | return -EPERM; | 858 | return -EPERM; |
881 | net_spot = host_cat_array[host_spot]; | 859 | net_spot = host_cat_array[host_spot]; |
@@ -921,7 +899,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, | |||
921 | u32 net_cat_size = 0; | 899 | u32 net_cat_size = 0; |
922 | u32 *net_cat_array = NULL; | 900 | u32 *net_cat_array = NULL; |
923 | 901 | ||
924 | if (doi_def->type == CIPSO_V4_MAP_STD) { | 902 | if (doi_def->type == CIPSO_V4_MAP_TRANS) { |
925 | net_cat_size = doi_def->map.std->cat.cipso_size; | 903 | net_cat_size = doi_def->map.std->cat.cipso_size; |
926 | net_cat_array = doi_def->map.std->cat.cipso; | 904 | net_cat_array = doi_def->map.std->cat.cipso; |
927 | } | 905 | } |
@@ -941,7 +919,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, | |||
941 | case CIPSO_V4_MAP_PASS: | 919 | case CIPSO_V4_MAP_PASS: |
942 | host_spot = net_spot; | 920 | host_spot = net_spot; |
943 | break; | 921 | break; |
944 | case CIPSO_V4_MAP_STD: | 922 | case CIPSO_V4_MAP_TRANS: |
945 | if (net_spot >= net_cat_size) | 923 | if (net_spot >= net_cat_size) |
946 | return -EPERM; | 924 | return -EPERM; |
947 | host_spot = net_cat_array[net_spot]; | 925 | host_spot = net_cat_array[net_spot]; |
@@ -1277,7 +1255,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, | |||
1277 | } else | 1255 | } else |
1278 | tag_len = 4; | 1256 | tag_len = 4; |
1279 | 1257 | ||
1280 | buffer[0] = 0x01; | 1258 | buffer[0] = CIPSO_V4_TAG_RBITMAP; |
1281 | buffer[1] = tag_len; | 1259 | buffer[1] = tag_len; |
1282 | buffer[3] = level; | 1260 | buffer[3] = level; |
1283 | 1261 | ||
@@ -1373,7 +1351,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, | |||
1373 | } else | 1351 | } else |
1374 | tag_len = 4; | 1352 | tag_len = 4; |
1375 | 1353 | ||
1376 | buffer[0] = 0x02; | 1354 | buffer[0] = CIPSO_V4_TAG_ENUM; |
1377 | buffer[1] = tag_len; | 1355 | buffer[1] = tag_len; |
1378 | buffer[3] = level; | 1356 | buffer[3] = level; |
1379 | 1357 | ||
@@ -1469,7 +1447,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, | |||
1469 | } else | 1447 | } else |
1470 | tag_len = 4; | 1448 | tag_len = 4; |
1471 | 1449 | ||
1472 | buffer[0] = 0x05; | 1450 | buffer[0] = CIPSO_V4_TAG_RANGE; |
1473 | buffer[1] = tag_len; | 1451 | buffer[1] = tag_len; |
1474 | buffer[3] = level; | 1452 | buffer[3] = level; |
1475 | 1453 | ||
@@ -1523,6 +1501,54 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, | |||
1523 | } | 1501 | } |
1524 | 1502 | ||
1525 | /** | 1503 | /** |
1504 | * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard) | ||
1505 | * @doi_def: the DOI definition | ||
1506 | * @secattr: the security attributes | ||
1507 | * @buffer: the option buffer | ||
1508 | * @buffer_len: length of buffer in bytes | ||
1509 | * | ||
1510 | * Description: | ||
1511 | * Generate a CIPSO option using the local tag. Returns the size of the tag | ||
1512 | * on success, negative values on failure. | ||
1513 | * | ||
1514 | */ | ||
1515 | static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def, | ||
1516 | const struct netlbl_lsm_secattr *secattr, | ||
1517 | unsigned char *buffer, | ||
1518 | u32 buffer_len) | ||
1519 | { | ||
1520 | if (!(secattr->flags & NETLBL_SECATTR_SECID)) | ||
1521 | return -EPERM; | ||
1522 | |||
1523 | buffer[0] = CIPSO_V4_TAG_LOCAL; | ||
1524 | buffer[1] = CIPSO_V4_TAG_LOC_BLEN; | ||
1525 | *(u32 *)&buffer[2] = secattr->attr.secid; | ||
1526 | |||
1527 | return CIPSO_V4_TAG_LOC_BLEN; | ||
1528 | } | ||
1529 | |||
1530 | /** | ||
1531 | * cipso_v4_parsetag_loc - Parse a CIPSO local tag | ||
1532 | * @doi_def: the DOI definition | ||
1533 | * @tag: the CIPSO tag | ||
1534 | * @secattr: the security attributes | ||
1535 | * | ||
1536 | * Description: | ||
1537 | * Parse a CIPSO local tag and return the security attributes in @secattr. | ||
1538 | * Return zero on success, negatives values on failure. | ||
1539 | * | ||
1540 | */ | ||
1541 | static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def, | ||
1542 | const unsigned char *tag, | ||
1543 | struct netlbl_lsm_secattr *secattr) | ||
1544 | { | ||
1545 | secattr->attr.secid = *(u32 *)&tag[2]; | ||
1546 | secattr->flags |= NETLBL_SECATTR_SECID; | ||
1547 | |||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | /** | ||
1526 | * cipso_v4_validate - Validate a CIPSO option | 1552 | * cipso_v4_validate - Validate a CIPSO option |
1527 | * @option: the start of the option, on error it is set to point to the error | 1553 | * @option: the start of the option, on error it is set to point to the error |
1528 | * | 1554 | * |
@@ -1541,7 +1567,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, | |||
1541 | * that is unrecognized." | 1567 | * that is unrecognized." |
1542 | * | 1568 | * |
1543 | */ | 1569 | */ |
1544 | int cipso_v4_validate(unsigned char **option) | 1570 | int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) |
1545 | { | 1571 | { |
1546 | unsigned char *opt = *option; | 1572 | unsigned char *opt = *option; |
1547 | unsigned char *tag; | 1573 | unsigned char *tag; |
@@ -1566,7 +1592,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1566 | goto validate_return_locked; | 1592 | goto validate_return_locked; |
1567 | } | 1593 | } |
1568 | 1594 | ||
1569 | opt_iter = 6; | 1595 | opt_iter = CIPSO_V4_HDR_LEN; |
1570 | tag = opt + opt_iter; | 1596 | tag = opt + opt_iter; |
1571 | while (opt_iter < opt_len) { | 1597 | while (opt_iter < opt_len) { |
1572 | for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) | 1598 | for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) |
@@ -1584,7 +1610,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1584 | 1610 | ||
1585 | switch (tag[0]) { | 1611 | switch (tag[0]) { |
1586 | case CIPSO_V4_TAG_RBITMAP: | 1612 | case CIPSO_V4_TAG_RBITMAP: |
1587 | if (tag_len < 4) { | 1613 | if (tag_len < CIPSO_V4_TAG_RBM_BLEN) { |
1588 | err_offset = opt_iter + 1; | 1614 | err_offset = opt_iter + 1; |
1589 | goto validate_return_locked; | 1615 | goto validate_return_locked; |
1590 | } | 1616 | } |
@@ -1602,7 +1628,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1602 | err_offset = opt_iter + 3; | 1628 | err_offset = opt_iter + 3; |
1603 | goto validate_return_locked; | 1629 | goto validate_return_locked; |
1604 | } | 1630 | } |
1605 | if (tag_len > 4 && | 1631 | if (tag_len > CIPSO_V4_TAG_RBM_BLEN && |
1606 | cipso_v4_map_cat_rbm_valid(doi_def, | 1632 | cipso_v4_map_cat_rbm_valid(doi_def, |
1607 | &tag[4], | 1633 | &tag[4], |
1608 | tag_len - 4) < 0) { | 1634 | tag_len - 4) < 0) { |
@@ -1612,7 +1638,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1612 | } | 1638 | } |
1613 | break; | 1639 | break; |
1614 | case CIPSO_V4_TAG_ENUM: | 1640 | case CIPSO_V4_TAG_ENUM: |
1615 | if (tag_len < 4) { | 1641 | if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) { |
1616 | err_offset = opt_iter + 1; | 1642 | err_offset = opt_iter + 1; |
1617 | goto validate_return_locked; | 1643 | goto validate_return_locked; |
1618 | } | 1644 | } |
@@ -1622,7 +1648,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1622 | err_offset = opt_iter + 3; | 1648 | err_offset = opt_iter + 3; |
1623 | goto validate_return_locked; | 1649 | goto validate_return_locked; |
1624 | } | 1650 | } |
1625 | if (tag_len > 4 && | 1651 | if (tag_len > CIPSO_V4_TAG_ENUM_BLEN && |
1626 | cipso_v4_map_cat_enum_valid(doi_def, | 1652 | cipso_v4_map_cat_enum_valid(doi_def, |
1627 | &tag[4], | 1653 | &tag[4], |
1628 | tag_len - 4) < 0) { | 1654 | tag_len - 4) < 0) { |
@@ -1631,7 +1657,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1631 | } | 1657 | } |
1632 | break; | 1658 | break; |
1633 | case CIPSO_V4_TAG_RANGE: | 1659 | case CIPSO_V4_TAG_RANGE: |
1634 | if (tag_len < 4) { | 1660 | if (tag_len < CIPSO_V4_TAG_RNG_BLEN) { |
1635 | err_offset = opt_iter + 1; | 1661 | err_offset = opt_iter + 1; |
1636 | goto validate_return_locked; | 1662 | goto validate_return_locked; |
1637 | } | 1663 | } |
@@ -1641,7 +1667,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1641 | err_offset = opt_iter + 3; | 1667 | err_offset = opt_iter + 3; |
1642 | goto validate_return_locked; | 1668 | goto validate_return_locked; |
1643 | } | 1669 | } |
1644 | if (tag_len > 4 && | 1670 | if (tag_len > CIPSO_V4_TAG_RNG_BLEN && |
1645 | cipso_v4_map_cat_rng_valid(doi_def, | 1671 | cipso_v4_map_cat_rng_valid(doi_def, |
1646 | &tag[4], | 1672 | &tag[4], |
1647 | tag_len - 4) < 0) { | 1673 | tag_len - 4) < 0) { |
@@ -1649,6 +1675,19 @@ int cipso_v4_validate(unsigned char **option) | |||
1649 | goto validate_return_locked; | 1675 | goto validate_return_locked; |
1650 | } | 1676 | } |
1651 | break; | 1677 | break; |
1678 | case CIPSO_V4_TAG_LOCAL: | ||
1679 | /* This is a non-standard tag that we only allow for | ||
1680 | * local connections, so if the incoming interface is | ||
1681 | * not the loopback device drop the packet. */ | ||
1682 | if (!(skb->dev->flags & IFF_LOOPBACK)) { | ||
1683 | err_offset = opt_iter; | ||
1684 | goto validate_return_locked; | ||
1685 | } | ||
1686 | if (tag_len != CIPSO_V4_TAG_LOC_BLEN) { | ||
1687 | err_offset = opt_iter + 1; | ||
1688 | goto validate_return_locked; | ||
1689 | } | ||
1690 | break; | ||
1652 | default: | 1691 | default: |
1653 | err_offset = opt_iter; | 1692 | err_offset = opt_iter; |
1654 | goto validate_return_locked; | 1693 | goto validate_return_locked; |
@@ -1704,48 +1743,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) | |||
1704 | } | 1743 | } |
1705 | 1744 | ||
1706 | /** | 1745 | /** |
1707 | * cipso_v4_sock_setattr - Add a CIPSO option to a socket | 1746 | * cipso_v4_genopt - Generate a CIPSO option |
1708 | * @sk: the socket | 1747 | * @buf: the option buffer |
1748 | * @buf_len: the size of opt_buf | ||
1709 | * @doi_def: the CIPSO DOI to use | 1749 | * @doi_def: the CIPSO DOI to use |
1710 | * @secattr: the specific security attributes of the socket | 1750 | * @secattr: the security attributes |
1711 | * | 1751 | * |
1712 | * Description: | 1752 | * Description: |
1713 | * Set the CIPSO option on the given socket using the DOI definition and | 1753 | * Generate a CIPSO option using the DOI definition and security attributes |
1714 | * security attributes passed to the function. This function requires | 1754 | * passed to the function. Returns the length of the option on success and |
1715 | * exclusive access to @sk, which means it either needs to be in the | 1755 | * negative values on failure. |
1716 | * process of being created or locked. Returns zero on success and negative | ||
1717 | * values on failure. | ||
1718 | * | 1756 | * |
1719 | */ | 1757 | */ |
1720 | int cipso_v4_sock_setattr(struct sock *sk, | 1758 | static int cipso_v4_genopt(unsigned char *buf, u32 buf_len, |
1721 | const struct cipso_v4_doi *doi_def, | 1759 | const struct cipso_v4_doi *doi_def, |
1722 | const struct netlbl_lsm_secattr *secattr) | 1760 | const struct netlbl_lsm_secattr *secattr) |
1723 | { | 1761 | { |
1724 | int ret_val = -EPERM; | 1762 | int ret_val; |
1725 | u32 iter; | 1763 | u32 iter; |
1726 | unsigned char *buf; | ||
1727 | u32 buf_len = 0; | ||
1728 | u32 opt_len; | ||
1729 | struct ip_options *opt = NULL; | ||
1730 | struct inet_sock *sk_inet; | ||
1731 | struct inet_connection_sock *sk_conn; | ||
1732 | 1764 | ||
1733 | /* In the case of sock_create_lite(), the sock->sk field is not | 1765 | if (buf_len <= CIPSO_V4_HDR_LEN) |
1734 | * defined yet but it is not a problem as the only users of these | 1766 | return -ENOSPC; |
1735 | * "lite" PF_INET sockets are functions which do an accept() call | ||
1736 | * afterwards so we will label the socket as part of the accept(). */ | ||
1737 | if (sk == NULL) | ||
1738 | return 0; | ||
1739 | |||
1740 | /* We allocate the maximum CIPSO option size here so we are probably | ||
1741 | * being a little wasteful, but it makes our life _much_ easier later | ||
1742 | * on and after all we are only talking about 40 bytes. */ | ||
1743 | buf_len = CIPSO_V4_OPT_LEN_MAX; | ||
1744 | buf = kmalloc(buf_len, GFP_ATOMIC); | ||
1745 | if (buf == NULL) { | ||
1746 | ret_val = -ENOMEM; | ||
1747 | goto socket_setattr_failure; | ||
1748 | } | ||
1749 | 1767 | ||
1750 | /* XXX - This code assumes only one tag per CIPSO option which isn't | 1768 | /* XXX - This code assumes only one tag per CIPSO option which isn't |
1751 | * really a good assumption to make but since we only support the MAC | 1769 | * really a good assumption to make but since we only support the MAC |
@@ -1772,9 +1790,14 @@ int cipso_v4_sock_setattr(struct sock *sk, | |||
1772 | &buf[CIPSO_V4_HDR_LEN], | 1790 | &buf[CIPSO_V4_HDR_LEN], |
1773 | buf_len - CIPSO_V4_HDR_LEN); | 1791 | buf_len - CIPSO_V4_HDR_LEN); |
1774 | break; | 1792 | break; |
1793 | case CIPSO_V4_TAG_LOCAL: | ||
1794 | ret_val = cipso_v4_gentag_loc(doi_def, | ||
1795 | secattr, | ||
1796 | &buf[CIPSO_V4_HDR_LEN], | ||
1797 | buf_len - CIPSO_V4_HDR_LEN); | ||
1798 | break; | ||
1775 | default: | 1799 | default: |
1776 | ret_val = -EPERM; | 1800 | return -EPERM; |
1777 | goto socket_setattr_failure; | ||
1778 | } | 1801 | } |
1779 | 1802 | ||
1780 | iter++; | 1803 | iter++; |
@@ -1782,9 +1805,58 @@ int cipso_v4_sock_setattr(struct sock *sk, | |||
1782 | iter < CIPSO_V4_TAG_MAXCNT && | 1805 | iter < CIPSO_V4_TAG_MAXCNT && |
1783 | doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); | 1806 | doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); |
1784 | if (ret_val < 0) | 1807 | if (ret_val < 0) |
1785 | goto socket_setattr_failure; | 1808 | return ret_val; |
1786 | cipso_v4_gentag_hdr(doi_def, buf, ret_val); | 1809 | cipso_v4_gentag_hdr(doi_def, buf, ret_val); |
1787 | buf_len = CIPSO_V4_HDR_LEN + ret_val; | 1810 | return CIPSO_V4_HDR_LEN + ret_val; |
1811 | } | ||
1812 | |||
1813 | /** | ||
1814 | * cipso_v4_sock_setattr - Add a CIPSO option to a socket | ||
1815 | * @sk: the socket | ||
1816 | * @doi_def: the CIPSO DOI to use | ||
1817 | * @secattr: the specific security attributes of the socket | ||
1818 | * | ||
1819 | * Description: | ||
1820 | * Set the CIPSO option on the given socket using the DOI definition and | ||
1821 | * security attributes passed to the function. This function requires | ||
1822 | * exclusive access to @sk, which means it either needs to be in the | ||
1823 | * process of being created or locked. Returns zero on success and negative | ||
1824 | * values on failure. | ||
1825 | * | ||
1826 | */ | ||
1827 | int cipso_v4_sock_setattr(struct sock *sk, | ||
1828 | const struct cipso_v4_doi *doi_def, | ||
1829 | const struct netlbl_lsm_secattr *secattr) | ||
1830 | { | ||
1831 | int ret_val = -EPERM; | ||
1832 | unsigned char *buf = NULL; | ||
1833 | u32 buf_len; | ||
1834 | u32 opt_len; | ||
1835 | struct ip_options *opt = NULL; | ||
1836 | struct inet_sock *sk_inet; | ||
1837 | struct inet_connection_sock *sk_conn; | ||
1838 | |||
1839 | /* In the case of sock_create_lite(), the sock->sk field is not | ||
1840 | * defined yet but it is not a problem as the only users of these | ||
1841 | * "lite" PF_INET sockets are functions which do an accept() call | ||
1842 | * afterwards so we will label the socket as part of the accept(). */ | ||
1843 | if (sk == NULL) | ||
1844 | return 0; | ||
1845 | |||
1846 | /* We allocate the maximum CIPSO option size here so we are probably | ||
1847 | * being a little wasteful, but it makes our life _much_ easier later | ||
1848 | * on and after all we are only talking about 40 bytes. */ | ||
1849 | buf_len = CIPSO_V4_OPT_LEN_MAX; | ||
1850 | buf = kmalloc(buf_len, GFP_ATOMIC); | ||
1851 | if (buf == NULL) { | ||
1852 | ret_val = -ENOMEM; | ||
1853 | goto socket_setattr_failure; | ||
1854 | } | ||
1855 | |||
1856 | ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr); | ||
1857 | if (ret_val < 0) | ||
1858 | goto socket_setattr_failure; | ||
1859 | buf_len = ret_val; | ||
1788 | 1860 | ||
1789 | /* We can't use ip_options_get() directly because it makes a call to | 1861 | /* We can't use ip_options_get() directly because it makes a call to |
1790 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and | 1862 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and |
@@ -1822,6 +1894,80 @@ socket_setattr_failure: | |||
1822 | } | 1894 | } |
1823 | 1895 | ||
1824 | /** | 1896 | /** |
1897 | * cipso_v4_sock_delattr - Delete the CIPSO option from a socket | ||
1898 | * @sk: the socket | ||
1899 | * | ||
1900 | * Description: | ||
1901 | * Removes the CIPSO option from a socket, if present. | ||
1902 | * | ||
1903 | */ | ||
1904 | void cipso_v4_sock_delattr(struct sock *sk) | ||
1905 | { | ||
1906 | u8 hdr_delta; | ||
1907 | struct ip_options *opt; | ||
1908 | struct inet_sock *sk_inet; | ||
1909 | |||
1910 | sk_inet = inet_sk(sk); | ||
1911 | opt = sk_inet->opt; | ||
1912 | if (opt == NULL || opt->cipso == 0) | ||
1913 | return; | ||
1914 | |||
1915 | if (opt->srr || opt->rr || opt->ts || opt->router_alert) { | ||
1916 | u8 cipso_len; | ||
1917 | u8 cipso_off; | ||
1918 | unsigned char *cipso_ptr; | ||
1919 | int iter; | ||
1920 | int optlen_new; | ||
1921 | |||
1922 | cipso_off = opt->cipso - sizeof(struct iphdr); | ||
1923 | cipso_ptr = &opt->__data[cipso_off]; | ||
1924 | cipso_len = cipso_ptr[1]; | ||
1925 | |||
1926 | if (opt->srr > opt->cipso) | ||
1927 | opt->srr -= cipso_len; | ||
1928 | if (opt->rr > opt->cipso) | ||
1929 | opt->rr -= cipso_len; | ||
1930 | if (opt->ts > opt->cipso) | ||
1931 | opt->ts -= cipso_len; | ||
1932 | if (opt->router_alert > opt->cipso) | ||
1933 | opt->router_alert -= cipso_len; | ||
1934 | opt->cipso = 0; | ||
1935 | |||
1936 | memmove(cipso_ptr, cipso_ptr + cipso_len, | ||
1937 | opt->optlen - cipso_off - cipso_len); | ||
1938 | |||
1939 | /* determining the new total option length is tricky because of | ||
1940 | * the padding necessary, the only thing i can think to do at | ||
1941 | * this point is walk the options one-by-one, skipping the | ||
1942 | * padding at the end to determine the actual option size and | ||
1943 | * from there we can determine the new total option length */ | ||
1944 | iter = 0; | ||
1945 | optlen_new = 0; | ||
1946 | while (iter < opt->optlen) | ||
1947 | if (opt->__data[iter] != IPOPT_NOP) { | ||
1948 | iter += opt->__data[iter + 1]; | ||
1949 | optlen_new = iter; | ||
1950 | } else | ||
1951 | iter++; | ||
1952 | hdr_delta = opt->optlen; | ||
1953 | opt->optlen = (optlen_new + 3) & ~3; | ||
1954 | hdr_delta -= opt->optlen; | ||
1955 | } else { | ||
1956 | /* only the cipso option was present on the socket so we can | ||
1957 | * remove the entire option struct */ | ||
1958 | sk_inet->opt = NULL; | ||
1959 | hdr_delta = opt->optlen; | ||
1960 | kfree(opt); | ||
1961 | } | ||
1962 | |||
1963 | if (sk_inet->is_icsk && hdr_delta > 0) { | ||
1964 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
1965 | sk_conn->icsk_ext_hdr_len -= hdr_delta; | ||
1966 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
1967 | } | ||
1968 | } | ||
1969 | |||
1970 | /** | ||
1825 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions | 1971 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions |
1826 | * @cipso: the CIPSO v4 option | 1972 | * @cipso: the CIPSO v4 option |
1827 | * @secattr: the security attributes | 1973 | * @secattr: the security attributes |
@@ -1859,6 +2005,9 @@ static int cipso_v4_getattr(const unsigned char *cipso, | |||
1859 | case CIPSO_V4_TAG_RANGE: | 2005 | case CIPSO_V4_TAG_RANGE: |
1860 | ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); | 2006 | ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); |
1861 | break; | 2007 | break; |
2008 | case CIPSO_V4_TAG_LOCAL: | ||
2009 | ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr); | ||
2010 | break; | ||
1862 | } | 2011 | } |
1863 | if (ret_val == 0) | 2012 | if (ret_val == 0) |
1864 | secattr->type = NETLBL_NLTYPE_CIPSOV4; | 2013 | secattr->type = NETLBL_NLTYPE_CIPSOV4; |
@@ -1893,6 +2042,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | |||
1893 | } | 2042 | } |
1894 | 2043 | ||
1895 | /** | 2044 | /** |
2045 | * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet | ||
2046 | * @skb: the packet | ||
2047 | * @secattr: the security attributes | ||
2048 | * | ||
2049 | * Description: | ||
2050 | * Set the CIPSO option on the given packet based on the security attributes. | ||
2051 | * Returns a pointer to the IP header on success and NULL on failure. | ||
2052 | * | ||
2053 | */ | ||
2054 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, | ||
2055 | const struct cipso_v4_doi *doi_def, | ||
2056 | const struct netlbl_lsm_secattr *secattr) | ||
2057 | { | ||
2058 | int ret_val; | ||
2059 | struct iphdr *iph; | ||
2060 | struct ip_options *opt = &IPCB(skb)->opt; | ||
2061 | unsigned char buf[CIPSO_V4_OPT_LEN_MAX]; | ||
2062 | u32 buf_len = CIPSO_V4_OPT_LEN_MAX; | ||
2063 | u32 opt_len; | ||
2064 | int len_delta; | ||
2065 | |||
2066 | buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr); | ||
2067 | if (buf_len < 0) | ||
2068 | return buf_len; | ||
2069 | opt_len = (buf_len + 3) & ~3; | ||
2070 | |||
2071 | /* we overwrite any existing options to ensure that we have enough | ||
2072 | * room for the CIPSO option, the reason is that we _need_ to guarantee | ||
2073 | * that the security label is applied to the packet - we do the same | ||
2074 | * thing when using the socket options and it hasn't caused a problem, | ||
2075 | * if we need to we can always revisit this choice later */ | ||
2076 | |||
2077 | len_delta = opt_len - opt->optlen; | ||
2078 | /* if we don't ensure enough headroom we could panic on the skb_push() | ||
2079 | * call below so make sure we have enough, we are also "mangling" the | ||
2080 | * packet so we should probably do a copy-on-write call anyway */ | ||
2081 | ret_val = skb_cow(skb, skb_headroom(skb) + len_delta); | ||
2082 | if (ret_val < 0) | ||
2083 | return ret_val; | ||
2084 | |||
2085 | if (len_delta > 0) { | ||
2086 | /* we assume that the header + opt->optlen have already been | ||
2087 | * "pushed" in ip_options_build() or similar */ | ||
2088 | iph = ip_hdr(skb); | ||
2089 | skb_push(skb, len_delta); | ||
2090 | memmove((char *)iph - len_delta, iph, iph->ihl << 2); | ||
2091 | skb_reset_network_header(skb); | ||
2092 | iph = ip_hdr(skb); | ||
2093 | } else if (len_delta < 0) { | ||
2094 | iph = ip_hdr(skb); | ||
2095 | memset(iph + 1, IPOPT_NOP, opt->optlen); | ||
2096 | } else | ||
2097 | iph = ip_hdr(skb); | ||
2098 | |||
2099 | if (opt->optlen > 0) | ||
2100 | memset(opt, 0, sizeof(*opt)); | ||
2101 | opt->optlen = opt_len; | ||
2102 | opt->cipso = sizeof(struct iphdr); | ||
2103 | opt->is_changed = 1; | ||
2104 | |||
2105 | /* we have to do the following because we are being called from a | ||
2106 | * netfilter hook which means the packet already has had the header | ||
2107 | * fields populated and the checksum calculated - yes this means we | ||
2108 | * are doing more work than needed but we do it to keep the core | ||
2109 | * stack clean and tidy */ | ||
2110 | memcpy(iph + 1, buf, buf_len); | ||
2111 | if (opt_len > buf_len) | ||
2112 | memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len); | ||
2113 | if (len_delta != 0) { | ||
2114 | iph->ihl = 5 + (opt_len >> 2); | ||
2115 | iph->tot_len = htons(skb->len); | ||
2116 | } | ||
2117 | ip_send_check(iph); | ||
2118 | |||
2119 | return 0; | ||
2120 | } | ||
2121 | |||
2122 | /** | ||
2123 | * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet | ||
2124 | * @skb: the packet | ||
2125 | * | ||
2126 | * Description: | ||
2127 | * Removes any and all CIPSO options from the given packet. Returns zero on | ||
2128 | * success, negative values on failure. | ||
2129 | * | ||
2130 | */ | ||
2131 | int cipso_v4_skbuff_delattr(struct sk_buff *skb) | ||
2132 | { | ||
2133 | int ret_val; | ||
2134 | struct iphdr *iph; | ||
2135 | struct ip_options *opt = &IPCB(skb)->opt; | ||
2136 | unsigned char *cipso_ptr; | ||
2137 | |||
2138 | if (opt->cipso == 0) | ||
2139 | return 0; | ||
2140 | |||
2141 | /* since we are changing the packet we should make a copy */ | ||
2142 | ret_val = skb_cow(skb, skb_headroom(skb)); | ||
2143 | if (ret_val < 0) | ||
2144 | return ret_val; | ||
2145 | |||
2146 | /* the easiest thing to do is just replace the cipso option with noop | ||
2147 | * options since we don't change the size of the packet, although we | ||
2148 | * still need to recalculate the checksum */ | ||
2149 | |||
2150 | iph = ip_hdr(skb); | ||
2151 | cipso_ptr = (unsigned char *)iph + opt->cipso; | ||
2152 | memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]); | ||
2153 | opt->cipso = 0; | ||
2154 | opt->is_changed = 1; | ||
2155 | |||
2156 | ip_send_check(iph); | ||
2157 | |||
2158 | return 0; | ||
2159 | } | ||
2160 | |||
2161 | /** | ||
1896 | * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option | 2162 | * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option |
1897 | * @skb: the packet | 2163 | * @skb: the packet |
1898 | * @secattr: the security attributes | 2164 | * @secattr: the security attributes |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index be3f18a7a40e..2c88da6e7862 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -438,7 +438,7 @@ int ip_options_compile(struct net *net, | |||
438 | goto error; | 438 | goto error; |
439 | } | 439 | } |
440 | opt->cipso = optptr - iph; | 440 | opt->cipso = optptr - iph; |
441 | if (cipso_v4_validate(&optptr)) { | 441 | if (cipso_v4_validate(skb, &optptr)) { |
442 | pp_ptr = optptr; | 442 | pp_ptr = optptr; |
443 | goto error; | 443 | goto error; |
444 | } | 444 | } |
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile index 8af18c0a47d9..ea750e9df65f 100644 --- a/net/netlabel/Makefile +++ b/net/netlabel/Makefile | |||
@@ -5,7 +5,8 @@ | |||
5 | # | 5 | # |
6 | 6 | ||
7 | # base objects | 7 | # base objects |
8 | obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o | 8 | obj-y := netlabel_user.o netlabel_kapi.o |
9 | obj-y += netlabel_domainhash.o netlabel_addrlist.o | ||
9 | 10 | ||
10 | # management objects | 11 | # management objects |
11 | obj-y += netlabel_mgmt.o | 12 | obj-y += netlabel_mgmt.o |
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c new file mode 100644 index 000000000000..b0925a303353 --- /dev/null +++ b/net/netlabel/netlabel_addrlist.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * NetLabel Network Address Lists | ||
3 | * | ||
4 | * This file contains network address list functions used to manage ordered | ||
5 | * lists of network addresses for use by the NetLabel subsystem. The NetLabel | ||
6 | * system manages static and dynamic label mappings for network protocols such | ||
7 | * as CIPSO and RIPSO. | ||
8 | * | ||
9 | * Author: Paul Moore <paul.moore@hp.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/types.h> | ||
33 | #include <linux/rcupdate.h> | ||
34 | #include <linux/list.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/in.h> | ||
37 | #include <linux/in6.h> | ||
38 | #include <linux/ip.h> | ||
39 | #include <linux/ipv6.h> | ||
40 | #include <net/ip.h> | ||
41 | #include <net/ipv6.h> | ||
42 | #include <linux/audit.h> | ||
43 | |||
44 | #include "netlabel_addrlist.h" | ||
45 | |||
46 | /* | ||
47 | * Address List Functions | ||
48 | */ | ||
49 | |||
50 | /** | ||
51 | * netlbl_af4list_search - Search for a matching IPv4 address entry | ||
52 | * @addr: IPv4 address | ||
53 | * @head: the list head | ||
54 | * | ||
55 | * Description: | ||
56 | * Searches the IPv4 address list given by @head. If a matching address entry | ||
57 | * is found it is returned, otherwise NULL is returned. The caller is | ||
58 | * responsible for calling the rcu_read_[un]lock() functions. | ||
59 | * | ||
60 | */ | ||
61 | struct netlbl_af4list *netlbl_af4list_search(__be32 addr, | ||
62 | struct list_head *head) | ||
63 | { | ||
64 | struct netlbl_af4list *iter; | ||
65 | |||
66 | list_for_each_entry_rcu(iter, head, list) | ||
67 | if (iter->valid && (addr & iter->mask) == iter->addr) | ||
68 | return iter; | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * netlbl_af4list_search_exact - Search for an exact IPv4 address entry | ||
75 | * @addr: IPv4 address | ||
76 | * @mask: IPv4 address mask | ||
77 | * @head: the list head | ||
78 | * | ||
79 | * Description: | ||
80 | * Searches the IPv4 address list given by @head. If an exact match if found | ||
81 | * it is returned, otherwise NULL is returned. The caller is responsible for | ||
82 | * calling the rcu_read_[un]lock() functions. | ||
83 | * | ||
84 | */ | ||
85 | struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr, | ||
86 | __be32 mask, | ||
87 | struct list_head *head) | ||
88 | { | ||
89 | struct netlbl_af4list *iter; | ||
90 | |||
91 | list_for_each_entry_rcu(iter, head, list) | ||
92 | if (iter->valid && iter->addr == addr && iter->mask == mask) | ||
93 | return iter; | ||
94 | |||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | |||
99 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
100 | /** | ||
101 | * netlbl_af6list_search - Search for a matching IPv6 address entry | ||
102 | * @addr: IPv6 address | ||
103 | * @head: the list head | ||
104 | * | ||
105 | * Description: | ||
106 | * Searches the IPv6 address list given by @head. If a matching address entry | ||
107 | * is found it is returned, otherwise NULL is returned. The caller is | ||
108 | * responsible for calling the rcu_read_[un]lock() functions. | ||
109 | * | ||
110 | */ | ||
111 | struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr, | ||
112 | struct list_head *head) | ||
113 | { | ||
114 | struct netlbl_af6list *iter; | ||
115 | |||
116 | list_for_each_entry_rcu(iter, head, list) | ||
117 | if (iter->valid && | ||
118 | ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0) | ||
119 | return iter; | ||
120 | |||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * netlbl_af6list_search_exact - Search for an exact IPv6 address entry | ||
126 | * @addr: IPv6 address | ||
127 | * @mask: IPv6 address mask | ||
128 | * @head: the list head | ||
129 | * | ||
130 | * Description: | ||
131 | * Searches the IPv6 address list given by @head. If an exact match if found | ||
132 | * it is returned, otherwise NULL is returned. The caller is responsible for | ||
133 | * calling the rcu_read_[un]lock() functions. | ||
134 | * | ||
135 | */ | ||
136 | struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr, | ||
137 | const struct in6_addr *mask, | ||
138 | struct list_head *head) | ||
139 | { | ||
140 | struct netlbl_af6list *iter; | ||
141 | |||
142 | list_for_each_entry_rcu(iter, head, list) | ||
143 | if (iter->valid && | ||
144 | ipv6_addr_equal(&iter->addr, addr) && | ||
145 | ipv6_addr_equal(&iter->mask, mask)) | ||
146 | return iter; | ||
147 | |||
148 | return NULL; | ||
149 | } | ||
150 | #endif /* IPv6 */ | ||
151 | |||
152 | /** | ||
153 | * netlbl_af4list_add - Add a new IPv4 address entry to a list | ||
154 | * @entry: address entry | ||
155 | * @head: the list head | ||
156 | * | ||
157 | * Description: | ||
158 | * Add a new address entry to the list pointed to by @head. On success zero is | ||
159 | * returned, otherwise a negative value is returned. The caller is responsible | ||
160 | * for calling the necessary locking functions. | ||
161 | * | ||
162 | */ | ||
163 | int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head) | ||
164 | { | ||
165 | struct netlbl_af4list *iter; | ||
166 | |||
167 | iter = netlbl_af4list_search(entry->addr, head); | ||
168 | if (iter != NULL && | ||
169 | iter->addr == entry->addr && iter->mask == entry->mask) | ||
170 | return -EEXIST; | ||
171 | |||
172 | /* in order to speed up address searches through the list (the common | ||
173 | * case) we need to keep the list in order based on the size of the | ||
174 | * address mask such that the entry with the widest mask (smallest | ||
175 | * numerical value) appears first in the list */ | ||
176 | list_for_each_entry_rcu(iter, head, list) | ||
177 | if (iter->valid && | ||
178 | ntohl(entry->mask) > ntohl(iter->mask)) { | ||
179 | __list_add_rcu(&entry->list, | ||
180 | iter->list.prev, | ||
181 | &iter->list); | ||
182 | return 0; | ||
183 | } | ||
184 | list_add_tail_rcu(&entry->list, head); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
189 | /** | ||
190 | * netlbl_af6list_add - Add a new IPv6 address entry to a list | ||
191 | * @entry: address entry | ||
192 | * @head: the list head | ||
193 | * | ||
194 | * Description: | ||
195 | * Add a new address entry to the list pointed to by @head. On success zero is | ||
196 | * returned, otherwise a negative value is returned. The caller is responsible | ||
197 | * for calling the necessary locking functions. | ||
198 | * | ||
199 | */ | ||
200 | int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head) | ||
201 | { | ||
202 | struct netlbl_af6list *iter; | ||
203 | |||
204 | iter = netlbl_af6list_search(&entry->addr, head); | ||
205 | if (iter != NULL && | ||
206 | ipv6_addr_equal(&iter->addr, &entry->addr) && | ||
207 | ipv6_addr_equal(&iter->mask, &entry->mask)) | ||
208 | return -EEXIST; | ||
209 | |||
210 | /* in order to speed up address searches through the list (the common | ||
211 | * case) we need to keep the list in order based on the size of the | ||
212 | * address mask such that the entry with the widest mask (smallest | ||
213 | * numerical value) appears first in the list */ | ||
214 | list_for_each_entry_rcu(iter, head, list) | ||
215 | if (iter->valid && | ||
216 | ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) { | ||
217 | __list_add_rcu(&entry->list, | ||
218 | iter->list.prev, | ||
219 | &iter->list); | ||
220 | return 0; | ||
221 | } | ||
222 | list_add_tail_rcu(&entry->list, head); | ||
223 | return 0; | ||
224 | } | ||
225 | #endif /* IPv6 */ | ||
226 | |||
227 | /** | ||
228 | * netlbl_af4list_remove_entry - Remove an IPv4 address entry | ||
229 | * @entry: address entry | ||
230 | * | ||
231 | * Description: | ||
232 | * Remove the specified IP address entry. The caller is responsible for | ||
233 | * calling the necessary locking functions. | ||
234 | * | ||
235 | */ | ||
236 | void netlbl_af4list_remove_entry(struct netlbl_af4list *entry) | ||
237 | { | ||
238 | entry->valid = 0; | ||
239 | list_del_rcu(&entry->list); | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * netlbl_af4list_remove - Remove an IPv4 address entry | ||
244 | * @addr: IP address | ||
245 | * @mask: IP address mask | ||
246 | * @head: the list head | ||
247 | * | ||
248 | * Description: | ||
249 | * Remove an IP address entry from the list pointed to by @head. Returns the | ||
250 | * entry on success, NULL on failure. The caller is responsible for calling | ||
251 | * the necessary locking functions. | ||
252 | * | ||
253 | */ | ||
254 | struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask, | ||
255 | struct list_head *head) | ||
256 | { | ||
257 | struct netlbl_af4list *entry; | ||
258 | |||
259 | entry = netlbl_af4list_search(addr, head); | ||
260 | if (entry != NULL && entry->addr == addr && entry->mask == mask) { | ||
261 | netlbl_af4list_remove_entry(entry); | ||
262 | return entry; | ||
263 | } | ||
264 | |||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
269 | /** | ||
270 | * netlbl_af6list_remove_entry - Remove an IPv6 address entry | ||
271 | * @entry: address entry | ||
272 | * | ||
273 | * Description: | ||
274 | * Remove the specified IP address entry. The caller is responsible for | ||
275 | * calling the necessary locking functions. | ||
276 | * | ||
277 | */ | ||
278 | void netlbl_af6list_remove_entry(struct netlbl_af6list *entry) | ||
279 | { | ||
280 | entry->valid = 0; | ||
281 | list_del_rcu(&entry->list); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * netlbl_af6list_remove - Remove an IPv6 address entry | ||
286 | * @addr: IP address | ||
287 | * @mask: IP address mask | ||
288 | * @head: the list head | ||
289 | * | ||
290 | * Description: | ||
291 | * Remove an IP address entry from the list pointed to by @head. Returns the | ||
292 | * entry on success, NULL on failure. The caller is responsible for calling | ||
293 | * the necessary locking functions. | ||
294 | * | ||
295 | */ | ||
296 | struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr, | ||
297 | const struct in6_addr *mask, | ||
298 | struct list_head *head) | ||
299 | { | ||
300 | struct netlbl_af6list *entry; | ||
301 | |||
302 | entry = netlbl_af6list_search(addr, head); | ||
303 | if (entry != NULL && | ||
304 | ipv6_addr_equal(&entry->addr, addr) && | ||
305 | ipv6_addr_equal(&entry->mask, mask)) { | ||
306 | netlbl_af6list_remove_entry(entry); | ||
307 | return entry; | ||
308 | } | ||
309 | |||
310 | return NULL; | ||
311 | } | ||
312 | #endif /* IPv6 */ | ||
313 | |||
314 | /* | ||
315 | * Audit Helper Functions | ||
316 | */ | ||
317 | |||
318 | /** | ||
319 | * netlbl_af4list_audit_addr - Audit an IPv4 address | ||
320 | * @audit_buf: audit buffer | ||
321 | * @src: true if source address, false if destination | ||
322 | * @dev: network interface | ||
323 | * @addr: IP address | ||
324 | * @mask: IP address mask | ||
325 | * | ||
326 | * Description: | ||
327 | * Write the IPv4 address and address mask, if necessary, to @audit_buf. | ||
328 | * | ||
329 | */ | ||
330 | void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, | ||
331 | int src, const char *dev, | ||
332 | __be32 addr, __be32 mask) | ||
333 | { | ||
334 | u32 mask_val = ntohl(mask); | ||
335 | char *dir = (src ? "src" : "dst"); | ||
336 | |||
337 | if (dev != NULL) | ||
338 | audit_log_format(audit_buf, " netif=%s", dev); | ||
339 | audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr)); | ||
340 | if (mask_val != 0xffffffff) { | ||
341 | u32 mask_len = 0; | ||
342 | while (mask_val > 0) { | ||
343 | mask_val <<= 1; | ||
344 | mask_len++; | ||
345 | } | ||
346 | audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
351 | /** | ||
352 | * netlbl_af6list_audit_addr - Audit an IPv6 address | ||
353 | * @audit_buf: audit buffer | ||
354 | * @src: true if source address, false if destination | ||
355 | * @dev: network interface | ||
356 | * @addr: IP address | ||
357 | * @mask: IP address mask | ||
358 | * | ||
359 | * Description: | ||
360 | * Write the IPv6 address and address mask, if necessary, to @audit_buf. | ||
361 | * | ||
362 | */ | ||
363 | void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, | ||
364 | int src, | ||
365 | const char *dev, | ||
366 | const struct in6_addr *addr, | ||
367 | const struct in6_addr *mask) | ||
368 | { | ||
369 | char *dir = (src ? "src" : "dst"); | ||
370 | |||
371 | if (dev != NULL) | ||
372 | audit_log_format(audit_buf, " netif=%s", dev); | ||
373 | audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr)); | ||
374 | if (ntohl(mask->s6_addr32[3]) != 0xffffffff) { | ||
375 | u32 mask_len = 0; | ||
376 | u32 mask_val; | ||
377 | int iter = -1; | ||
378 | while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff) | ||
379 | mask_len += 32; | ||
380 | mask_val = ntohl(mask->s6_addr32[iter]); | ||
381 | while (mask_val > 0) { | ||
382 | mask_val <<= 1; | ||
383 | mask_len++; | ||
384 | } | ||
385 | audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len); | ||
386 | } | ||
387 | } | ||
388 | #endif /* IPv6 */ | ||
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h new file mode 100644 index 000000000000..0242bead405f --- /dev/null +++ b/net/netlabel/netlabel_addrlist.h | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * NetLabel Network Address Lists | ||
3 | * | ||
4 | * This file contains network address list functions used to manage ordered | ||
5 | * lists of network addresses for use by the NetLabel subsystem. The NetLabel | ||
6 | * system manages static and dynamic label mappings for network protocols such | ||
7 | * as CIPSO and RIPSO. | ||
8 | * | ||
9 | * Author: Paul Moore <paul.moore@hp.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #ifndef _NETLABEL_ADDRLIST_H | ||
33 | #define _NETLABEL_ADDRLIST_H | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/rcupdate.h> | ||
37 | #include <linux/list.h> | ||
38 | #include <linux/in6.h> | ||
39 | #include <linux/audit.h> | ||
40 | |||
41 | /** | ||
42 | * struct netlbl_af4list - NetLabel IPv4 address list | ||
43 | * @addr: IPv4 address | ||
44 | * @mask: IPv4 address mask | ||
45 | * @valid: valid flag | ||
46 | * @list: list structure, used internally | ||
47 | */ | ||
48 | struct netlbl_af4list { | ||
49 | __be32 addr; | ||
50 | __be32 mask; | ||
51 | |||
52 | u32 valid; | ||
53 | struct list_head list; | ||
54 | }; | ||
55 | |||
56 | /** | ||
57 | * struct netlbl_af6list - NetLabel IPv6 address list | ||
58 | * @addr: IPv6 address | ||
59 | * @mask: IPv6 address mask | ||
60 | * @valid: valid flag | ||
61 | * @list: list structure, used internally | ||
62 | */ | ||
63 | struct netlbl_af6list { | ||
64 | struct in6_addr addr; | ||
65 | struct in6_addr mask; | ||
66 | |||
67 | u32 valid; | ||
68 | struct list_head list; | ||
69 | }; | ||
70 | |||
71 | #define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list) | ||
72 | |||
73 | static inline struct netlbl_af4list *__af4list_valid(struct list_head *s, | ||
74 | struct list_head *h) | ||
75 | { | ||
76 | struct list_head *i = s; | ||
77 | struct netlbl_af4list *n = __af4list_entry(s); | ||
78 | while (i != h && !n->valid) { | ||
79 | i = i->next; | ||
80 | n = __af4list_entry(i); | ||
81 | } | ||
82 | return n; | ||
83 | } | ||
84 | |||
85 | static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s, | ||
86 | struct list_head *h) | ||
87 | { | ||
88 | struct list_head *i = s; | ||
89 | struct netlbl_af4list *n = __af4list_entry(s); | ||
90 | while (i != h && !n->valid) { | ||
91 | i = rcu_dereference(i->next); | ||
92 | n = __af4list_entry(i); | ||
93 | } | ||
94 | return n; | ||
95 | } | ||
96 | |||
97 | #define netlbl_af4list_foreach(iter, head) \ | ||
98 | for (iter = __af4list_valid((head)->next, head); \ | ||
99 | prefetch(iter->list.next), &iter->list != (head); \ | ||
100 | iter = __af4list_valid(iter->list.next, head)) | ||
101 | |||
102 | #define netlbl_af4list_foreach_rcu(iter, head) \ | ||
103 | for (iter = __af4list_valid_rcu((head)->next, head); \ | ||
104 | prefetch(iter->list.next), &iter->list != (head); \ | ||
105 | iter = __af4list_valid_rcu(iter->list.next, head)) | ||
106 | |||
107 | #define netlbl_af4list_foreach_safe(iter, tmp, head) \ | ||
108 | for (iter = __af4list_valid((head)->next, head), \ | ||
109 | tmp = __af4list_valid(iter->list.next, head); \ | ||
110 | &iter->list != (head); \ | ||
111 | iter = tmp, tmp = __af4list_valid(iter->list.next, head)) | ||
112 | |||
113 | int netlbl_af4list_add(struct netlbl_af4list *entry, | ||
114 | struct list_head *head); | ||
115 | struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask, | ||
116 | struct list_head *head); | ||
117 | void netlbl_af4list_remove_entry(struct netlbl_af4list *entry); | ||
118 | struct netlbl_af4list *netlbl_af4list_search(__be32 addr, | ||
119 | struct list_head *head); | ||
120 | struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr, | ||
121 | __be32 mask, | ||
122 | struct list_head *head); | ||
123 | void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, | ||
124 | int src, const char *dev, | ||
125 | __be32 addr, __be32 mask); | ||
126 | |||
127 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
128 | |||
129 | #define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list) | ||
130 | |||
131 | static inline struct netlbl_af6list *__af6list_valid(struct list_head *s, | ||
132 | struct list_head *h) | ||
133 | { | ||
134 | struct list_head *i = s; | ||
135 | struct netlbl_af6list *n = __af6list_entry(s); | ||
136 | while (i != h && !n->valid) { | ||
137 | i = i->next; | ||
138 | n = __af6list_entry(i); | ||
139 | } | ||
140 | return n; | ||
141 | } | ||
142 | |||
143 | static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s, | ||
144 | struct list_head *h) | ||
145 | { | ||
146 | struct list_head *i = s; | ||
147 | struct netlbl_af6list *n = __af6list_entry(s); | ||
148 | while (i != h && !n->valid) { | ||
149 | i = rcu_dereference(i->next); | ||
150 | n = __af6list_entry(i); | ||
151 | } | ||
152 | return n; | ||
153 | } | ||
154 | |||
155 | #define netlbl_af6list_foreach(iter, head) \ | ||
156 | for (iter = __af6list_valid((head)->next, head); \ | ||
157 | prefetch(iter->list.next), &iter->list != (head); \ | ||
158 | iter = __af6list_valid(iter->list.next, head)) | ||
159 | |||
160 | #define netlbl_af6list_foreach_rcu(iter, head) \ | ||
161 | for (iter = __af6list_valid_rcu((head)->next, head); \ | ||
162 | prefetch(iter->list.next), &iter->list != (head); \ | ||
163 | iter = __af6list_valid_rcu(iter->list.next, head)) | ||
164 | |||
165 | #define netlbl_af6list_foreach_safe(iter, tmp, head) \ | ||
166 | for (iter = __af6list_valid((head)->next, head), \ | ||
167 | tmp = __af6list_valid(iter->list.next, head); \ | ||
168 | &iter->list != (head); \ | ||
169 | iter = tmp, tmp = __af6list_valid(iter->list.next, head)) | ||
170 | |||
171 | int netlbl_af6list_add(struct netlbl_af6list *entry, | ||
172 | struct list_head *head); | ||
173 | struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr, | ||
174 | const struct in6_addr *mask, | ||
175 | struct list_head *head); | ||
176 | void netlbl_af6list_remove_entry(struct netlbl_af6list *entry); | ||
177 | struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr, | ||
178 | struct list_head *head); | ||
179 | struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr, | ||
180 | const struct in6_addr *mask, | ||
181 | struct list_head *head); | ||
182 | void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, | ||
183 | int src, | ||
184 | const char *dev, | ||
185 | const struct in6_addr *addr, | ||
186 | const struct in6_addr *mask); | ||
187 | #endif /* IPV6 */ | ||
188 | |||
189 | #endif | ||
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 0aec318bf0ef..fff32b70efa9 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include "netlabel_user.h" | 43 | #include "netlabel_user.h" |
44 | #include "netlabel_cipso_v4.h" | 44 | #include "netlabel_cipso_v4.h" |
45 | #include "netlabel_mgmt.h" | 45 | #include "netlabel_mgmt.h" |
46 | #include "netlabel_domainhash.h" | ||
46 | 47 | ||
47 | /* Argument struct for cipso_v4_doi_walk() */ | 48 | /* Argument struct for cipso_v4_doi_walk() */ |
48 | struct netlbl_cipsov4_doiwalk_arg { | 49 | struct netlbl_cipsov4_doiwalk_arg { |
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg { | |||
51 | u32 seq; | 52 | u32 seq; |
52 | }; | 53 | }; |
53 | 54 | ||
55 | /* Argument struct for netlbl_domhsh_walk() */ | ||
56 | struct netlbl_domhsh_walk_arg { | ||
57 | struct netlbl_audit *audit_info; | ||
58 | u32 doi; | ||
59 | }; | ||
60 | |||
54 | /* NetLabel Generic NETLINK CIPSOv4 family */ | 61 | /* NetLabel Generic NETLINK CIPSOv4 family */ |
55 | static struct genl_family netlbl_cipsov4_gnl_family = { | 62 | static struct genl_family netlbl_cipsov4_gnl_family = { |
56 | .id = GENL_ID_GENERATE, | 63 | .id = GENL_ID_GENERATE, |
@@ -81,32 +88,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1 | |||
81 | */ | 88 | */ |
82 | 89 | ||
83 | /** | 90 | /** |
84 | * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition | ||
85 | * @entry: the entry's RCU field | ||
86 | * | ||
87 | * Description: | ||
88 | * This function is designed to be used as a callback to the call_rcu() | ||
89 | * function so that the memory allocated to the DOI definition can be released | ||
90 | * safely. | ||
91 | * | ||
92 | */ | ||
93 | void netlbl_cipsov4_doi_free(struct rcu_head *entry) | ||
94 | { | ||
95 | struct cipso_v4_doi *ptr; | ||
96 | |||
97 | ptr = container_of(entry, struct cipso_v4_doi, rcu); | ||
98 | switch (ptr->type) { | ||
99 | case CIPSO_V4_MAP_STD: | ||
100 | kfree(ptr->map.std->lvl.cipso); | ||
101 | kfree(ptr->map.std->lvl.local); | ||
102 | kfree(ptr->map.std->cat.cipso); | ||
103 | kfree(ptr->map.std->cat.local); | ||
104 | break; | ||
105 | } | ||
106 | kfree(ptr); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * netlbl_cipsov4_add_common - Parse the common sections of a ADD message | 91 | * netlbl_cipsov4_add_common - Parse the common sections of a ADD message |
111 | * @info: the Generic NETLINK info block | 92 | * @info: the Generic NETLINK info block |
112 | * @doi_def: the CIPSO V4 DOI definition | 93 | * @doi_def: the CIPSO V4 DOI definition |
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, | |||
151 | * @info: the Generic NETLINK info block | 132 | * @info: the Generic NETLINK info block |
152 | * | 133 | * |
153 | * Description: | 134 | * Description: |
154 | * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message | 135 | * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD |
155 | * and add it to the CIPSO V4 engine. Return zero on success and non-zero on | 136 | * message and add it to the CIPSO V4 engine. Return zero on success and |
156 | * error. | 137 | * non-zero on error. |
157 | * | 138 | * |
158 | */ | 139 | */ |
159 | static int netlbl_cipsov4_add_std(struct genl_info *info) | 140 | static int netlbl_cipsov4_add_std(struct genl_info *info) |
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) | |||
183 | ret_val = -ENOMEM; | 164 | ret_val = -ENOMEM; |
184 | goto add_std_failure; | 165 | goto add_std_failure; |
185 | } | 166 | } |
186 | doi_def->type = CIPSO_V4_MAP_STD; | 167 | doi_def->type = CIPSO_V4_MAP_TRANS; |
187 | 168 | ||
188 | ret_val = netlbl_cipsov4_add_common(info, doi_def); | 169 | ret_val = netlbl_cipsov4_add_common(info, doi_def); |
189 | if (ret_val != 0) | 170 | if (ret_val != 0) |
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) | |||
342 | 323 | ||
343 | add_std_failure: | 324 | add_std_failure: |
344 | if (doi_def) | 325 | if (doi_def) |
345 | netlbl_cipsov4_doi_free(&doi_def->rcu); | 326 | cipso_v4_doi_free(doi_def); |
346 | return ret_val; | 327 | return ret_val; |
347 | } | 328 | } |
348 | 329 | ||
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info) | |||
379 | return 0; | 360 | return 0; |
380 | 361 | ||
381 | add_pass_failure: | 362 | add_pass_failure: |
382 | netlbl_cipsov4_doi_free(&doi_def->rcu); | 363 | cipso_v4_doi_free(doi_def); |
364 | return ret_val; | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition | ||
369 | * @info: the Generic NETLINK info block | ||
370 | * | ||
371 | * Description: | ||
372 | * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD | ||
373 | * message and add it to the CIPSO V4 engine. Return zero on success and | ||
374 | * non-zero on error. | ||
375 | * | ||
376 | */ | ||
377 | static int netlbl_cipsov4_add_local(struct genl_info *info) | ||
378 | { | ||
379 | int ret_val; | ||
380 | struct cipso_v4_doi *doi_def = NULL; | ||
381 | |||
382 | if (!info->attrs[NLBL_CIPSOV4_A_TAGLST]) | ||
383 | return -EINVAL; | ||
384 | |||
385 | doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); | ||
386 | if (doi_def == NULL) | ||
387 | return -ENOMEM; | ||
388 | doi_def->type = CIPSO_V4_MAP_LOCAL; | ||
389 | |||
390 | ret_val = netlbl_cipsov4_add_common(info, doi_def); | ||
391 | if (ret_val != 0) | ||
392 | goto add_local_failure; | ||
393 | |||
394 | ret_val = cipso_v4_doi_add(doi_def); | ||
395 | if (ret_val != 0) | ||
396 | goto add_local_failure; | ||
397 | return 0; | ||
398 | |||
399 | add_local_failure: | ||
400 | cipso_v4_doi_free(doi_def); | ||
383 | return ret_val; | 401 | return ret_val; |
384 | } | 402 | } |
385 | 403 | ||
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) | |||
412 | 430 | ||
413 | type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); | 431 | type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); |
414 | switch (type) { | 432 | switch (type) { |
415 | case CIPSO_V4_MAP_STD: | 433 | case CIPSO_V4_MAP_TRANS: |
416 | type_str = "std"; | 434 | type_str = "trans"; |
417 | ret_val = netlbl_cipsov4_add_std(info); | 435 | ret_val = netlbl_cipsov4_add_std(info); |
418 | break; | 436 | break; |
419 | case CIPSO_V4_MAP_PASS: | 437 | case CIPSO_V4_MAP_PASS: |
420 | type_str = "pass"; | 438 | type_str = "pass"; |
421 | ret_val = netlbl_cipsov4_add_pass(info); | 439 | ret_val = netlbl_cipsov4_add_pass(info); |
422 | break; | 440 | break; |
441 | case CIPSO_V4_MAP_LOCAL: | ||
442 | type_str = "local"; | ||
443 | ret_val = netlbl_cipsov4_add_local(info); | ||
444 | break; | ||
423 | } | 445 | } |
424 | if (ret_val == 0) | 446 | if (ret_val == 0) |
425 | atomic_inc(&netlabel_mgmt_protocount); | 447 | atomic_inc(&netlabel_mgmt_protocount); |
@@ -491,7 +513,7 @@ list_start: | |||
491 | doi_def = cipso_v4_doi_getdef(doi); | 513 | doi_def = cipso_v4_doi_getdef(doi); |
492 | if (doi_def == NULL) { | 514 | if (doi_def == NULL) { |
493 | ret_val = -EINVAL; | 515 | ret_val = -EINVAL; |
494 | goto list_failure; | 516 | goto list_failure_lock; |
495 | } | 517 | } |
496 | 518 | ||
497 | ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); | 519 | ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); |
@@ -516,7 +538,7 @@ list_start: | |||
516 | nla_nest_end(ans_skb, nla_a); | 538 | nla_nest_end(ans_skb, nla_a); |
517 | 539 | ||
518 | switch (doi_def->type) { | 540 | switch (doi_def->type) { |
519 | case CIPSO_V4_MAP_STD: | 541 | case CIPSO_V4_MAP_TRANS: |
520 | nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); | 542 | nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); |
521 | if (nla_a == NULL) { | 543 | if (nla_a == NULL) { |
522 | ret_val = -ENOMEM; | 544 | ret_val = -ENOMEM; |
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, | |||
655 | struct netlink_callback *cb) | 677 | struct netlink_callback *cb) |
656 | { | 678 | { |
657 | struct netlbl_cipsov4_doiwalk_arg cb_arg; | 679 | struct netlbl_cipsov4_doiwalk_arg cb_arg; |
658 | int doi_skip = cb->args[0]; | 680 | u32 doi_skip = cb->args[0]; |
659 | 681 | ||
660 | cb_arg.nl_cb = cb; | 682 | cb_arg.nl_cb = cb; |
661 | cb_arg.skb = skb; | 683 | cb_arg.skb = skb; |
@@ -668,6 +690,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, | |||
668 | } | 690 | } |
669 | 691 | ||
670 | /** | 692 | /** |
693 | * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE | ||
694 | * @entry: LSM domain mapping entry | ||
695 | * @arg: the netlbl_domhsh_walk_arg structure | ||
696 | * | ||
697 | * Description: | ||
698 | * This function is intended for use by netlbl_cipsov4_remove() as the callback | ||
699 | * for the netlbl_domhsh_walk() function; it removes LSM domain map entries | ||
700 | * which are associated with the CIPSO DOI specified in @arg. Returns zero on | ||
701 | * success, negative values on failure. | ||
702 | * | ||
703 | */ | ||
704 | static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg) | ||
705 | { | ||
706 | struct netlbl_domhsh_walk_arg *cb_arg = arg; | ||
707 | |||
708 | if (entry->type == NETLBL_NLTYPE_CIPSOV4 && | ||
709 | entry->type_def.cipsov4->doi == cb_arg->doi) | ||
710 | return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info); | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | /** | ||
671 | * netlbl_cipsov4_remove - Handle a REMOVE message | 716 | * netlbl_cipsov4_remove - Handle a REMOVE message |
672 | * @skb: the NETLINK buffer | 717 | * @skb: the NETLINK buffer |
673 | * @info: the Generic NETLINK info block | 718 | * @info: the Generic NETLINK info block |
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | |||
681 | { | 726 | { |
682 | int ret_val = -EINVAL; | 727 | int ret_val = -EINVAL; |
683 | u32 doi = 0; | 728 | u32 doi = 0; |
729 | struct netlbl_domhsh_walk_arg cb_arg; | ||
684 | struct audit_buffer *audit_buf; | 730 | struct audit_buffer *audit_buf; |
685 | struct netlbl_audit audit_info; | 731 | struct netlbl_audit audit_info; |
732 | u32 skip_bkt = 0; | ||
733 | u32 skip_chain = 0; | ||
686 | 734 | ||
687 | if (!info->attrs[NLBL_CIPSOV4_A_DOI]) | 735 | if (!info->attrs[NLBL_CIPSOV4_A_DOI]) |
688 | return -EINVAL; | 736 | return -EINVAL; |
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | |||
690 | doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); | 738 | doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); |
691 | netlbl_netlink_auditinfo(skb, &audit_info); | 739 | netlbl_netlink_auditinfo(skb, &audit_info); |
692 | 740 | ||
693 | ret_val = cipso_v4_doi_remove(doi, | 741 | cb_arg.doi = doi; |
694 | &audit_info, | 742 | cb_arg.audit_info = &audit_info; |
695 | netlbl_cipsov4_doi_free); | 743 | ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, |
696 | if (ret_val == 0) | 744 | netlbl_cipsov4_remove_cb, &cb_arg); |
697 | atomic_dec(&netlabel_mgmt_protocount); | 745 | if (ret_val == 0 || ret_val == -ENOENT) { |
746 | ret_val = cipso_v4_doi_remove(doi, &audit_info); | ||
747 | if (ret_val == 0) | ||
748 | atomic_dec(&netlabel_mgmt_protocount); | ||
749 | } | ||
698 | 750 | ||
699 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, | 751 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, |
700 | &audit_info); | 752 | &audit_info); |
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h index 220cb9d06b49..c8a4079261f0 100644 --- a/net/netlabel/netlabel_cipso_v4.h +++ b/net/netlabel/netlabel_cipso_v4.h | |||
@@ -45,12 +45,13 @@ | |||
45 | * NLBL_CIPSOV4_A_MTYPE | 45 | * NLBL_CIPSOV4_A_MTYPE |
46 | * NLBL_CIPSOV4_A_TAGLST | 46 | * NLBL_CIPSOV4_A_TAGLST |
47 | * | 47 | * |
48 | * If using CIPSO_V4_MAP_STD the following attributes are required: | 48 | * If using CIPSO_V4_MAP_TRANS the following attributes are required: |
49 | * | 49 | * |
50 | * NLBL_CIPSOV4_A_MLSLVLLST | 50 | * NLBL_CIPSOV4_A_MLSLVLLST |
51 | * NLBL_CIPSOV4_A_MLSCATLST | 51 | * NLBL_CIPSOV4_A_MLSCATLST |
52 | * | 52 | * |
53 | * If using CIPSO_V4_MAP_PASS no additional attributes are required. | 53 | * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes |
54 | * are required. | ||
54 | * | 55 | * |
55 | * o REMOVE: | 56 | * o REMOVE: |
56 | * Sent by an application to remove a specific DOI mapping table from the | 57 | * Sent by an application to remove a specific DOI mapping table from the |
@@ -76,12 +77,13 @@ | |||
76 | * NLBL_CIPSOV4_A_MTYPE | 77 | * NLBL_CIPSOV4_A_MTYPE |
77 | * NLBL_CIPSOV4_A_TAGLST | 78 | * NLBL_CIPSOV4_A_TAGLST |
78 | * | 79 | * |
79 | * If using CIPSO_V4_MAP_STD the following attributes are required: | 80 | * If using CIPSO_V4_MAP_TRANS the following attributes are required: |
80 | * | 81 | * |
81 | * NLBL_CIPSOV4_A_MLSLVLLST | 82 | * NLBL_CIPSOV4_A_MLSLVLLST |
82 | * NLBL_CIPSOV4_A_MLSCATLST | 83 | * NLBL_CIPSOV4_A_MLSCATLST |
83 | * | 84 | * |
84 | * If using CIPSO_V4_MAP_PASS no additional attributes are required. | 85 | * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes |
86 | * are required. | ||
85 | * | 87 | * |
86 | * o LISTALL: | 88 | * o LISTALL: |
87 | * This message is sent by an application to list the valid DOIs on the | 89 | * This message is sent by an application to list the valid DOIs on the |
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 643c032a3a57..5fadf10e5ddf 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
@@ -40,6 +40,7 @@ | |||
40 | #include <asm/bug.h> | 40 | #include <asm/bug.h> |
41 | 41 | ||
42 | #include "netlabel_mgmt.h" | 42 | #include "netlabel_mgmt.h" |
43 | #include "netlabel_addrlist.h" | ||
43 | #include "netlabel_domainhash.h" | 44 | #include "netlabel_domainhash.h" |
44 | #include "netlabel_user.h" | 45 | #include "netlabel_user.h" |
45 | 46 | ||
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL; | |||
72 | static void netlbl_domhsh_free_entry(struct rcu_head *entry) | 73 | static void netlbl_domhsh_free_entry(struct rcu_head *entry) |
73 | { | 74 | { |
74 | struct netlbl_dom_map *ptr; | 75 | struct netlbl_dom_map *ptr; |
76 | struct netlbl_af4list *iter4; | ||
77 | struct netlbl_af4list *tmp4; | ||
78 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
79 | struct netlbl_af6list *iter6; | ||
80 | struct netlbl_af6list *tmp6; | ||
81 | #endif /* IPv6 */ | ||
75 | 82 | ||
76 | ptr = container_of(entry, struct netlbl_dom_map, rcu); | 83 | ptr = container_of(entry, struct netlbl_dom_map, rcu); |
84 | if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) { | ||
85 | netlbl_af4list_foreach_safe(iter4, tmp4, | ||
86 | &ptr->type_def.addrsel->list4) { | ||
87 | netlbl_af4list_remove_entry(iter4); | ||
88 | kfree(netlbl_domhsh_addr4_entry(iter4)); | ||
89 | } | ||
90 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
91 | netlbl_af6list_foreach_safe(iter6, tmp6, | ||
92 | &ptr->type_def.addrsel->list6) { | ||
93 | netlbl_af6list_remove_entry(iter6); | ||
94 | kfree(netlbl_domhsh_addr6_entry(iter6)); | ||
95 | } | ||
96 | #endif /* IPv6 */ | ||
97 | } | ||
77 | kfree(ptr->domain); | 98 | kfree(ptr->domain); |
78 | kfree(ptr); | 99 | kfree(ptr); |
79 | } | 100 | } |
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
115 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | 136 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) |
116 | { | 137 | { |
117 | u32 bkt; | 138 | u32 bkt; |
139 | struct list_head *bkt_list; | ||
118 | struct netlbl_dom_map *iter; | 140 | struct netlbl_dom_map *iter; |
119 | 141 | ||
120 | if (domain != NULL) { | 142 | if (domain != NULL) { |
121 | bkt = netlbl_domhsh_hash(domain); | 143 | bkt = netlbl_domhsh_hash(domain); |
122 | list_for_each_entry_rcu(iter, | 144 | bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; |
123 | &rcu_dereference(netlbl_domhsh)->tbl[bkt], | 145 | list_for_each_entry_rcu(iter, bkt_list, list) |
124 | list) | ||
125 | if (iter->valid && strcmp(iter->domain, domain) == 0) | 146 | if (iter->valid && strcmp(iter->domain, domain) == 0) |
126 | return iter; | 147 | return iter; |
127 | } | 148 | } |
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | |||
156 | return entry; | 177 | return entry; |
157 | } | 178 | } |
158 | 179 | ||
180 | /** | ||
181 | * netlbl_domhsh_audit_add - Generate an audit entry for an add event | ||
182 | * @entry: the entry being added | ||
183 | * @addr4: the IPv4 address information | ||
184 | * @addr6: the IPv6 address information | ||
185 | * @result: the result code | ||
186 | * @audit_info: NetLabel audit information | ||
187 | * | ||
188 | * Description: | ||
189 | * Generate an audit record for adding a new NetLabel/LSM mapping entry with | ||
190 | * the given information. Caller is responsibile for holding the necessary | ||
191 | * locks. | ||
192 | * | ||
193 | */ | ||
194 | static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, | ||
195 | struct netlbl_af4list *addr4, | ||
196 | struct netlbl_af6list *addr6, | ||
197 | int result, | ||
198 | struct netlbl_audit *audit_info) | ||
199 | { | ||
200 | struct audit_buffer *audit_buf; | ||
201 | struct cipso_v4_doi *cipsov4 = NULL; | ||
202 | u32 type; | ||
203 | |||
204 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); | ||
205 | if (audit_buf != NULL) { | ||
206 | audit_log_format(audit_buf, " nlbl_domain=%s", | ||
207 | entry->domain ? entry->domain : "(default)"); | ||
208 | if (addr4 != NULL) { | ||
209 | struct netlbl_domaddr4_map *map4; | ||
210 | map4 = netlbl_domhsh_addr4_entry(addr4); | ||
211 | type = map4->type; | ||
212 | cipsov4 = map4->type_def.cipsov4; | ||
213 | netlbl_af4list_audit_addr(audit_buf, 0, NULL, | ||
214 | addr4->addr, addr4->mask); | ||
215 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
216 | } else if (addr6 != NULL) { | ||
217 | struct netlbl_domaddr6_map *map6; | ||
218 | map6 = netlbl_domhsh_addr6_entry(addr6); | ||
219 | type = map6->type; | ||
220 | netlbl_af6list_audit_addr(audit_buf, 0, NULL, | ||
221 | &addr6->addr, &addr6->mask); | ||
222 | #endif /* IPv6 */ | ||
223 | } else { | ||
224 | type = entry->type; | ||
225 | cipsov4 = entry->type_def.cipsov4; | ||
226 | } | ||
227 | switch (type) { | ||
228 | case NETLBL_NLTYPE_UNLABELED: | ||
229 | audit_log_format(audit_buf, " nlbl_protocol=unlbl"); | ||
230 | break; | ||
231 | case NETLBL_NLTYPE_CIPSOV4: | ||
232 | BUG_ON(cipsov4 == NULL); | ||
233 | audit_log_format(audit_buf, | ||
234 | " nlbl_protocol=cipsov4 cipso_doi=%u", | ||
235 | cipsov4->doi); | ||
236 | break; | ||
237 | } | ||
238 | audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0); | ||
239 | audit_log_end(audit_buf); | ||
240 | } | ||
241 | } | ||
242 | |||
159 | /* | 243 | /* |
160 | * Domain Hash Table Functions | 244 | * Domain Hash Table Functions |
161 | */ | 245 | */ |
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size) | |||
213 | int netlbl_domhsh_add(struct netlbl_dom_map *entry, | 297 | int netlbl_domhsh_add(struct netlbl_dom_map *entry, |
214 | struct netlbl_audit *audit_info) | 298 | struct netlbl_audit *audit_info) |
215 | { | 299 | { |
216 | int ret_val; | 300 | int ret_val = 0; |
217 | u32 bkt; | 301 | struct netlbl_dom_map *entry_old; |
218 | struct audit_buffer *audit_buf; | 302 | struct netlbl_af4list *iter4; |
219 | 303 | struct netlbl_af4list *tmp4; | |
220 | switch (entry->type) { | 304 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
221 | case NETLBL_NLTYPE_UNLABELED: | 305 | struct netlbl_af6list *iter6; |
222 | ret_val = 0; | 306 | struct netlbl_af6list *tmp6; |
223 | break; | 307 | #endif /* IPv6 */ |
224 | case NETLBL_NLTYPE_CIPSOV4: | ||
225 | ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4, | ||
226 | entry->domain); | ||
227 | break; | ||
228 | default: | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | if (ret_val != 0) | ||
232 | return ret_val; | ||
233 | |||
234 | entry->valid = 1; | ||
235 | INIT_RCU_HEAD(&entry->rcu); | ||
236 | 308 | ||
237 | rcu_read_lock(); | 309 | rcu_read_lock(); |
310 | |||
238 | spin_lock(&netlbl_domhsh_lock); | 311 | spin_lock(&netlbl_domhsh_lock); |
239 | if (entry->domain != NULL) { | 312 | if (entry->domain != NULL) |
240 | bkt = netlbl_domhsh_hash(entry->domain); | 313 | entry_old = netlbl_domhsh_search(entry->domain); |
241 | if (netlbl_domhsh_search(entry->domain) == NULL) | 314 | else |
315 | entry_old = netlbl_domhsh_search_def(entry->domain); | ||
316 | if (entry_old == NULL) { | ||
317 | entry->valid = 1; | ||
318 | INIT_RCU_HEAD(&entry->rcu); | ||
319 | |||
320 | if (entry->domain != NULL) { | ||
321 | u32 bkt = netlbl_domhsh_hash(entry->domain); | ||
242 | list_add_tail_rcu(&entry->list, | 322 | list_add_tail_rcu(&entry->list, |
243 | &rcu_dereference(netlbl_domhsh)->tbl[bkt]); | 323 | &rcu_dereference(netlbl_domhsh)->tbl[bkt]); |
244 | else | 324 | } else { |
245 | ret_val = -EEXIST; | 325 | INIT_LIST_HEAD(&entry->list); |
246 | } else { | ||
247 | INIT_LIST_HEAD(&entry->list); | ||
248 | if (rcu_dereference(netlbl_domhsh_def) == NULL) | ||
249 | rcu_assign_pointer(netlbl_domhsh_def, entry); | 326 | rcu_assign_pointer(netlbl_domhsh_def, entry); |
250 | else | ||
251 | ret_val = -EEXIST; | ||
252 | } | ||
253 | spin_unlock(&netlbl_domhsh_lock); | ||
254 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); | ||
255 | if (audit_buf != NULL) { | ||
256 | audit_log_format(audit_buf, | ||
257 | " nlbl_domain=%s", | ||
258 | entry->domain ? entry->domain : "(default)"); | ||
259 | switch (entry->type) { | ||
260 | case NETLBL_NLTYPE_UNLABELED: | ||
261 | audit_log_format(audit_buf, " nlbl_protocol=unlbl"); | ||
262 | break; | ||
263 | case NETLBL_NLTYPE_CIPSOV4: | ||
264 | audit_log_format(audit_buf, | ||
265 | " nlbl_protocol=cipsov4 cipso_doi=%u", | ||
266 | entry->type_def.cipsov4->doi); | ||
267 | break; | ||
268 | } | 327 | } |
269 | audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); | ||
270 | audit_log_end(audit_buf); | ||
271 | } | ||
272 | rcu_read_unlock(); | ||
273 | 328 | ||
274 | if (ret_val != 0) { | 329 | if (entry->type == NETLBL_NLTYPE_ADDRSELECT) { |
275 | switch (entry->type) { | 330 | netlbl_af4list_foreach_rcu(iter4, |
276 | case NETLBL_NLTYPE_CIPSOV4: | 331 | &entry->type_def.addrsel->list4) |
277 | if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, | 332 | netlbl_domhsh_audit_add(entry, iter4, NULL, |
278 | entry->domain) != 0) | 333 | ret_val, audit_info); |
279 | BUG(); | 334 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
280 | break; | 335 | netlbl_af6list_foreach_rcu(iter6, |
336 | &entry->type_def.addrsel->list6) | ||
337 | netlbl_domhsh_audit_add(entry, NULL, iter6, | ||
338 | ret_val, audit_info); | ||
339 | #endif /* IPv6 */ | ||
340 | } else | ||
341 | netlbl_domhsh_audit_add(entry, NULL, NULL, | ||
342 | ret_val, audit_info); | ||
343 | } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT && | ||
344 | entry->type == NETLBL_NLTYPE_ADDRSELECT) { | ||
345 | struct list_head *old_list4; | ||
346 | struct list_head *old_list6; | ||
347 | |||
348 | old_list4 = &entry_old->type_def.addrsel->list4; | ||
349 | old_list6 = &entry_old->type_def.addrsel->list6; | ||
350 | |||
351 | /* we only allow the addition of address selectors if all of | ||
352 | * the selectors do not exist in the existing domain map */ | ||
353 | netlbl_af4list_foreach_rcu(iter4, | ||
354 | &entry->type_def.addrsel->list4) | ||
355 | if (netlbl_af4list_search_exact(iter4->addr, | ||
356 | iter4->mask, | ||
357 | old_list4)) { | ||
358 | ret_val = -EEXIST; | ||
359 | goto add_return; | ||
360 | } | ||
361 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
362 | netlbl_af6list_foreach_rcu(iter6, | ||
363 | &entry->type_def.addrsel->list6) | ||
364 | if (netlbl_af6list_search_exact(&iter6->addr, | ||
365 | &iter6->mask, | ||
366 | old_list6)) { | ||
367 | ret_val = -EEXIST; | ||
368 | goto add_return; | ||
369 | } | ||
370 | #endif /* IPv6 */ | ||
371 | |||
372 | netlbl_af4list_foreach_safe(iter4, tmp4, | ||
373 | &entry->type_def.addrsel->list4) { | ||
374 | netlbl_af4list_remove_entry(iter4); | ||
375 | iter4->valid = 1; | ||
376 | ret_val = netlbl_af4list_add(iter4, old_list4); | ||
377 | netlbl_domhsh_audit_add(entry_old, iter4, NULL, | ||
378 | ret_val, audit_info); | ||
379 | if (ret_val != 0) | ||
380 | goto add_return; | ||
281 | } | 381 | } |
282 | } | 382 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
383 | netlbl_af6list_foreach_safe(iter6, tmp6, | ||
384 | &entry->type_def.addrsel->list6) { | ||
385 | netlbl_af6list_remove_entry(iter6); | ||
386 | iter6->valid = 1; | ||
387 | ret_val = netlbl_af6list_add(iter6, old_list6); | ||
388 | netlbl_domhsh_audit_add(entry_old, NULL, iter6, | ||
389 | ret_val, audit_info); | ||
390 | if (ret_val != 0) | ||
391 | goto add_return; | ||
392 | } | ||
393 | #endif /* IPv6 */ | ||
394 | } else | ||
395 | ret_val = -EINVAL; | ||
283 | 396 | ||
397 | add_return: | ||
398 | spin_unlock(&netlbl_domhsh_lock); | ||
399 | rcu_read_unlock(); | ||
284 | return ret_val; | 400 | return ret_val; |
285 | } | 401 | } |
286 | 402 | ||
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, | |||
302 | } | 418 | } |
303 | 419 | ||
304 | /** | 420 | /** |
305 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | 421 | * netlbl_domhsh_remove_entry - Removes a given entry from the domain table |
306 | * @domain: the domain to remove | 422 | * @entry: the entry to remove |
307 | * @audit_info: NetLabel audit information | 423 | * @audit_info: NetLabel audit information |
308 | * | 424 | * |
309 | * Description: | 425 | * Description: |
310 | * Removes an entry from the domain hash table and handles any updates to the | 426 | * Removes an entry from the domain hash table and handles any updates to the |
311 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | 427 | * lower level protocol handler (i.e. CIPSO). Caller is responsible for |
312 | * negative on failure. | 428 | * ensuring that the RCU read lock is held. Returns zero on success, negative |
429 | * on failure. | ||
313 | * | 430 | * |
314 | */ | 431 | */ |
315 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | 432 | int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, |
433 | struct netlbl_audit *audit_info) | ||
316 | { | 434 | { |
317 | int ret_val = -ENOENT; | 435 | int ret_val = 0; |
318 | struct netlbl_dom_map *entry; | ||
319 | struct audit_buffer *audit_buf; | 436 | struct audit_buffer *audit_buf; |
320 | 437 | ||
321 | rcu_read_lock(); | ||
322 | if (domain) | ||
323 | entry = netlbl_domhsh_search(domain); | ||
324 | else | ||
325 | entry = netlbl_domhsh_search_def(domain); | ||
326 | if (entry == NULL) | 438 | if (entry == NULL) |
327 | goto remove_return; | 439 | return -ENOENT; |
328 | switch (entry->type) { | 440 | |
329 | case NETLBL_NLTYPE_CIPSOV4: | ||
330 | cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, | ||
331 | entry->domain); | ||
332 | break; | ||
333 | } | ||
334 | spin_lock(&netlbl_domhsh_lock); | 441 | spin_lock(&netlbl_domhsh_lock); |
335 | if (entry->valid) { | 442 | if (entry->valid) { |
336 | entry->valid = 0; | 443 | entry->valid = 0; |
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | |||
338 | list_del_rcu(&entry->list); | 445 | list_del_rcu(&entry->list); |
339 | else | 446 | else |
340 | rcu_assign_pointer(netlbl_domhsh_def, NULL); | 447 | rcu_assign_pointer(netlbl_domhsh_def, NULL); |
341 | ret_val = 0; | 448 | } else |
342 | } | 449 | ret_val = -ENOENT; |
343 | spin_unlock(&netlbl_domhsh_lock); | 450 | spin_unlock(&netlbl_domhsh_lock); |
344 | 451 | ||
345 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); | 452 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); |
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | |||
351 | audit_log_end(audit_buf); | 458 | audit_log_end(audit_buf); |
352 | } | 459 | } |
353 | 460 | ||
354 | remove_return: | 461 | if (ret_val == 0) { |
355 | rcu_read_unlock(); | 462 | struct netlbl_af4list *iter4; |
356 | if (ret_val == 0) | 463 | struct netlbl_domaddr4_map *map4; |
464 | |||
465 | switch (entry->type) { | ||
466 | case NETLBL_NLTYPE_ADDRSELECT: | ||
467 | netlbl_af4list_foreach_rcu(iter4, | ||
468 | &entry->type_def.addrsel->list4) { | ||
469 | map4 = netlbl_domhsh_addr4_entry(iter4); | ||
470 | cipso_v4_doi_putdef(map4->type_def.cipsov4); | ||
471 | } | ||
472 | /* no need to check the IPv6 list since we currently | ||
473 | * support only unlabeled protocols for IPv6 */ | ||
474 | break; | ||
475 | case NETLBL_NLTYPE_CIPSOV4: | ||
476 | cipso_v4_doi_putdef(entry->type_def.cipsov4); | ||
477 | break; | ||
478 | } | ||
357 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); | 479 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); |
480 | } | ||
481 | |||
482 | return ret_val; | ||
483 | } | ||
484 | |||
485 | /** | ||
486 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | ||
487 | * @domain: the domain to remove | ||
488 | * @audit_info: NetLabel audit information | ||
489 | * | ||
490 | * Description: | ||
491 | * Removes an entry from the domain hash table and handles any updates to the | ||
492 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | ||
493 | * negative on failure. | ||
494 | * | ||
495 | */ | ||
496 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | ||
497 | { | ||
498 | int ret_val; | ||
499 | struct netlbl_dom_map *entry; | ||
500 | |||
501 | rcu_read_lock(); | ||
502 | if (domain) | ||
503 | entry = netlbl_domhsh_search(domain); | ||
504 | else | ||
505 | entry = netlbl_domhsh_search_def(domain); | ||
506 | ret_val = netlbl_domhsh_remove_entry(entry, audit_info); | ||
507 | rcu_read_unlock(); | ||
508 | |||
358 | return ret_val; | 509 | return ret_val; |
359 | } | 510 | } |
360 | 511 | ||
@@ -389,6 +540,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) | |||
389 | } | 540 | } |
390 | 541 | ||
391 | /** | 542 | /** |
543 | * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table | ||
544 | * @domain: the domain name to search for | ||
545 | * @addr: the IP address to search for | ||
546 | * | ||
547 | * Description: | ||
548 | * Look through the domain hash table searching for an entry to match @domain | ||
549 | * and @addr, return a pointer to a copy of the entry or NULL. The caller is | ||
550 | * responsible for ensuring that rcu_read_[un]lock() is called. | ||
551 | * | ||
552 | */ | ||
553 | struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, | ||
554 | __be32 addr) | ||
555 | { | ||
556 | struct netlbl_dom_map *dom_iter; | ||
557 | struct netlbl_af4list *addr_iter; | ||
558 | |||
559 | dom_iter = netlbl_domhsh_search_def(domain); | ||
560 | if (dom_iter == NULL) | ||
561 | return NULL; | ||
562 | if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) | ||
563 | return NULL; | ||
564 | |||
565 | addr_iter = netlbl_af4list_search(addr, | ||
566 | &dom_iter->type_def.addrsel->list4); | ||
567 | if (addr_iter == NULL) | ||
568 | return NULL; | ||
569 | |||
570 | return netlbl_domhsh_addr4_entry(addr_iter); | ||
571 | } | ||
572 | |||
573 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
574 | /** | ||
575 | * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table | ||
576 | * @domain: the domain name to search for | ||
577 | * @addr: the IP address to search for | ||
578 | * | ||
579 | * Description: | ||
580 | * Look through the domain hash table searching for an entry to match @domain | ||
581 | * and @addr, return a pointer to a copy of the entry or NULL. The caller is | ||
582 | * responsible for ensuring that rcu_read_[un]lock() is called. | ||
583 | * | ||
584 | */ | ||
585 | struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, | ||
586 | const struct in6_addr *addr) | ||
587 | { | ||
588 | struct netlbl_dom_map *dom_iter; | ||
589 | struct netlbl_af6list *addr_iter; | ||
590 | |||
591 | dom_iter = netlbl_domhsh_search_def(domain); | ||
592 | if (dom_iter == NULL) | ||
593 | return NULL; | ||
594 | if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) | ||
595 | return NULL; | ||
596 | |||
597 | addr_iter = netlbl_af6list_search(addr, | ||
598 | &dom_iter->type_def.addrsel->list6); | ||
599 | if (addr_iter == NULL) | ||
600 | return NULL; | ||
601 | |||
602 | return netlbl_domhsh_addr6_entry(addr_iter); | ||
603 | } | ||
604 | #endif /* IPv6 */ | ||
605 | |||
606 | /** | ||
392 | * netlbl_domhsh_walk - Iterate through the domain mapping hash table | 607 | * netlbl_domhsh_walk - Iterate through the domain mapping hash table |
393 | * @skip_bkt: the number of buckets to skip at the start | 608 | * @skip_bkt: the number of buckets to skip at the start |
394 | * @skip_chain: the number of entries to skip in the first iterated bucket | 609 | * @skip_chain: the number of entries to skip in the first iterated bucket |
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt, | |||
410 | { | 625 | { |
411 | int ret_val = -ENOENT; | 626 | int ret_val = -ENOENT; |
412 | u32 iter_bkt; | 627 | u32 iter_bkt; |
628 | struct list_head *iter_list; | ||
413 | struct netlbl_dom_map *iter_entry; | 629 | struct netlbl_dom_map *iter_entry; |
414 | u32 chain_cnt = 0; | 630 | u32 chain_cnt = 0; |
415 | 631 | ||
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt, | |||
417 | for (iter_bkt = *skip_bkt; | 633 | for (iter_bkt = *skip_bkt; |
418 | iter_bkt < rcu_dereference(netlbl_domhsh)->size; | 634 | iter_bkt < rcu_dereference(netlbl_domhsh)->size; |
419 | iter_bkt++, chain_cnt = 0) { | 635 | iter_bkt++, chain_cnt = 0) { |
420 | list_for_each_entry_rcu(iter_entry, | 636 | iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt]; |
421 | &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt], | 637 | list_for_each_entry_rcu(iter_entry, iter_list, list) |
422 | list) | ||
423 | if (iter_entry->valid) { | 638 | if (iter_entry->valid) { |
424 | if (chain_cnt++ < *skip_chain) | 639 | if (chain_cnt++ < *skip_chain) |
425 | continue; | 640 | continue; |
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index 8220990ceb96..bfcb6763a1a1 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
@@ -36,16 +36,43 @@ | |||
36 | #include <linux/rcupdate.h> | 36 | #include <linux/rcupdate.h> |
37 | #include <linux/list.h> | 37 | #include <linux/list.h> |
38 | 38 | ||
39 | #include "netlabel_addrlist.h" | ||
40 | |||
39 | /* Domain hash table size */ | 41 | /* Domain hash table size */ |
40 | /* XXX - currently this number is an uneducated guess */ | 42 | /* XXX - currently this number is an uneducated guess */ |
41 | #define NETLBL_DOMHSH_BITSIZE 7 | 43 | #define NETLBL_DOMHSH_BITSIZE 7 |
42 | 44 | ||
43 | /* Domain mapping definition struct */ | 45 | /* Domain mapping definition structures */ |
46 | #define netlbl_domhsh_addr4_entry(iter) \ | ||
47 | container_of(iter, struct netlbl_domaddr4_map, list) | ||
48 | struct netlbl_domaddr4_map { | ||
49 | u32 type; | ||
50 | union { | ||
51 | struct cipso_v4_doi *cipsov4; | ||
52 | } type_def; | ||
53 | |||
54 | struct netlbl_af4list list; | ||
55 | }; | ||
56 | #define netlbl_domhsh_addr6_entry(iter) \ | ||
57 | container_of(iter, struct netlbl_domaddr6_map, list) | ||
58 | struct netlbl_domaddr6_map { | ||
59 | u32 type; | ||
60 | |||
61 | /* NOTE: no 'type_def' union needed at present since we don't currently | ||
62 | * support any IPv6 labeling protocols */ | ||
63 | |||
64 | struct netlbl_af6list list; | ||
65 | }; | ||
66 | struct netlbl_domaddr_map { | ||
67 | struct list_head list4; | ||
68 | struct list_head list6; | ||
69 | }; | ||
44 | struct netlbl_dom_map { | 70 | struct netlbl_dom_map { |
45 | char *domain; | 71 | char *domain; |
46 | u32 type; | 72 | u32 type; |
47 | union { | 73 | union { |
48 | struct cipso_v4_doi *cipsov4; | 74 | struct cipso_v4_doi *cipsov4; |
75 | struct netlbl_domaddr_map *addrsel; | ||
49 | } type_def; | 76 | } type_def; |
50 | 77 | ||
51 | u32 valid; | 78 | u32 valid; |
@@ -61,12 +88,21 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, | |||
61 | struct netlbl_audit *audit_info); | 88 | struct netlbl_audit *audit_info); |
62 | int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, | 89 | int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, |
63 | struct netlbl_audit *audit_info); | 90 | struct netlbl_audit *audit_info); |
91 | int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, | ||
92 | struct netlbl_audit *audit_info); | ||
64 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); | 93 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); |
65 | int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); | 94 | int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); |
66 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); | 95 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); |
96 | struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, | ||
97 | __be32 addr); | ||
67 | int netlbl_domhsh_walk(u32 *skip_bkt, | 98 | int netlbl_domhsh_walk(u32 *skip_bkt, |
68 | u32 *skip_chain, | 99 | u32 *skip_chain, |
69 | int (*callback) (struct netlbl_dom_map *entry, void *arg), | 100 | int (*callback) (struct netlbl_dom_map *entry, void *arg), |
70 | void *cb_arg); | 101 | void *cb_arg); |
71 | 102 | ||
103 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
104 | struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, | ||
105 | const struct in6_addr *addr); | ||
106 | #endif /* IPv6 */ | ||
107 | |||
72 | #endif | 108 | #endif |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 39793a1a93aa..b32eceb3ab0d 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
@@ -82,7 +82,7 @@ int netlbl_cfg_unlbl_add_map(const char *domain, | |||
82 | 82 | ||
83 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 83 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
84 | if (entry == NULL) | 84 | if (entry == NULL) |
85 | goto cfg_unlbl_add_map_failure; | 85 | return -ENOMEM; |
86 | if (domain != NULL) { | 86 | if (domain != NULL) { |
87 | entry->domain = kstrdup(domain, GFP_ATOMIC); | 87 | entry->domain = kstrdup(domain, GFP_ATOMIC); |
88 | if (entry->domain == NULL) | 88 | if (entry->domain == NULL) |
@@ -104,49 +104,6 @@ cfg_unlbl_add_map_failure: | |||
104 | } | 104 | } |
105 | 105 | ||
106 | /** | 106 | /** |
107 | * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition | ||
108 | * @doi_def: the DOI definition | ||
109 | * @audit_info: NetLabel audit information | ||
110 | * | ||
111 | * Description: | ||
112 | * Add a new CIPSOv4 DOI definition to the NetLabel subsystem. Returns zero on | ||
113 | * success, negative values on failure. | ||
114 | * | ||
115 | */ | ||
116 | int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, | ||
117 | struct netlbl_audit *audit_info) | ||
118 | { | ||
119 | int ret_val; | ||
120 | const char *type_str; | ||
121 | struct audit_buffer *audit_buf; | ||
122 | |||
123 | ret_val = cipso_v4_doi_add(doi_def); | ||
124 | |||
125 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, | ||
126 | audit_info); | ||
127 | if (audit_buf != NULL) { | ||
128 | switch (doi_def->type) { | ||
129 | case CIPSO_V4_MAP_STD: | ||
130 | type_str = "std"; | ||
131 | break; | ||
132 | case CIPSO_V4_MAP_PASS: | ||
133 | type_str = "pass"; | ||
134 | break; | ||
135 | default: | ||
136 | type_str = "(unknown)"; | ||
137 | } | ||
138 | audit_log_format(audit_buf, | ||
139 | " cipso_doi=%u cipso_type=%s res=%u", | ||
140 | doi_def->doi, | ||
141 | type_str, | ||
142 | ret_val == 0 ? 1 : 0); | ||
143 | audit_log_end(audit_buf); | ||
144 | } | ||
145 | |||
146 | return ret_val; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping | 107 | * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping |
151 | * @doi_def: the DOI definition | 108 | * @doi_def: the DOI definition |
152 | * @domain: the domain mapping to add | 109 | * @domain: the domain mapping to add |
@@ -164,58 +121,71 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | |||
164 | struct netlbl_audit *audit_info) | 121 | struct netlbl_audit *audit_info) |
165 | { | 122 | { |
166 | int ret_val = -ENOMEM; | 123 | int ret_val = -ENOMEM; |
124 | u32 doi; | ||
125 | u32 doi_type; | ||
167 | struct netlbl_dom_map *entry; | 126 | struct netlbl_dom_map *entry; |
127 | const char *type_str; | ||
128 | struct audit_buffer *audit_buf; | ||
129 | |||
130 | doi = doi_def->doi; | ||
131 | doi_type = doi_def->type; | ||
168 | 132 | ||
169 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 133 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
170 | if (entry == NULL) | 134 | if (entry == NULL) |
171 | goto cfg_cipsov4_add_map_failure; | 135 | return -ENOMEM; |
172 | if (domain != NULL) { | 136 | if (domain != NULL) { |
173 | entry->domain = kstrdup(domain, GFP_ATOMIC); | 137 | entry->domain = kstrdup(domain, GFP_ATOMIC); |
174 | if (entry->domain == NULL) | 138 | if (entry->domain == NULL) |
175 | goto cfg_cipsov4_add_map_failure; | 139 | goto cfg_cipsov4_add_map_failure; |
176 | } | 140 | } |
177 | entry->type = NETLBL_NLTYPE_CIPSOV4; | ||
178 | entry->type_def.cipsov4 = doi_def; | ||
179 | |||
180 | /* Grab a RCU read lock here so nothing happens to the doi_def variable | ||
181 | * between adding it to the CIPSOv4 protocol engine and adding a | ||
182 | * domain mapping for it. */ | ||
183 | 141 | ||
184 | rcu_read_lock(); | 142 | ret_val = cipso_v4_doi_add(doi_def); |
185 | ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info); | ||
186 | if (ret_val != 0) | 143 | if (ret_val != 0) |
187 | goto cfg_cipsov4_add_map_failure_unlock; | 144 | goto cfg_cipsov4_add_map_failure_remove_doi; |
145 | entry->type = NETLBL_NLTYPE_CIPSOV4; | ||
146 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi); | ||
147 | if (entry->type_def.cipsov4 == NULL) { | ||
148 | ret_val = -ENOENT; | ||
149 | goto cfg_cipsov4_add_map_failure_remove_doi; | ||
150 | } | ||
188 | ret_val = netlbl_domhsh_add(entry, audit_info); | 151 | ret_val = netlbl_domhsh_add(entry, audit_info); |
189 | if (ret_val != 0) | 152 | if (ret_val != 0) |
190 | goto cfg_cipsov4_add_map_failure_remove_doi; | 153 | goto cfg_cipsov4_add_map_failure_release_doi; |
191 | rcu_read_unlock(); | ||
192 | 154 | ||
193 | return 0; | 155 | cfg_cipsov4_add_map_return: |
156 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, | ||
157 | audit_info); | ||
158 | if (audit_buf != NULL) { | ||
159 | switch (doi_type) { | ||
160 | case CIPSO_V4_MAP_TRANS: | ||
161 | type_str = "trans"; | ||
162 | break; | ||
163 | case CIPSO_V4_MAP_PASS: | ||
164 | type_str = "pass"; | ||
165 | break; | ||
166 | case CIPSO_V4_MAP_LOCAL: | ||
167 | type_str = "local"; | ||
168 | break; | ||
169 | default: | ||
170 | type_str = "(unknown)"; | ||
171 | } | ||
172 | audit_log_format(audit_buf, | ||
173 | " cipso_doi=%u cipso_type=%s res=%u", | ||
174 | doi, type_str, ret_val == 0 ? 1 : 0); | ||
175 | audit_log_end(audit_buf); | ||
176 | } | ||
194 | 177 | ||
178 | return ret_val; | ||
179 | |||
180 | cfg_cipsov4_add_map_failure_release_doi: | ||
181 | cipso_v4_doi_putdef(doi_def); | ||
195 | cfg_cipsov4_add_map_failure_remove_doi: | 182 | cfg_cipsov4_add_map_failure_remove_doi: |
196 | cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free); | 183 | cipso_v4_doi_remove(doi, audit_info); |
197 | cfg_cipsov4_add_map_failure_unlock: | ||
198 | rcu_read_unlock(); | ||
199 | cfg_cipsov4_add_map_failure: | 184 | cfg_cipsov4_add_map_failure: |
200 | if (entry != NULL) | 185 | if (entry != NULL) |
201 | kfree(entry->domain); | 186 | kfree(entry->domain); |
202 | kfree(entry); | 187 | kfree(entry); |
203 | return ret_val; | 188 | goto cfg_cipsov4_add_map_return; |
204 | } | ||
205 | |||
206 | /** | ||
207 | * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition | ||
208 | * @doi: the CIPSO DOI value | ||
209 | * @audit_info: NetLabel audit information | ||
210 | * | ||
211 | * Description: | ||
212 | * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem. | ||
213 | * Returns zero on success, negative values on failure. | ||
214 | * | ||
215 | */ | ||
216 | int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info) | ||
217 | { | ||
218 | return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free); | ||
219 | } | 189 | } |
220 | 190 | ||
221 | /* | 191 | /* |
@@ -452,7 +422,9 @@ int netlbl_enabled(void) | |||
452 | * Attach the correct label to the given socket using the security attributes | 422 | * Attach the correct label to the given socket using the security attributes |
453 | * specified in @secattr. This function requires exclusive access to @sk, | 423 | * specified in @secattr. This function requires exclusive access to @sk, |
454 | * which means it either needs to be in the process of being created or locked. | 424 | * which means it either needs to be in the process of being created or locked. |
455 | * Returns zero on success, negative values on failure. | 425 | * Returns zero on success, -EDESTADDRREQ if the domain is configured to use |
426 | * network address selectors (can't blindly label the socket), and negative | ||
427 | * values on all other failures. | ||
456 | * | 428 | * |
457 | */ | 429 | */ |
458 | int netlbl_sock_setattr(struct sock *sk, | 430 | int netlbl_sock_setattr(struct sock *sk, |
@@ -466,6 +438,9 @@ int netlbl_sock_setattr(struct sock *sk, | |||
466 | if (dom_entry == NULL) | 438 | if (dom_entry == NULL) |
467 | goto socket_setattr_return; | 439 | goto socket_setattr_return; |
468 | switch (dom_entry->type) { | 440 | switch (dom_entry->type) { |
441 | case NETLBL_NLTYPE_ADDRSELECT: | ||
442 | ret_val = -EDESTADDRREQ; | ||
443 | break; | ||
469 | case NETLBL_NLTYPE_CIPSOV4: | 444 | case NETLBL_NLTYPE_CIPSOV4: |
470 | ret_val = cipso_v4_sock_setattr(sk, | 445 | ret_val = cipso_v4_sock_setattr(sk, |
471 | dom_entry->type_def.cipsov4, | 446 | dom_entry->type_def.cipsov4, |
@@ -484,6 +459,20 @@ socket_setattr_return: | |||
484 | } | 459 | } |
485 | 460 | ||
486 | /** | 461 | /** |
462 | * netlbl_sock_delattr - Delete all the NetLabel labels on a socket | ||
463 | * @sk: the socket | ||
464 | * | ||
465 | * Description: | ||
466 | * Remove all the NetLabel labeling from @sk. The caller is responsible for | ||
467 | * ensuring that @sk is locked. | ||
468 | * | ||
469 | */ | ||
470 | void netlbl_sock_delattr(struct sock *sk) | ||
471 | { | ||
472 | cipso_v4_sock_delattr(sk); | ||
473 | } | ||
474 | |||
475 | /** | ||
487 | * netlbl_sock_getattr - Determine the security attributes of a sock | 476 | * netlbl_sock_getattr - Determine the security attributes of a sock |
488 | * @sk: the sock | 477 | * @sk: the sock |
489 | * @secattr: the security attributes | 478 | * @secattr: the security attributes |
@@ -501,6 +490,128 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | |||
501 | } | 490 | } |
502 | 491 | ||
503 | /** | 492 | /** |
493 | * netlbl_conn_setattr - Label a connected socket using the correct protocol | ||
494 | * @sk: the socket to label | ||
495 | * @addr: the destination address | ||
496 | * @secattr: the security attributes | ||
497 | * | ||
498 | * Description: | ||
499 | * Attach the correct label to the given connected socket using the security | ||
500 | * attributes specified in @secattr. The caller is responsible for ensuring | ||
501 | * that @sk is locked. Returns zero on success, negative values on failure. | ||
502 | * | ||
503 | */ | ||
504 | int netlbl_conn_setattr(struct sock *sk, | ||
505 | struct sockaddr *addr, | ||
506 | const struct netlbl_lsm_secattr *secattr) | ||
507 | { | ||
508 | int ret_val; | ||
509 | struct sockaddr_in *addr4; | ||
510 | struct netlbl_domaddr4_map *af4_entry; | ||
511 | |||
512 | rcu_read_lock(); | ||
513 | switch (addr->sa_family) { | ||
514 | case AF_INET: | ||
515 | addr4 = (struct sockaddr_in *)addr; | ||
516 | af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, | ||
517 | addr4->sin_addr.s_addr); | ||
518 | if (af4_entry == NULL) { | ||
519 | ret_val = -ENOENT; | ||
520 | goto conn_setattr_return; | ||
521 | } | ||
522 | switch (af4_entry->type) { | ||
523 | case NETLBL_NLTYPE_CIPSOV4: | ||
524 | ret_val = cipso_v4_sock_setattr(sk, | ||
525 | af4_entry->type_def.cipsov4, | ||
526 | secattr); | ||
527 | break; | ||
528 | case NETLBL_NLTYPE_UNLABELED: | ||
529 | /* just delete the protocols we support for right now | ||
530 | * but we could remove other protocols if needed */ | ||
531 | cipso_v4_sock_delattr(sk); | ||
532 | ret_val = 0; | ||
533 | break; | ||
534 | default: | ||
535 | ret_val = -ENOENT; | ||
536 | } | ||
537 | break; | ||
538 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
539 | case AF_INET6: | ||
540 | /* since we don't support any IPv6 labeling protocols right | ||
541 | * now we can optimize everything away until we do */ | ||
542 | ret_val = 0; | ||
543 | break; | ||
544 | #endif /* IPv6 */ | ||
545 | default: | ||
546 | ret_val = 0; | ||
547 | } | ||
548 | |||
549 | conn_setattr_return: | ||
550 | rcu_read_unlock(); | ||
551 | return ret_val; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * netlbl_skbuff_setattr - Label a packet using the correct protocol | ||
556 | * @skb: the packet | ||
557 | * @family: protocol family | ||
558 | * @secattr: the security attributes | ||
559 | * | ||
560 | * Description: | ||
561 | * Attach the correct label to the given packet using the security attributes | ||
562 | * specified in @secattr. Returns zero on success, negative values on failure. | ||
563 | * | ||
564 | */ | ||
565 | int netlbl_skbuff_setattr(struct sk_buff *skb, | ||
566 | u16 family, | ||
567 | const struct netlbl_lsm_secattr *secattr) | ||
568 | { | ||
569 | int ret_val; | ||
570 | struct iphdr *hdr4; | ||
571 | struct netlbl_domaddr4_map *af4_entry; | ||
572 | |||
573 | rcu_read_lock(); | ||
574 | switch (family) { | ||
575 | case AF_INET: | ||
576 | hdr4 = ip_hdr(skb); | ||
577 | af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, | ||
578 | hdr4->daddr); | ||
579 | if (af4_entry == NULL) { | ||
580 | ret_val = -ENOENT; | ||
581 | goto skbuff_setattr_return; | ||
582 | } | ||
583 | switch (af4_entry->type) { | ||
584 | case NETLBL_NLTYPE_CIPSOV4: | ||
585 | ret_val = cipso_v4_skbuff_setattr(skb, | ||
586 | af4_entry->type_def.cipsov4, | ||
587 | secattr); | ||
588 | break; | ||
589 | case NETLBL_NLTYPE_UNLABELED: | ||
590 | /* just delete the protocols we support for right now | ||
591 | * but we could remove other protocols if needed */ | ||
592 | ret_val = cipso_v4_skbuff_delattr(skb); | ||
593 | break; | ||
594 | default: | ||
595 | ret_val = -ENOENT; | ||
596 | } | ||
597 | break; | ||
598 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
599 | case AF_INET6: | ||
600 | /* since we don't support any IPv6 labeling protocols right | ||
601 | * now we can optimize everything away until we do */ | ||
602 | ret_val = 0; | ||
603 | break; | ||
604 | #endif /* IPv6 */ | ||
605 | default: | ||
606 | ret_val = 0; | ||
607 | } | ||
608 | |||
609 | skbuff_setattr_return: | ||
610 | rcu_read_unlock(); | ||
611 | return ret_val; | ||
612 | } | ||
613 | |||
614 | /** | ||
504 | * netlbl_skbuff_getattr - Determine the security attributes of a packet | 615 | * netlbl_skbuff_getattr - Determine the security attributes of a packet |
505 | * @skb: the packet | 616 | * @skb: the packet |
506 | * @family: protocol family | 617 | * @family: protocol family |
@@ -528,6 +639,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, | |||
528 | * netlbl_skbuff_err - Handle a LSM error on a sk_buff | 639 | * netlbl_skbuff_err - Handle a LSM error on a sk_buff |
529 | * @skb: the packet | 640 | * @skb: the packet |
530 | * @error: the error code | 641 | * @error: the error code |
642 | * @gateway: true if host is acting as a gateway, false otherwise | ||
531 | * | 643 | * |
532 | * Description: | 644 | * Description: |
533 | * Deal with a LSM problem when handling the packet in @skb, typically this is | 645 | * Deal with a LSM problem when handling the packet in @skb, typically this is |
@@ -535,10 +647,10 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, | |||
535 | * according to the packet's labeling protocol. | 647 | * according to the packet's labeling protocol. |
536 | * | 648 | * |
537 | */ | 649 | */ |
538 | void netlbl_skbuff_err(struct sk_buff *skb, int error) | 650 | void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) |
539 | { | 651 | { |
540 | if (CIPSO_V4_OPTEXIST(skb)) | 652 | if (CIPSO_V4_OPTEXIST(skb)) |
541 | cipso_v4_error(skb, error, 0); | 653 | cipso_v4_error(skb, error, gateway); |
542 | } | 654 | } |
543 | 655 | ||
544 | /** | 656 | /** |
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 44be5d5261f4..ee769ecaa13c 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
@@ -32,9 +32,13 @@ | |||
32 | #include <linux/socket.h> | 32 | #include <linux/socket.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
35 | #include <linux/in.h> | ||
36 | #include <linux/in6.h> | ||
35 | #include <net/sock.h> | 37 | #include <net/sock.h> |
36 | #include <net/netlink.h> | 38 | #include <net/netlink.h> |
37 | #include <net/genetlink.h> | 39 | #include <net/genetlink.h> |
40 | #include <net/ip.h> | ||
41 | #include <net/ipv6.h> | ||
38 | #include <net/netlabel.h> | 42 | #include <net/netlabel.h> |
39 | #include <net/cipso_ipv4.h> | 43 | #include <net/cipso_ipv4.h> |
40 | #include <asm/atomic.h> | 44 | #include <asm/atomic.h> |
@@ -71,86 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { | |||
71 | }; | 75 | }; |
72 | 76 | ||
73 | /* | 77 | /* |
74 | * NetLabel Command Handlers | 78 | * Helper Functions |
75 | */ | 79 | */ |
76 | 80 | ||
77 | /** | 81 | /** |
78 | * netlbl_mgmt_add - Handle an ADD message | 82 | * netlbl_mgmt_add - Handle an ADD message |
79 | * @skb: the NETLINK buffer | ||
80 | * @info: the Generic NETLINK info block | 83 | * @info: the Generic NETLINK info block |
84 | * @audit_info: NetLabel audit information | ||
81 | * | 85 | * |
82 | * Description: | 86 | * Description: |
83 | * Process a user generated ADD message and add the domains from the message | 87 | * Helper function for the ADD and ADDDEF messages to add the domain mappings |
84 | * to the hash table. See netlabel.h for a description of the message format. | 88 | * from the message to the hash table. See netlabel.h for a description of the |
85 | * Returns zero on success, negative values on failure. | 89 | * message format. Returns zero on success, negative values on failure. |
86 | * | 90 | * |
87 | */ | 91 | */ |
88 | static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) | 92 | static int netlbl_mgmt_add_common(struct genl_info *info, |
93 | struct netlbl_audit *audit_info) | ||
89 | { | 94 | { |
90 | int ret_val = -EINVAL; | 95 | int ret_val = -EINVAL; |
91 | struct netlbl_dom_map *entry = NULL; | 96 | struct netlbl_dom_map *entry = NULL; |
92 | size_t tmp_size; | 97 | struct netlbl_domaddr_map *addrmap = NULL; |
98 | struct cipso_v4_doi *cipsov4 = NULL; | ||
93 | u32 tmp_val; | 99 | u32 tmp_val; |
94 | struct netlbl_audit audit_info; | ||
95 | |||
96 | if (!info->attrs[NLBL_MGMT_A_DOMAIN] || | ||
97 | !info->attrs[NLBL_MGMT_A_PROTOCOL]) | ||
98 | goto add_failure; | ||
99 | |||
100 | netlbl_netlink_auditinfo(skb, &audit_info); | ||
101 | 100 | ||
102 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 101 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
103 | if (entry == NULL) { | 102 | if (entry == NULL) { |
104 | ret_val = -ENOMEM; | 103 | ret_val = -ENOMEM; |
105 | goto add_failure; | 104 | goto add_failure; |
106 | } | 105 | } |
107 | tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); | ||
108 | entry->domain = kmalloc(tmp_size, GFP_KERNEL); | ||
109 | if (entry->domain == NULL) { | ||
110 | ret_val = -ENOMEM; | ||
111 | goto add_failure; | ||
112 | } | ||
113 | entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); | 106 | entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); |
114 | nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); | 107 | if (info->attrs[NLBL_MGMT_A_DOMAIN]) { |
108 | size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); | ||
109 | entry->domain = kmalloc(tmp_size, GFP_KERNEL); | ||
110 | if (entry->domain == NULL) { | ||
111 | ret_val = -ENOMEM; | ||
112 | goto add_failure; | ||
113 | } | ||
114 | nla_strlcpy(entry->domain, | ||
115 | info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); | ||
116 | } | ||
117 | |||
118 | /* NOTE: internally we allow/use a entry->type value of | ||
119 | * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users | ||
120 | * to pass that as a protocol value because we need to know the | ||
121 | * "real" protocol */ | ||
115 | 122 | ||
116 | switch (entry->type) { | 123 | switch (entry->type) { |
117 | case NETLBL_NLTYPE_UNLABELED: | 124 | case NETLBL_NLTYPE_UNLABELED: |
118 | ret_val = netlbl_domhsh_add(entry, &audit_info); | ||
119 | break; | 125 | break; |
120 | case NETLBL_NLTYPE_CIPSOV4: | 126 | case NETLBL_NLTYPE_CIPSOV4: |
121 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) | 127 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) |
122 | goto add_failure; | 128 | goto add_failure; |
123 | 129 | ||
124 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); | 130 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); |
125 | /* We should be holding a rcu_read_lock() here while we hold | 131 | cipsov4 = cipso_v4_doi_getdef(tmp_val); |
126 | * the result but since the entry will always be deleted when | 132 | if (cipsov4 == NULL) |
127 | * the CIPSO DOI is deleted we aren't going to keep the | ||
128 | * lock. */ | ||
129 | rcu_read_lock(); | ||
130 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); | ||
131 | if (entry->type_def.cipsov4 == NULL) { | ||
132 | rcu_read_unlock(); | ||
133 | goto add_failure; | 133 | goto add_failure; |
134 | } | 134 | entry->type_def.cipsov4 = cipsov4; |
135 | ret_val = netlbl_domhsh_add(entry, &audit_info); | ||
136 | rcu_read_unlock(); | ||
137 | break; | 135 | break; |
138 | default: | 136 | default: |
139 | goto add_failure; | 137 | goto add_failure; |
140 | } | 138 | } |
139 | |||
140 | if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { | ||
141 | struct in_addr *addr; | ||
142 | struct in_addr *mask; | ||
143 | struct netlbl_domaddr4_map *map; | ||
144 | |||
145 | addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); | ||
146 | if (addrmap == NULL) { | ||
147 | ret_val = -ENOMEM; | ||
148 | goto add_failure; | ||
149 | } | ||
150 | INIT_LIST_HEAD(&addrmap->list4); | ||
151 | INIT_LIST_HEAD(&addrmap->list6); | ||
152 | |||
153 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != | ||
154 | sizeof(struct in_addr)) { | ||
155 | ret_val = -EINVAL; | ||
156 | goto add_failure; | ||
157 | } | ||
158 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != | ||
159 | sizeof(struct in_addr)) { | ||
160 | ret_val = -EINVAL; | ||
161 | goto add_failure; | ||
162 | } | ||
163 | addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); | ||
164 | mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); | ||
165 | |||
166 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
167 | if (map == NULL) { | ||
168 | ret_val = -ENOMEM; | ||
169 | goto add_failure; | ||
170 | } | ||
171 | map->list.addr = addr->s_addr & mask->s_addr; | ||
172 | map->list.mask = mask->s_addr; | ||
173 | map->list.valid = 1; | ||
174 | map->type = entry->type; | ||
175 | if (cipsov4) | ||
176 | map->type_def.cipsov4 = cipsov4; | ||
177 | |||
178 | ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); | ||
179 | if (ret_val != 0) { | ||
180 | kfree(map); | ||
181 | goto add_failure; | ||
182 | } | ||
183 | |||
184 | entry->type = NETLBL_NLTYPE_ADDRSELECT; | ||
185 | entry->type_def.addrsel = addrmap; | ||
186 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
187 | } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { | ||
188 | struct in6_addr *addr; | ||
189 | struct in6_addr *mask; | ||
190 | struct netlbl_domaddr6_map *map; | ||
191 | |||
192 | addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); | ||
193 | if (addrmap == NULL) { | ||
194 | ret_val = -ENOMEM; | ||
195 | goto add_failure; | ||
196 | } | ||
197 | INIT_LIST_HEAD(&addrmap->list4); | ||
198 | INIT_LIST_HEAD(&addrmap->list6); | ||
199 | |||
200 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != | ||
201 | sizeof(struct in6_addr)) { | ||
202 | ret_val = -EINVAL; | ||
203 | goto add_failure; | ||
204 | } | ||
205 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != | ||
206 | sizeof(struct in6_addr)) { | ||
207 | ret_val = -EINVAL; | ||
208 | goto add_failure; | ||
209 | } | ||
210 | addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); | ||
211 | mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); | ||
212 | |||
213 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
214 | if (map == NULL) { | ||
215 | ret_val = -ENOMEM; | ||
216 | goto add_failure; | ||
217 | } | ||
218 | ipv6_addr_copy(&map->list.addr, addr); | ||
219 | map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; | ||
220 | map->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; | ||
221 | map->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; | ||
222 | map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; | ||
223 | ipv6_addr_copy(&map->list.mask, mask); | ||
224 | map->list.valid = 1; | ||
225 | map->type = entry->type; | ||
226 | |||
227 | ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); | ||
228 | if (ret_val != 0) { | ||
229 | kfree(map); | ||
230 | goto add_failure; | ||
231 | } | ||
232 | |||
233 | entry->type = NETLBL_NLTYPE_ADDRSELECT; | ||
234 | entry->type_def.addrsel = addrmap; | ||
235 | #endif /* IPv6 */ | ||
236 | } | ||
237 | |||
238 | ret_val = netlbl_domhsh_add(entry, audit_info); | ||
141 | if (ret_val != 0) | 239 | if (ret_val != 0) |
142 | goto add_failure; | 240 | goto add_failure; |
143 | 241 | ||
144 | return 0; | 242 | return 0; |
145 | 243 | ||
146 | add_failure: | 244 | add_failure: |
245 | if (cipsov4) | ||
246 | cipso_v4_doi_putdef(cipsov4); | ||
147 | if (entry) | 247 | if (entry) |
148 | kfree(entry->domain); | 248 | kfree(entry->domain); |
249 | kfree(addrmap); | ||
149 | kfree(entry); | 250 | kfree(entry); |
150 | return ret_val; | 251 | return ret_val; |
151 | } | 252 | } |
152 | 253 | ||
153 | /** | 254 | /** |
255 | * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry | ||
256 | * @skb: the NETLINK buffer | ||
257 | * @entry: the map entry | ||
258 | * | ||
259 | * Description: | ||
260 | * This function is a helper function used by the LISTALL and LISTDEF command | ||
261 | * handlers. The caller is responsibile for ensuring that the RCU read lock | ||
262 | * is held. Returns zero on success, negative values on failure. | ||
263 | * | ||
264 | */ | ||
265 | static int netlbl_mgmt_listentry(struct sk_buff *skb, | ||
266 | struct netlbl_dom_map *entry) | ||
267 | { | ||
268 | int ret_val; | ||
269 | struct nlattr *nla_a; | ||
270 | struct nlattr *nla_b; | ||
271 | struct netlbl_af4list *iter4; | ||
272 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
273 | struct netlbl_af6list *iter6; | ||
274 | #endif | ||
275 | |||
276 | if (entry->domain != NULL) { | ||
277 | ret_val = nla_put_string(skb, | ||
278 | NLBL_MGMT_A_DOMAIN, entry->domain); | ||
279 | if (ret_val != 0) | ||
280 | return ret_val; | ||
281 | } | ||
282 | |||
283 | switch (entry->type) { | ||
284 | case NETLBL_NLTYPE_ADDRSELECT: | ||
285 | nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); | ||
286 | if (nla_a == NULL) | ||
287 | return -ENOMEM; | ||
288 | |||
289 | netlbl_af4list_foreach_rcu(iter4, | ||
290 | &entry->type_def.addrsel->list4) { | ||
291 | struct netlbl_domaddr4_map *map4; | ||
292 | struct in_addr addr_struct; | ||
293 | |||
294 | nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); | ||
295 | if (nla_b == NULL) | ||
296 | return -ENOMEM; | ||
297 | |||
298 | addr_struct.s_addr = iter4->addr; | ||
299 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR, | ||
300 | sizeof(struct in_addr), | ||
301 | &addr_struct); | ||
302 | if (ret_val != 0) | ||
303 | return ret_val; | ||
304 | addr_struct.s_addr = iter4->mask; | ||
305 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK, | ||
306 | sizeof(struct in_addr), | ||
307 | &addr_struct); | ||
308 | if (ret_val != 0) | ||
309 | return ret_val; | ||
310 | map4 = netlbl_domhsh_addr4_entry(iter4); | ||
311 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, | ||
312 | map4->type); | ||
313 | if (ret_val != 0) | ||
314 | return ret_val; | ||
315 | switch (map4->type) { | ||
316 | case NETLBL_NLTYPE_CIPSOV4: | ||
317 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, | ||
318 | map4->type_def.cipsov4->doi); | ||
319 | if (ret_val != 0) | ||
320 | return ret_val; | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | nla_nest_end(skb, nla_b); | ||
325 | } | ||
326 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
327 | netlbl_af6list_foreach_rcu(iter6, | ||
328 | &entry->type_def.addrsel->list6) { | ||
329 | struct netlbl_domaddr6_map *map6; | ||
330 | |||
331 | nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); | ||
332 | if (nla_b == NULL) | ||
333 | return -ENOMEM; | ||
334 | |||
335 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR, | ||
336 | sizeof(struct in6_addr), | ||
337 | &iter6->addr); | ||
338 | if (ret_val != 0) | ||
339 | return ret_val; | ||
340 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK, | ||
341 | sizeof(struct in6_addr), | ||
342 | &iter6->mask); | ||
343 | if (ret_val != 0) | ||
344 | return ret_val; | ||
345 | map6 = netlbl_domhsh_addr6_entry(iter6); | ||
346 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, | ||
347 | map6->type); | ||
348 | if (ret_val != 0) | ||
349 | return ret_val; | ||
350 | |||
351 | nla_nest_end(skb, nla_b); | ||
352 | } | ||
353 | #endif /* IPv6 */ | ||
354 | |||
355 | nla_nest_end(skb, nla_a); | ||
356 | break; | ||
357 | case NETLBL_NLTYPE_UNLABELED: | ||
358 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); | ||
359 | break; | ||
360 | case NETLBL_NLTYPE_CIPSOV4: | ||
361 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); | ||
362 | if (ret_val != 0) | ||
363 | return ret_val; | ||
364 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, | ||
365 | entry->type_def.cipsov4->doi); | ||
366 | break; | ||
367 | } | ||
368 | |||
369 | return ret_val; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * NetLabel Command Handlers | ||
374 | */ | ||
375 | |||
376 | /** | ||
377 | * netlbl_mgmt_add - Handle an ADD message | ||
378 | * @skb: the NETLINK buffer | ||
379 | * @info: the Generic NETLINK info block | ||
380 | * | ||
381 | * Description: | ||
382 | * Process a user generated ADD message and add the domains from the message | ||
383 | * to the hash table. See netlabel.h for a description of the message format. | ||
384 | * Returns zero on success, negative values on failure. | ||
385 | * | ||
386 | */ | ||
387 | static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) | ||
388 | { | ||
389 | struct netlbl_audit audit_info; | ||
390 | |||
391 | if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || | ||
392 | (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || | ||
393 | (info->attrs[NLBL_MGMT_A_IPV4ADDR] && | ||
394 | info->attrs[NLBL_MGMT_A_IPV6ADDR]) || | ||
395 | (info->attrs[NLBL_MGMT_A_IPV4MASK] && | ||
396 | info->attrs[NLBL_MGMT_A_IPV6MASK]) || | ||
397 | ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ | ||
398 | (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || | ||
399 | ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ | ||
400 | (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) | ||
401 | return -EINVAL; | ||
402 | |||
403 | netlbl_netlink_auditinfo(skb, &audit_info); | ||
404 | |||
405 | return netlbl_mgmt_add_common(info, &audit_info); | ||
406 | } | ||
407 | |||
408 | /** | ||
154 | * netlbl_mgmt_remove - Handle a REMOVE message | 409 | * netlbl_mgmt_remove - Handle a REMOVE message |
155 | * @skb: the NETLINK buffer | 410 | * @skb: the NETLINK buffer |
156 | * @info: the Generic NETLINK info block | 411 | * @info: the Generic NETLINK info block |
@@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) | |||
198 | if (data == NULL) | 453 | if (data == NULL) |
199 | goto listall_cb_failure; | 454 | goto listall_cb_failure; |
200 | 455 | ||
201 | ret_val = nla_put_string(cb_arg->skb, | 456 | ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); |
202 | NLBL_MGMT_A_DOMAIN, | ||
203 | entry->domain); | ||
204 | if (ret_val != 0) | 457 | if (ret_val != 0) |
205 | goto listall_cb_failure; | 458 | goto listall_cb_failure; |
206 | ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type); | ||
207 | if (ret_val != 0) | ||
208 | goto listall_cb_failure; | ||
209 | switch (entry->type) { | ||
210 | case NETLBL_NLTYPE_CIPSOV4: | ||
211 | ret_val = nla_put_u32(cb_arg->skb, | ||
212 | NLBL_MGMT_A_CV4DOI, | ||
213 | entry->type_def.cipsov4->doi); | ||
214 | if (ret_val != 0) | ||
215 | goto listall_cb_failure; | ||
216 | break; | ||
217 | } | ||
218 | 459 | ||
219 | cb_arg->seq++; | 460 | cb_arg->seq++; |
220 | return genlmsg_end(cb_arg->skb, data); | 461 | return genlmsg_end(cb_arg->skb, data); |
@@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb, | |||
268 | */ | 509 | */ |
269 | static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) | 510 | static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) |
270 | { | 511 | { |
271 | int ret_val = -EINVAL; | ||
272 | struct netlbl_dom_map *entry = NULL; | ||
273 | u32 tmp_val; | ||
274 | struct netlbl_audit audit_info; | 512 | struct netlbl_audit audit_info; |
275 | 513 | ||
276 | if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) | 514 | if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || |
277 | goto adddef_failure; | 515 | (info->attrs[NLBL_MGMT_A_IPV4ADDR] && |
516 | info->attrs[NLBL_MGMT_A_IPV6ADDR]) || | ||
517 | (info->attrs[NLBL_MGMT_A_IPV4MASK] && | ||
518 | info->attrs[NLBL_MGMT_A_IPV6MASK]) || | ||
519 | ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ | ||
520 | (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || | ||
521 | ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ | ||
522 | (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) | ||
523 | return -EINVAL; | ||
278 | 524 | ||
279 | netlbl_netlink_auditinfo(skb, &audit_info); | 525 | netlbl_netlink_auditinfo(skb, &audit_info); |
280 | 526 | ||
281 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 527 | return netlbl_mgmt_add_common(info, &audit_info); |
282 | if (entry == NULL) { | ||
283 | ret_val = -ENOMEM; | ||
284 | goto adddef_failure; | ||
285 | } | ||
286 | entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); | ||
287 | |||
288 | switch (entry->type) { | ||
289 | case NETLBL_NLTYPE_UNLABELED: | ||
290 | ret_val = netlbl_domhsh_add_default(entry, &audit_info); | ||
291 | break; | ||
292 | case NETLBL_NLTYPE_CIPSOV4: | ||
293 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) | ||
294 | goto adddef_failure; | ||
295 | |||
296 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); | ||
297 | /* We should be holding a rcu_read_lock() here while we hold | ||
298 | * the result but since the entry will always be deleted when | ||
299 | * the CIPSO DOI is deleted we aren't going to keep the | ||
300 | * lock. */ | ||
301 | rcu_read_lock(); | ||
302 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); | ||
303 | if (entry->type_def.cipsov4 == NULL) { | ||
304 | rcu_read_unlock(); | ||
305 | goto adddef_failure; | ||
306 | } | ||
307 | ret_val = netlbl_domhsh_add_default(entry, &audit_info); | ||
308 | rcu_read_unlock(); | ||
309 | break; | ||
310 | default: | ||
311 | goto adddef_failure; | ||
312 | } | ||
313 | if (ret_val != 0) | ||
314 | goto adddef_failure; | ||
315 | |||
316 | return 0; | ||
317 | |||
318 | adddef_failure: | ||
319 | kfree(entry); | ||
320 | return ret_val; | ||
321 | } | 528 | } |
322 | 529 | ||
323 | /** | 530 | /** |
@@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) | |||
371 | ret_val = -ENOENT; | 578 | ret_val = -ENOENT; |
372 | goto listdef_failure_lock; | 579 | goto listdef_failure_lock; |
373 | } | 580 | } |
374 | ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); | 581 | ret_val = netlbl_mgmt_listentry(ans_skb, entry); |
375 | if (ret_val != 0) | ||
376 | goto listdef_failure_lock; | ||
377 | switch (entry->type) { | ||
378 | case NETLBL_NLTYPE_CIPSOV4: | ||
379 | ret_val = nla_put_u32(ans_skb, | ||
380 | NLBL_MGMT_A_CV4DOI, | ||
381 | entry->type_def.cipsov4->doi); | ||
382 | if (ret_val != 0) | ||
383 | goto listdef_failure_lock; | ||
384 | break; | ||
385 | } | ||
386 | rcu_read_unlock(); | 582 | rcu_read_unlock(); |
583 | if (ret_val != 0) | ||
584 | goto listdef_failure; | ||
387 | 585 | ||
388 | genlmsg_end(ans_skb, data); | 586 | genlmsg_end(ans_skb, data); |
389 | return genlmsg_reply(ans_skb, info); | 587 | return genlmsg_reply(ans_skb, info); |
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h index a43bff169d6b..05d96431f819 100644 --- a/net/netlabel/netlabel_mgmt.h +++ b/net/netlabel/netlabel_mgmt.h | |||
@@ -45,6 +45,16 @@ | |||
45 | * NLBL_MGMT_A_DOMAIN | 45 | * NLBL_MGMT_A_DOMAIN |
46 | * NLBL_MGMT_A_PROTOCOL | 46 | * NLBL_MGMT_A_PROTOCOL |
47 | * | 47 | * |
48 | * If IPv4 is specified the following attributes are required: | ||
49 | * | ||
50 | * NLBL_MGMT_A_IPV4ADDR | ||
51 | * NLBL_MGMT_A_IPV4MASK | ||
52 | * | ||
53 | * If IPv6 is specified the following attributes are required: | ||
54 | * | ||
55 | * NLBL_MGMT_A_IPV6ADDR | ||
56 | * NLBL_MGMT_A_IPV6MASK | ||
57 | * | ||
48 | * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: | 58 | * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: |
49 | * | 59 | * |
50 | * NLBL_MGMT_A_CV4DOI | 60 | * NLBL_MGMT_A_CV4DOI |
@@ -68,13 +78,24 @@ | |||
68 | * Required attributes: | 78 | * Required attributes: |
69 | * | 79 | * |
70 | * NLBL_MGMT_A_DOMAIN | 80 | * NLBL_MGMT_A_DOMAIN |
81 | * | ||
82 | * If the IP address selectors are not used the following attribute is | ||
83 | * required: | ||
84 | * | ||
71 | * NLBL_MGMT_A_PROTOCOL | 85 | * NLBL_MGMT_A_PROTOCOL |
72 | * | 86 | * |
73 | * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: | 87 | * If the IP address selectors are used then the following attritbute is |
88 | * required: | ||
89 | * | ||
90 | * NLBL_MGMT_A_SELECTORLIST | ||
91 | * | ||
92 | * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following | ||
93 | * attributes are required: | ||
74 | * | 94 | * |
75 | * NLBL_MGMT_A_CV4DOI | 95 | * NLBL_MGMT_A_CV4DOI |
76 | * | 96 | * |
77 | * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. | 97 | * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other |
98 | * attributes are required. | ||
78 | * | 99 | * |
79 | * o ADDDEF: | 100 | * o ADDDEF: |
80 | * Sent by an application to set the default domain mapping for the NetLabel | 101 | * Sent by an application to set the default domain mapping for the NetLabel |
@@ -100,15 +121,23 @@ | |||
100 | * application there is no payload. On success the kernel should send a | 121 | * application there is no payload. On success the kernel should send a |
101 | * response using the following format. | 122 | * response using the following format. |
102 | * | 123 | * |
103 | * Required attributes: | 124 | * If the IP address selectors are not used the following attribute is |
125 | * required: | ||
104 | * | 126 | * |
105 | * NLBL_MGMT_A_PROTOCOL | 127 | * NLBL_MGMT_A_PROTOCOL |
106 | * | 128 | * |
107 | * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: | 129 | * If the IP address selectors are used then the following attritbute is |
130 | * required: | ||
131 | * | ||
132 | * NLBL_MGMT_A_SELECTORLIST | ||
133 | * | ||
134 | * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following | ||
135 | * attributes are required: | ||
108 | * | 136 | * |
109 | * NLBL_MGMT_A_CV4DOI | 137 | * NLBL_MGMT_A_CV4DOI |
110 | * | 138 | * |
111 | * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. | 139 | * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other |
140 | * attributes are required. | ||
112 | * | 141 | * |
113 | * o PROTOCOLS: | 142 | * o PROTOCOLS: |
114 | * Sent by an application to request a list of configured NetLabel protocols | 143 | * Sent by an application to request a list of configured NetLabel protocols |
@@ -162,6 +191,26 @@ enum { | |||
162 | NLBL_MGMT_A_CV4DOI, | 191 | NLBL_MGMT_A_CV4DOI, |
163 | /* (NLA_U32) | 192 | /* (NLA_U32) |
164 | * the CIPSOv4 DOI value */ | 193 | * the CIPSOv4 DOI value */ |
194 | NLBL_MGMT_A_IPV6ADDR, | ||
195 | /* (NLA_BINARY, struct in6_addr) | ||
196 | * an IPv6 address */ | ||
197 | NLBL_MGMT_A_IPV6MASK, | ||
198 | /* (NLA_BINARY, struct in6_addr) | ||
199 | * an IPv6 address mask */ | ||
200 | NLBL_MGMT_A_IPV4ADDR, | ||
201 | /* (NLA_BINARY, struct in_addr) | ||
202 | * an IPv4 address */ | ||
203 | NLBL_MGMT_A_IPV4MASK, | ||
204 | /* (NLA_BINARY, struct in_addr) | ||
205 | * and IPv4 address mask */ | ||
206 | NLBL_MGMT_A_ADDRSELECTOR, | ||
207 | /* (NLA_NESTED) | ||
208 | * an IP address selector, must contain an address, mask, and protocol | ||
209 | * attribute plus any protocol specific attributes */ | ||
210 | NLBL_MGMT_A_SELECTORLIST, | ||
211 | /* (NLA_NESTED) | ||
212 | * the selector list, there must be at least one | ||
213 | * NLBL_MGMT_A_ADDRSELECTOR attribute */ | ||
165 | __NLBL_MGMT_A_MAX, | 214 | __NLBL_MGMT_A_MAX, |
166 | }; | 215 | }; |
167 | #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) | 216 | #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) |
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 921c118ead89..e8a5c32b0f10 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007 | 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008 |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
@@ -54,6 +54,7 @@ | |||
54 | #include <asm/atomic.h> | 54 | #include <asm/atomic.h> |
55 | 55 | ||
56 | #include "netlabel_user.h" | 56 | #include "netlabel_user.h" |
57 | #include "netlabel_addrlist.h" | ||
57 | #include "netlabel_domainhash.h" | 58 | #include "netlabel_domainhash.h" |
58 | #include "netlabel_unlabeled.h" | 59 | #include "netlabel_unlabeled.h" |
59 | #include "netlabel_mgmt.h" | 60 | #include "netlabel_mgmt.h" |
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl { | |||
76 | struct list_head *tbl; | 77 | struct list_head *tbl; |
77 | u32 size; | 78 | u32 size; |
78 | }; | 79 | }; |
80 | #define netlbl_unlhsh_addr4_entry(iter) \ | ||
81 | container_of(iter, struct netlbl_unlhsh_addr4, list) | ||
79 | struct netlbl_unlhsh_addr4 { | 82 | struct netlbl_unlhsh_addr4 { |
80 | __be32 addr; | ||
81 | __be32 mask; | ||
82 | u32 secid; | 83 | u32 secid; |
83 | 84 | ||
84 | u32 valid; | 85 | struct netlbl_af4list list; |
85 | struct list_head list; | ||
86 | struct rcu_head rcu; | 86 | struct rcu_head rcu; |
87 | }; | 87 | }; |
88 | #define netlbl_unlhsh_addr6_entry(iter) \ | ||
89 | container_of(iter, struct netlbl_unlhsh_addr6, list) | ||
88 | struct netlbl_unlhsh_addr6 { | 90 | struct netlbl_unlhsh_addr6 { |
89 | struct in6_addr addr; | ||
90 | struct in6_addr mask; | ||
91 | u32 secid; | 91 | u32 secid; |
92 | 92 | ||
93 | u32 valid; | 93 | struct netlbl_af6list list; |
94 | struct list_head list; | ||
95 | struct rcu_head rcu; | 94 | struct rcu_head rcu; |
96 | }; | 95 | }; |
97 | struct netlbl_unlhsh_iface { | 96 | struct netlbl_unlhsh_iface { |
@@ -147,76 +146,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1 | |||
147 | }; | 146 | }; |
148 | 147 | ||
149 | /* | 148 | /* |
150 | * Audit Helper Functions | ||
151 | */ | ||
152 | |||
153 | /** | ||
154 | * netlbl_unlabel_audit_addr4 - Audit an IPv4 address | ||
155 | * @audit_buf: audit buffer | ||
156 | * @dev: network interface | ||
157 | * @addr: IP address | ||
158 | * @mask: IP address mask | ||
159 | * | ||
160 | * Description: | ||
161 | * Write the IPv4 address and address mask, if necessary, to @audit_buf. | ||
162 | * | ||
163 | */ | ||
164 | static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf, | ||
165 | const char *dev, | ||
166 | __be32 addr, __be32 mask) | ||
167 | { | ||
168 | u32 mask_val = ntohl(mask); | ||
169 | |||
170 | if (dev != NULL) | ||
171 | audit_log_format(audit_buf, " netif=%s", dev); | ||
172 | audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr)); | ||
173 | if (mask_val != 0xffffffff) { | ||
174 | u32 mask_len = 0; | ||
175 | while (mask_val > 0) { | ||
176 | mask_val <<= 1; | ||
177 | mask_len++; | ||
178 | } | ||
179 | audit_log_format(audit_buf, " src_prefixlen=%d", mask_len); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
184 | /** | ||
185 | * netlbl_unlabel_audit_addr6 - Audit an IPv6 address | ||
186 | * @audit_buf: audit buffer | ||
187 | * @dev: network interface | ||
188 | * @addr: IP address | ||
189 | * @mask: IP address mask | ||
190 | * | ||
191 | * Description: | ||
192 | * Write the IPv6 address and address mask, if necessary, to @audit_buf. | ||
193 | * | ||
194 | */ | ||
195 | static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf, | ||
196 | const char *dev, | ||
197 | const struct in6_addr *addr, | ||
198 | const struct in6_addr *mask) | ||
199 | { | ||
200 | if (dev != NULL) | ||
201 | audit_log_format(audit_buf, " netif=%s", dev); | ||
202 | audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr)); | ||
203 | if (ntohl(mask->s6_addr32[3]) != 0xffffffff) { | ||
204 | u32 mask_len = 0; | ||
205 | u32 mask_val; | ||
206 | int iter = -1; | ||
207 | while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff) | ||
208 | mask_len += 32; | ||
209 | mask_val = ntohl(mask->s6_addr32[iter]); | ||
210 | while (mask_val > 0) { | ||
211 | mask_val <<= 1; | ||
212 | mask_len++; | ||
213 | } | ||
214 | audit_log_format(audit_buf, " src_prefixlen=%d", mask_len); | ||
215 | } | ||
216 | } | ||
217 | #endif /* IPv6 */ | ||
218 | |||
219 | /* | ||
220 | * Unlabeled Connection Hash Table Functions | 149 | * Unlabeled Connection Hash Table Functions |
221 | */ | 150 | */ |
222 | 151 | ||
@@ -274,26 +203,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry) | |||
274 | static void netlbl_unlhsh_free_iface(struct rcu_head *entry) | 203 | static void netlbl_unlhsh_free_iface(struct rcu_head *entry) |
275 | { | 204 | { |
276 | struct netlbl_unlhsh_iface *iface; | 205 | struct netlbl_unlhsh_iface *iface; |
277 | struct netlbl_unlhsh_addr4 *iter4; | 206 | struct netlbl_af4list *iter4; |
278 | struct netlbl_unlhsh_addr4 *tmp4; | 207 | struct netlbl_af4list *tmp4; |
279 | struct netlbl_unlhsh_addr6 *iter6; | 208 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
280 | struct netlbl_unlhsh_addr6 *tmp6; | 209 | struct netlbl_af6list *iter6; |
210 | struct netlbl_af6list *tmp6; | ||
211 | #endif /* IPv6 */ | ||
281 | 212 | ||
282 | iface = container_of(entry, struct netlbl_unlhsh_iface, rcu); | 213 | iface = container_of(entry, struct netlbl_unlhsh_iface, rcu); |
283 | 214 | ||
284 | /* no need for locks here since we are the only one with access to this | 215 | /* no need for locks here since we are the only one with access to this |
285 | * structure */ | 216 | * structure */ |
286 | 217 | ||
287 | list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list) | 218 | netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) { |
288 | if (iter4->valid) { | 219 | netlbl_af4list_remove_entry(iter4); |
289 | list_del_rcu(&iter4->list); | 220 | kfree(netlbl_unlhsh_addr4_entry(iter4)); |
290 | kfree(iter4); | 221 | } |
291 | } | 222 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
292 | list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list) | 223 | netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) { |
293 | if (iter6->valid) { | 224 | netlbl_af6list_remove_entry(iter6); |
294 | list_del_rcu(&iter6->list); | 225 | kfree(netlbl_unlhsh_addr6_entry(iter6)); |
295 | kfree(iter6); | 226 | } |
296 | } | 227 | #endif /* IPv6 */ |
297 | kfree(iface); | 228 | kfree(iface); |
298 | } | 229 | } |
299 | 230 | ||
@@ -316,59 +247,6 @@ static u32 netlbl_unlhsh_hash(int ifindex) | |||
316 | } | 247 | } |
317 | 248 | ||
318 | /** | 249 | /** |
319 | * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry | ||
320 | * @addr: IPv4 address | ||
321 | * @iface: the network interface entry | ||
322 | * | ||
323 | * Description: | ||
324 | * Searches the IPv4 address list of the network interface specified by @iface. | ||
325 | * If a matching address entry is found it is returned, otherwise NULL is | ||
326 | * returned. The caller is responsible for calling the rcu_read_[un]lock() | ||
327 | * functions. | ||
328 | * | ||
329 | */ | ||
330 | static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4( | ||
331 | __be32 addr, | ||
332 | const struct netlbl_unlhsh_iface *iface) | ||
333 | { | ||
334 | struct netlbl_unlhsh_addr4 *iter; | ||
335 | |||
336 | list_for_each_entry_rcu(iter, &iface->addr4_list, list) | ||
337 | if (iter->valid && (addr & iter->mask) == iter->addr) | ||
338 | return iter; | ||
339 | |||
340 | return NULL; | ||
341 | } | ||
342 | |||
343 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
344 | /** | ||
345 | * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry | ||
346 | * @addr: IPv6 address | ||
347 | * @iface: the network interface entry | ||
348 | * | ||
349 | * Description: | ||
350 | * Searches the IPv6 address list of the network interface specified by @iface. | ||
351 | * If a matching address entry is found it is returned, otherwise NULL is | ||
352 | * returned. The caller is responsible for calling the rcu_read_[un]lock() | ||
353 | * functions. | ||
354 | * | ||
355 | */ | ||
356 | static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6( | ||
357 | const struct in6_addr *addr, | ||
358 | const struct netlbl_unlhsh_iface *iface) | ||
359 | { | ||
360 | struct netlbl_unlhsh_addr6 *iter; | ||
361 | |||
362 | list_for_each_entry_rcu(iter, &iface->addr6_list, list) | ||
363 | if (iter->valid && | ||
364 | ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0) | ||
365 | return iter; | ||
366 | |||
367 | return NULL; | ||
368 | } | ||
369 | #endif /* IPv6 */ | ||
370 | |||
371 | /** | ||
372 | * netlbl_unlhsh_search_iface - Search for a matching interface entry | 250 | * netlbl_unlhsh_search_iface - Search for a matching interface entry |
373 | * @ifindex: the network interface | 251 | * @ifindex: the network interface |
374 | * | 252 | * |
@@ -381,12 +259,12 @@ static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6( | |||
381 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | 259 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) |
382 | { | 260 | { |
383 | u32 bkt; | 261 | u32 bkt; |
262 | struct list_head *bkt_list; | ||
384 | struct netlbl_unlhsh_iface *iter; | 263 | struct netlbl_unlhsh_iface *iter; |
385 | 264 | ||
386 | bkt = netlbl_unlhsh_hash(ifindex); | 265 | bkt = netlbl_unlhsh_hash(ifindex); |
387 | list_for_each_entry_rcu(iter, | 266 | bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt]; |
388 | &rcu_dereference(netlbl_unlhsh)->tbl[bkt], | 267 | list_for_each_entry_rcu(iter, bkt_list, list) |
389 | list) | ||
390 | if (iter->valid && iter->ifindex == ifindex) | 268 | if (iter->valid && iter->ifindex == ifindex) |
391 | return iter; | 269 | return iter; |
392 | 270 | ||
@@ -439,43 +317,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, | |||
439 | const struct in_addr *mask, | 317 | const struct in_addr *mask, |
440 | u32 secid) | 318 | u32 secid) |
441 | { | 319 | { |
320 | int ret_val; | ||
442 | struct netlbl_unlhsh_addr4 *entry; | 321 | struct netlbl_unlhsh_addr4 *entry; |
443 | struct netlbl_unlhsh_addr4 *iter; | ||
444 | 322 | ||
445 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 323 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
446 | if (entry == NULL) | 324 | if (entry == NULL) |
447 | return -ENOMEM; | 325 | return -ENOMEM; |
448 | 326 | ||
449 | entry->addr = addr->s_addr & mask->s_addr; | 327 | entry->list.addr = addr->s_addr & mask->s_addr; |
450 | entry->mask = mask->s_addr; | 328 | entry->list.mask = mask->s_addr; |
451 | entry->secid = secid; | 329 | entry->list.valid = 1; |
452 | entry->valid = 1; | ||
453 | INIT_RCU_HEAD(&entry->rcu); | 330 | INIT_RCU_HEAD(&entry->rcu); |
331 | entry->secid = secid; | ||
454 | 332 | ||
455 | spin_lock(&netlbl_unlhsh_lock); | 333 | spin_lock(&netlbl_unlhsh_lock); |
456 | iter = netlbl_unlhsh_search_addr4(entry->addr, iface); | 334 | ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list); |
457 | if (iter != NULL && | ||
458 | iter->addr == addr->s_addr && iter->mask == mask->s_addr) { | ||
459 | spin_unlock(&netlbl_unlhsh_lock); | ||
460 | kfree(entry); | ||
461 | return -EEXIST; | ||
462 | } | ||
463 | /* in order to speed up address searches through the list (the common | ||
464 | * case) we need to keep the list in order based on the size of the | ||
465 | * address mask such that the entry with the widest mask (smallest | ||
466 | * numerical value) appears first in the list */ | ||
467 | list_for_each_entry_rcu(iter, &iface->addr4_list, list) | ||
468 | if (iter->valid && | ||
469 | ntohl(entry->mask) > ntohl(iter->mask)) { | ||
470 | __list_add_rcu(&entry->list, | ||
471 | iter->list.prev, | ||
472 | &iter->list); | ||
473 | spin_unlock(&netlbl_unlhsh_lock); | ||
474 | return 0; | ||
475 | } | ||
476 | list_add_tail_rcu(&entry->list, &iface->addr4_list); | ||
477 | spin_unlock(&netlbl_unlhsh_lock); | 335 | spin_unlock(&netlbl_unlhsh_lock); |
478 | return 0; | 336 | |
337 | if (ret_val != 0) | ||
338 | kfree(entry); | ||
339 | return ret_val; | ||
479 | } | 340 | } |
480 | 341 | ||
481 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 342 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
@@ -498,47 +359,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, | |||
498 | const struct in6_addr *mask, | 359 | const struct in6_addr *mask, |
499 | u32 secid) | 360 | u32 secid) |
500 | { | 361 | { |
362 | int ret_val; | ||
501 | struct netlbl_unlhsh_addr6 *entry; | 363 | struct netlbl_unlhsh_addr6 *entry; |
502 | struct netlbl_unlhsh_addr6 *iter; | ||
503 | 364 | ||
504 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 365 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
505 | if (entry == NULL) | 366 | if (entry == NULL) |
506 | return -ENOMEM; | 367 | return -ENOMEM; |
507 | 368 | ||
508 | ipv6_addr_copy(&entry->addr, addr); | 369 | ipv6_addr_copy(&entry->list.addr, addr); |
509 | entry->addr.s6_addr32[0] &= mask->s6_addr32[0]; | 370 | entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; |
510 | entry->addr.s6_addr32[1] &= mask->s6_addr32[1]; | 371 | entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; |
511 | entry->addr.s6_addr32[2] &= mask->s6_addr32[2]; | 372 | entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; |
512 | entry->addr.s6_addr32[3] &= mask->s6_addr32[3]; | 373 | entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; |
513 | ipv6_addr_copy(&entry->mask, mask); | 374 | ipv6_addr_copy(&entry->list.mask, mask); |
514 | entry->secid = secid; | 375 | entry->list.valid = 1; |
515 | entry->valid = 1; | ||
516 | INIT_RCU_HEAD(&entry->rcu); | 376 | INIT_RCU_HEAD(&entry->rcu); |
377 | entry->secid = secid; | ||
517 | 378 | ||
518 | spin_lock(&netlbl_unlhsh_lock); | 379 | spin_lock(&netlbl_unlhsh_lock); |
519 | iter = netlbl_unlhsh_search_addr6(&entry->addr, iface); | 380 | ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list); |
520 | if (iter != NULL && | ||
521 | (ipv6_addr_equal(&iter->addr, addr) && | ||
522 | ipv6_addr_equal(&iter->mask, mask))) { | ||
523 | spin_unlock(&netlbl_unlhsh_lock); | ||
524 | kfree(entry); | ||
525 | return -EEXIST; | ||
526 | } | ||
527 | /* in order to speed up address searches through the list (the common | ||
528 | * case) we need to keep the list in order based on the size of the | ||
529 | * address mask such that the entry with the widest mask (smallest | ||
530 | * numerical value) appears first in the list */ | ||
531 | list_for_each_entry_rcu(iter, &iface->addr6_list, list) | ||
532 | if (iter->valid && | ||
533 | ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) { | ||
534 | __list_add_rcu(&entry->list, | ||
535 | iter->list.prev, | ||
536 | &iter->list); | ||
537 | spin_unlock(&netlbl_unlhsh_lock); | ||
538 | return 0; | ||
539 | } | ||
540 | list_add_tail_rcu(&entry->list, &iface->addr6_list); | ||
541 | spin_unlock(&netlbl_unlhsh_lock); | 381 | spin_unlock(&netlbl_unlhsh_lock); |
382 | |||
383 | if (ret_val != 0) | ||
384 | kfree(entry); | ||
542 | return 0; | 385 | return 0; |
543 | } | 386 | } |
544 | #endif /* IPv6 */ | 387 | #endif /* IPv6 */ |
@@ -658,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net, | |||
658 | mask4 = (struct in_addr *)mask; | 501 | mask4 = (struct in_addr *)mask; |
659 | ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); | 502 | ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); |
660 | if (audit_buf != NULL) | 503 | if (audit_buf != NULL) |
661 | netlbl_unlabel_audit_addr4(audit_buf, | 504 | netlbl_af4list_audit_addr(audit_buf, 1, |
662 | dev_name, | 505 | dev_name, |
663 | addr4->s_addr, | 506 | addr4->s_addr, |
664 | mask4->s_addr); | 507 | mask4->s_addr); |
665 | break; | 508 | break; |
666 | } | 509 | } |
667 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 510 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
@@ -672,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net, | |||
672 | mask6 = (struct in6_addr *)mask; | 515 | mask6 = (struct in6_addr *)mask; |
673 | ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); | 516 | ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); |
674 | if (audit_buf != NULL) | 517 | if (audit_buf != NULL) |
675 | netlbl_unlabel_audit_addr6(audit_buf, | 518 | netlbl_af6list_audit_addr(audit_buf, 1, |
676 | dev_name, | 519 | dev_name, |
677 | addr6, mask6); | 520 | addr6, mask6); |
678 | break; | 521 | break; |
679 | } | 522 | } |
680 | #endif /* IPv6 */ | 523 | #endif /* IPv6 */ |
@@ -719,35 +562,34 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, | |||
719 | const struct in_addr *mask, | 562 | const struct in_addr *mask, |
720 | struct netlbl_audit *audit_info) | 563 | struct netlbl_audit *audit_info) |
721 | { | 564 | { |
722 | int ret_val = -ENOENT; | 565 | int ret_val = 0; |
566 | struct netlbl_af4list *list_entry; | ||
723 | struct netlbl_unlhsh_addr4 *entry; | 567 | struct netlbl_unlhsh_addr4 *entry; |
724 | struct audit_buffer *audit_buf = NULL; | 568 | struct audit_buffer *audit_buf; |
725 | struct net_device *dev; | 569 | struct net_device *dev; |
726 | char *secctx = NULL; | 570 | char *secctx; |
727 | u32 secctx_len; | 571 | u32 secctx_len; |
728 | 572 | ||
729 | spin_lock(&netlbl_unlhsh_lock); | 573 | spin_lock(&netlbl_unlhsh_lock); |
730 | entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface); | 574 | list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr, |
731 | if (entry != NULL && | 575 | &iface->addr4_list); |
732 | entry->addr == addr->s_addr && entry->mask == mask->s_addr) { | ||
733 | entry->valid = 0; | ||
734 | list_del_rcu(&entry->list); | ||
735 | ret_val = 0; | ||
736 | } | ||
737 | spin_unlock(&netlbl_unlhsh_lock); | 576 | spin_unlock(&netlbl_unlhsh_lock); |
577 | if (list_entry == NULL) | ||
578 | ret_val = -ENOENT; | ||
579 | entry = netlbl_unlhsh_addr4_entry(list_entry); | ||
738 | 580 | ||
739 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, | 581 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, |
740 | audit_info); | 582 | audit_info); |
741 | if (audit_buf != NULL) { | 583 | if (audit_buf != NULL) { |
742 | dev = dev_get_by_index(net, iface->ifindex); | 584 | dev = dev_get_by_index(net, iface->ifindex); |
743 | netlbl_unlabel_audit_addr4(audit_buf, | 585 | netlbl_af4list_audit_addr(audit_buf, 1, |
744 | (dev != NULL ? dev->name : NULL), | 586 | (dev != NULL ? dev->name : NULL), |
745 | entry->addr, entry->mask); | 587 | addr->s_addr, mask->s_addr); |
746 | if (dev != NULL) | 588 | if (dev != NULL) |
747 | dev_put(dev); | 589 | dev_put(dev); |
748 | if (security_secid_to_secctx(entry->secid, | 590 | if (entry && security_secid_to_secctx(entry->secid, |
749 | &secctx, | 591 | &secctx, |
750 | &secctx_len) == 0) { | 592 | &secctx_len) == 0) { |
751 | audit_log_format(audit_buf, " sec_obj=%s", secctx); | 593 | audit_log_format(audit_buf, " sec_obj=%s", secctx); |
752 | security_release_secctx(secctx, secctx_len); | 594 | security_release_secctx(secctx, secctx_len); |
753 | } | 595 | } |
@@ -781,36 +623,33 @@ static int netlbl_unlhsh_remove_addr6(struct net *net, | |||
781 | const struct in6_addr *mask, | 623 | const struct in6_addr *mask, |
782 | struct netlbl_audit *audit_info) | 624 | struct netlbl_audit *audit_info) |
783 | { | 625 | { |
784 | int ret_val = -ENOENT; | 626 | int ret_val = 0; |
627 | struct netlbl_af6list *list_entry; | ||
785 | struct netlbl_unlhsh_addr6 *entry; | 628 | struct netlbl_unlhsh_addr6 *entry; |
786 | struct audit_buffer *audit_buf = NULL; | 629 | struct audit_buffer *audit_buf; |
787 | struct net_device *dev; | 630 | struct net_device *dev; |
788 | char *secctx = NULL; | 631 | char *secctx; |
789 | u32 secctx_len; | 632 | u32 secctx_len; |
790 | 633 | ||
791 | spin_lock(&netlbl_unlhsh_lock); | 634 | spin_lock(&netlbl_unlhsh_lock); |
792 | entry = netlbl_unlhsh_search_addr6(addr, iface); | 635 | list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list); |
793 | if (entry != NULL && | ||
794 | (ipv6_addr_equal(&entry->addr, addr) && | ||
795 | ipv6_addr_equal(&entry->mask, mask))) { | ||
796 | entry->valid = 0; | ||
797 | list_del_rcu(&entry->list); | ||
798 | ret_val = 0; | ||
799 | } | ||
800 | spin_unlock(&netlbl_unlhsh_lock); | 636 | spin_unlock(&netlbl_unlhsh_lock); |
637 | if (list_entry == NULL) | ||
638 | ret_val = -ENOENT; | ||
639 | entry = netlbl_unlhsh_addr6_entry(list_entry); | ||
801 | 640 | ||
802 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, | 641 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, |
803 | audit_info); | 642 | audit_info); |
804 | if (audit_buf != NULL) { | 643 | if (audit_buf != NULL) { |
805 | dev = dev_get_by_index(net, iface->ifindex); | 644 | dev = dev_get_by_index(net, iface->ifindex); |
806 | netlbl_unlabel_audit_addr6(audit_buf, | 645 | netlbl_af6list_audit_addr(audit_buf, 1, |
807 | (dev != NULL ? dev->name : NULL), | 646 | (dev != NULL ? dev->name : NULL), |
808 | addr, mask); | 647 | addr, mask); |
809 | if (dev != NULL) | 648 | if (dev != NULL) |
810 | dev_put(dev); | 649 | dev_put(dev); |
811 | if (security_secid_to_secctx(entry->secid, | 650 | if (entry && security_secid_to_secctx(entry->secid, |
812 | &secctx, | 651 | &secctx, |
813 | &secctx_len) == 0) { | 652 | &secctx_len) == 0) { |
814 | audit_log_format(audit_buf, " sec_obj=%s", secctx); | 653 | audit_log_format(audit_buf, " sec_obj=%s", secctx); |
815 | security_release_secctx(secctx, secctx_len); | 654 | security_release_secctx(secctx, secctx_len); |
816 | } | 655 | } |
@@ -836,16 +675,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net, | |||
836 | */ | 675 | */ |
837 | static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) | 676 | static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) |
838 | { | 677 | { |
839 | struct netlbl_unlhsh_addr4 *iter4; | 678 | struct netlbl_af4list *iter4; |
840 | struct netlbl_unlhsh_addr6 *iter6; | 679 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
680 | struct netlbl_af6list *iter6; | ||
681 | #endif /* IPv6 */ | ||
841 | 682 | ||
842 | spin_lock(&netlbl_unlhsh_lock); | 683 | spin_lock(&netlbl_unlhsh_lock); |
843 | list_for_each_entry_rcu(iter4, &iface->addr4_list, list) | 684 | netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list) |
844 | if (iter4->valid) | 685 | goto unlhsh_condremove_failure; |
845 | goto unlhsh_condremove_failure; | 686 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
846 | list_for_each_entry_rcu(iter6, &iface->addr6_list, list) | 687 | netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list) |
847 | if (iter6->valid) | 688 | goto unlhsh_condremove_failure; |
848 | goto unlhsh_condremove_failure; | 689 | #endif /* IPv6 */ |
849 | iface->valid = 0; | 690 | iface->valid = 0; |
850 | if (iface->ifindex > 0) | 691 | if (iface->ifindex > 0) |
851 | list_del_rcu(&iface->list); | 692 | list_del_rcu(&iface->list); |
@@ -1349,7 +1190,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, | |||
1349 | if (addr4) { | 1190 | if (addr4) { |
1350 | struct in_addr addr_struct; | 1191 | struct in_addr addr_struct; |
1351 | 1192 | ||
1352 | addr_struct.s_addr = addr4->addr; | 1193 | addr_struct.s_addr = addr4->list.addr; |
1353 | ret_val = nla_put(cb_arg->skb, | 1194 | ret_val = nla_put(cb_arg->skb, |
1354 | NLBL_UNLABEL_A_IPV4ADDR, | 1195 | NLBL_UNLABEL_A_IPV4ADDR, |
1355 | sizeof(struct in_addr), | 1196 | sizeof(struct in_addr), |
@@ -1357,7 +1198,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, | |||
1357 | if (ret_val != 0) | 1198 | if (ret_val != 0) |
1358 | goto list_cb_failure; | 1199 | goto list_cb_failure; |
1359 | 1200 | ||
1360 | addr_struct.s_addr = addr4->mask; | 1201 | addr_struct.s_addr = addr4->list.mask; |
1361 | ret_val = nla_put(cb_arg->skb, | 1202 | ret_val = nla_put(cb_arg->skb, |
1362 | NLBL_UNLABEL_A_IPV4MASK, | 1203 | NLBL_UNLABEL_A_IPV4MASK, |
1363 | sizeof(struct in_addr), | 1204 | sizeof(struct in_addr), |
@@ -1370,14 +1211,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, | |||
1370 | ret_val = nla_put(cb_arg->skb, | 1211 | ret_val = nla_put(cb_arg->skb, |
1371 | NLBL_UNLABEL_A_IPV6ADDR, | 1212 | NLBL_UNLABEL_A_IPV6ADDR, |
1372 | sizeof(struct in6_addr), | 1213 | sizeof(struct in6_addr), |
1373 | &addr6->addr); | 1214 | &addr6->list.addr); |
1374 | if (ret_val != 0) | 1215 | if (ret_val != 0) |
1375 | goto list_cb_failure; | 1216 | goto list_cb_failure; |
1376 | 1217 | ||
1377 | ret_val = nla_put(cb_arg->skb, | 1218 | ret_val = nla_put(cb_arg->skb, |
1378 | NLBL_UNLABEL_A_IPV6MASK, | 1219 | NLBL_UNLABEL_A_IPV6MASK, |
1379 | sizeof(struct in6_addr), | 1220 | sizeof(struct in6_addr), |
1380 | &addr6->mask); | 1221 | &addr6->list.mask); |
1381 | if (ret_val != 0) | 1222 | if (ret_val != 0) |
1382 | goto list_cb_failure; | 1223 | goto list_cb_failure; |
1383 | 1224 | ||
@@ -1425,8 +1266,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb, | |||
1425 | u32 iter_bkt; | 1266 | u32 iter_bkt; |
1426 | u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0; | 1267 | u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0; |
1427 | struct netlbl_unlhsh_iface *iface; | 1268 | struct netlbl_unlhsh_iface *iface; |
1428 | struct netlbl_unlhsh_addr4 *addr4; | 1269 | struct list_head *iter_list; |
1429 | struct netlbl_unlhsh_addr6 *addr6; | 1270 | struct netlbl_af4list *addr4; |
1271 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
1272 | struct netlbl_af6list *addr6; | ||
1273 | #endif | ||
1430 | 1274 | ||
1431 | cb_arg.nl_cb = cb; | 1275 | cb_arg.nl_cb = cb; |
1432 | cb_arg.skb = skb; | 1276 | cb_arg.skb = skb; |
@@ -1436,44 +1280,43 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb, | |||
1436 | for (iter_bkt = skip_bkt; | 1280 | for (iter_bkt = skip_bkt; |
1437 | iter_bkt < rcu_dereference(netlbl_unlhsh)->size; | 1281 | iter_bkt < rcu_dereference(netlbl_unlhsh)->size; |
1438 | iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) { | 1282 | iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) { |
1439 | list_for_each_entry_rcu(iface, | 1283 | iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt]; |
1440 | &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt], | 1284 | list_for_each_entry_rcu(iface, iter_list, list) { |
1441 | list) { | ||
1442 | if (!iface->valid || | 1285 | if (!iface->valid || |
1443 | iter_chain++ < skip_chain) | 1286 | iter_chain++ < skip_chain) |
1444 | continue; | 1287 | continue; |
1445 | list_for_each_entry_rcu(addr4, | 1288 | netlbl_af4list_foreach_rcu(addr4, |
1446 | &iface->addr4_list, | 1289 | &iface->addr4_list) { |
1447 | list) { | 1290 | if (iter_addr4++ < skip_addr4) |
1448 | if (!addr4->valid || iter_addr4++ < skip_addr4) | ||
1449 | continue; | 1291 | continue; |
1450 | if (netlbl_unlabel_staticlist_gen( | 1292 | if (netlbl_unlabel_staticlist_gen( |
1451 | NLBL_UNLABEL_C_STATICLIST, | 1293 | NLBL_UNLABEL_C_STATICLIST, |
1452 | iface, | 1294 | iface, |
1453 | addr4, | 1295 | netlbl_unlhsh_addr4_entry(addr4), |
1454 | NULL, | 1296 | NULL, |
1455 | &cb_arg) < 0) { | 1297 | &cb_arg) < 0) { |
1456 | iter_addr4--; | 1298 | iter_addr4--; |
1457 | iter_chain--; | 1299 | iter_chain--; |
1458 | goto unlabel_staticlist_return; | 1300 | goto unlabel_staticlist_return; |
1459 | } | 1301 | } |
1460 | } | 1302 | } |
1461 | list_for_each_entry_rcu(addr6, | 1303 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1462 | &iface->addr6_list, | 1304 | netlbl_af6list_foreach_rcu(addr6, |
1463 | list) { | 1305 | &iface->addr6_list) { |
1464 | if (!addr6->valid || iter_addr6++ < skip_addr6) | 1306 | if (iter_addr6++ < skip_addr6) |
1465 | continue; | 1307 | continue; |
1466 | if (netlbl_unlabel_staticlist_gen( | 1308 | if (netlbl_unlabel_staticlist_gen( |
1467 | NLBL_UNLABEL_C_STATICLIST, | 1309 | NLBL_UNLABEL_C_STATICLIST, |
1468 | iface, | 1310 | iface, |
1469 | NULL, | 1311 | NULL, |
1470 | addr6, | 1312 | netlbl_unlhsh_addr6_entry(addr6), |
1471 | &cb_arg) < 0) { | 1313 | &cb_arg) < 0) { |
1472 | iter_addr6--; | 1314 | iter_addr6--; |
1473 | iter_chain--; | 1315 | iter_chain--; |
1474 | goto unlabel_staticlist_return; | 1316 | goto unlabel_staticlist_return; |
1475 | } | 1317 | } |
1476 | } | 1318 | } |
1319 | #endif /* IPv6 */ | ||
1477 | } | 1320 | } |
1478 | } | 1321 | } |
1479 | 1322 | ||
@@ -1504,9 +1347,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb, | |||
1504 | struct netlbl_unlhsh_iface *iface; | 1347 | struct netlbl_unlhsh_iface *iface; |
1505 | u32 skip_addr4 = cb->args[0]; | 1348 | u32 skip_addr4 = cb->args[0]; |
1506 | u32 skip_addr6 = cb->args[1]; | 1349 | u32 skip_addr6 = cb->args[1]; |
1507 | u32 iter_addr4 = 0, iter_addr6 = 0; | 1350 | u32 iter_addr4 = 0; |
1508 | struct netlbl_unlhsh_addr4 *addr4; | 1351 | struct netlbl_af4list *addr4; |
1509 | struct netlbl_unlhsh_addr6 *addr6; | 1352 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1353 | u32 iter_addr6 = 0; | ||
1354 | struct netlbl_af6list *addr6; | ||
1355 | #endif | ||
1510 | 1356 | ||
1511 | cb_arg.nl_cb = cb; | 1357 | cb_arg.nl_cb = cb; |
1512 | cb_arg.skb = skb; | 1358 | cb_arg.skb = skb; |
@@ -1517,30 +1363,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb, | |||
1517 | if (iface == NULL || !iface->valid) | 1363 | if (iface == NULL || !iface->valid) |
1518 | goto unlabel_staticlistdef_return; | 1364 | goto unlabel_staticlistdef_return; |
1519 | 1365 | ||
1520 | list_for_each_entry_rcu(addr4, &iface->addr4_list, list) { | 1366 | netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) { |
1521 | if (!addr4->valid || iter_addr4++ < skip_addr4) | 1367 | if (iter_addr4++ < skip_addr4) |
1522 | continue; | 1368 | continue; |
1523 | if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, | 1369 | if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, |
1524 | iface, | 1370 | iface, |
1525 | addr4, | 1371 | netlbl_unlhsh_addr4_entry(addr4), |
1526 | NULL, | 1372 | NULL, |
1527 | &cb_arg) < 0) { | 1373 | &cb_arg) < 0) { |
1528 | iter_addr4--; | 1374 | iter_addr4--; |
1529 | goto unlabel_staticlistdef_return; | 1375 | goto unlabel_staticlistdef_return; |
1530 | } | 1376 | } |
1531 | } | 1377 | } |
1532 | list_for_each_entry_rcu(addr6, &iface->addr6_list, list) { | 1378 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1533 | if (!addr6->valid || iter_addr6++ < skip_addr6) | 1379 | netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) { |
1380 | if (iter_addr6++ < skip_addr6) | ||
1534 | continue; | 1381 | continue; |
1535 | if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, | 1382 | if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, |
1536 | iface, | 1383 | iface, |
1537 | NULL, | 1384 | NULL, |
1538 | addr6, | 1385 | netlbl_unlhsh_addr6_entry(addr6), |
1539 | &cb_arg) < 0) { | 1386 | &cb_arg) < 0) { |
1540 | iter_addr6--; | 1387 | iter_addr6--; |
1541 | goto unlabel_staticlistdef_return; | 1388 | goto unlabel_staticlistdef_return; |
1542 | } | 1389 | } |
1543 | } | 1390 | } |
1391 | #endif /* IPv6 */ | ||
1544 | 1392 | ||
1545 | unlabel_staticlistdef_return: | 1393 | unlabel_staticlistdef_return: |
1546 | rcu_read_unlock(); | 1394 | rcu_read_unlock(); |
@@ -1718,25 +1566,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, | |||
1718 | switch (family) { | 1566 | switch (family) { |
1719 | case PF_INET: { | 1567 | case PF_INET: { |
1720 | struct iphdr *hdr4; | 1568 | struct iphdr *hdr4; |
1721 | struct netlbl_unlhsh_addr4 *addr4; | 1569 | struct netlbl_af4list *addr4; |
1722 | 1570 | ||
1723 | hdr4 = ip_hdr(skb); | 1571 | hdr4 = ip_hdr(skb); |
1724 | addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); | 1572 | addr4 = netlbl_af4list_search(hdr4->saddr, |
1573 | &iface->addr4_list); | ||
1725 | if (addr4 == NULL) | 1574 | if (addr4 == NULL) |
1726 | goto unlabel_getattr_nolabel; | 1575 | goto unlabel_getattr_nolabel; |
1727 | secattr->attr.secid = addr4->secid; | 1576 | secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid; |
1728 | break; | 1577 | break; |
1729 | } | 1578 | } |
1730 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 1579 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1731 | case PF_INET6: { | 1580 | case PF_INET6: { |
1732 | struct ipv6hdr *hdr6; | 1581 | struct ipv6hdr *hdr6; |
1733 | struct netlbl_unlhsh_addr6 *addr6; | 1582 | struct netlbl_af6list *addr6; |
1734 | 1583 | ||
1735 | hdr6 = ipv6_hdr(skb); | 1584 | hdr6 = ipv6_hdr(skb); |
1736 | addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); | 1585 | addr6 = netlbl_af6list_search(&hdr6->saddr, |
1586 | &iface->addr6_list); | ||
1737 | if (addr6 == NULL) | 1587 | if (addr6 == NULL) |
1738 | goto unlabel_getattr_nolabel; | 1588 | goto unlabel_getattr_nolabel; |
1739 | secattr->attr.secid = addr6->secid; | 1589 | secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid; |
1740 | break; | 1590 | break; |
1741 | } | 1591 | } |
1742 | #endif /* IPv6 */ | 1592 | #endif /* IPv6 */ |
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 4c9890ec2528..473f94e56ead 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c | |||
@@ -629,6 +629,59 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id, | |||
629 | return 1; | 629 | return 1; |
630 | } | 630 | } |
631 | 631 | ||
632 | static const struct dmifield { | ||
633 | const char *prefix; | ||
634 | int field; | ||
635 | } dmi_fields[] = { | ||
636 | { "bvn", DMI_BIOS_VENDOR }, | ||
637 | { "bvr", DMI_BIOS_VERSION }, | ||
638 | { "bd", DMI_BIOS_DATE }, | ||
639 | { "svn", DMI_SYS_VENDOR }, | ||
640 | { "pn", DMI_PRODUCT_NAME }, | ||
641 | { "pvr", DMI_PRODUCT_VERSION }, | ||
642 | { "rvn", DMI_BOARD_VENDOR }, | ||
643 | { "rn", DMI_BOARD_NAME }, | ||
644 | { "rvr", DMI_BOARD_VERSION }, | ||
645 | { "cvn", DMI_CHASSIS_VENDOR }, | ||
646 | { "ct", DMI_CHASSIS_TYPE }, | ||
647 | { "cvr", DMI_CHASSIS_VERSION }, | ||
648 | { NULL, DMI_NONE } | ||
649 | }; | ||
650 | |||
651 | static void dmi_ascii_filter(char *d, const char *s) | ||
652 | { | ||
653 | /* Filter out characters we don't want to see in the modalias string */ | ||
654 | for (; *s; s++) | ||
655 | if (*s > ' ' && *s < 127 && *s != ':') | ||
656 | *(d++) = *s; | ||
657 | |||
658 | *d = 0; | ||
659 | } | ||
660 | |||
661 | |||
662 | static int do_dmi_entry(const char *filename, struct dmi_system_id *id, | ||
663 | char *alias) | ||
664 | { | ||
665 | int i, j; | ||
666 | |||
667 | sprintf(alias, "dmi*"); | ||
668 | |||
669 | for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { | ||
670 | for (j = 0; j < 4; j++) { | ||
671 | if (id->matches[j].slot && | ||
672 | id->matches[j].slot == dmi_fields[i].field) { | ||
673 | sprintf(alias + strlen(alias), ":%s*", | ||
674 | dmi_fields[i].prefix); | ||
675 | dmi_ascii_filter(alias + strlen(alias), | ||
676 | id->matches[j].substr); | ||
677 | strcat(alias, "*"); | ||
678 | } | ||
679 | } | ||
680 | } | ||
681 | |||
682 | strcat(alias, ":"); | ||
683 | return 1; | ||
684 | } | ||
632 | /* Ignore any prefix, eg. some architectures prepend _ */ | 685 | /* Ignore any prefix, eg. some architectures prepend _ */ |
633 | static inline int sym_is(const char *symbol, const char *name) | 686 | static inline int sym_is(const char *symbol, const char *name) |
634 | { | 687 | { |
@@ -760,6 +813,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, | |||
760 | do_table(symval, sym->st_size, | 813 | do_table(symval, sym->st_size, |
761 | sizeof(struct i2c_device_id), "i2c", | 814 | sizeof(struct i2c_device_id), "i2c", |
762 | do_i2c_entry, mod); | 815 | do_i2c_entry, mod); |
816 | else if (sym_is(symname, "__mod_dmi_device_table")) | ||
817 | do_table(symval, sym->st_size, | ||
818 | sizeof(struct dmi_system_id), "dmi", | ||
819 | do_dmi_entry, mod); | ||
763 | free(zeros); | 820 | free(zeros); |
764 | } | 821 | } |
765 | 822 | ||
diff --git a/security/inode.c b/security/inode.c index ca4958ebad8d..efea5a605466 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -20,8 +20,7 @@ | |||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/namei.h> | 21 | #include <linux/namei.h> |
22 | #include <linux/security.h> | 22 | #include <linux/security.h> |
23 | 23 | #include <linux/magic.h> | |
24 | #define SECURITYFS_MAGIC 0x73636673 | ||
25 | 24 | ||
26 | static struct vfsmount *mount; | 25 | static struct vfsmount *mount; |
27 | static int mount_count; | 26 | static int mount_count; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4a7374c12d9c..88f19536efad 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk) | |||
291 | struct sk_security_struct *ssec = sk->sk_security; | 291 | struct sk_security_struct *ssec = sk->sk_security; |
292 | 292 | ||
293 | sk->sk_security = NULL; | 293 | sk->sk_security = NULL; |
294 | selinux_netlbl_sk_security_free(ssec); | ||
294 | kfree(ssec); | 295 | kfree(ssec); |
295 | } | 296 | } |
296 | 297 | ||
@@ -2121,7 +2122,6 @@ static inline void flush_unauthorized_files(struct files_struct *files) | |||
2121 | long j = -1; | 2122 | long j = -1; |
2122 | int drop_tty = 0; | 2123 | int drop_tty = 0; |
2123 | 2124 | ||
2124 | mutex_lock(&tty_mutex); | ||
2125 | tty = get_current_tty(); | 2125 | tty = get_current_tty(); |
2126 | if (tty) { | 2126 | if (tty) { |
2127 | file_list_lock(); | 2127 | file_list_lock(); |
@@ -2139,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files) | |||
2139 | } | 2139 | } |
2140 | } | 2140 | } |
2141 | file_list_unlock(); | 2141 | file_list_unlock(); |
2142 | tty_kref_put(tty); | ||
2142 | } | 2143 | } |
2143 | mutex_unlock(&tty_mutex); | ||
2144 | /* Reset controlling tty. */ | 2144 | /* Reset controlling tty. */ |
2145 | if (drop_tty) | 2145 | if (drop_tty) |
2146 | no_tty(); | 2146 | no_tty(); |
@@ -3801,6 +3801,7 @@ out: | |||
3801 | 3801 | ||
3802 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3802 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
3803 | { | 3803 | { |
3804 | struct sock *sk = sock->sk; | ||
3804 | struct inode_security_struct *isec; | 3805 | struct inode_security_struct *isec; |
3805 | int err; | 3806 | int err; |
3806 | 3807 | ||
@@ -3814,7 +3815,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3814 | isec = SOCK_INODE(sock)->i_security; | 3815 | isec = SOCK_INODE(sock)->i_security; |
3815 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3816 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
3816 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3817 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
3817 | struct sock *sk = sock->sk; | ||
3818 | struct avc_audit_data ad; | 3818 | struct avc_audit_data ad; |
3819 | struct sockaddr_in *addr4 = NULL; | 3819 | struct sockaddr_in *addr4 = NULL; |
3820 | struct sockaddr_in6 *addr6 = NULL; | 3820 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3848,6 +3848,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3848 | goto out; | 3848 | goto out; |
3849 | } | 3849 | } |
3850 | 3850 | ||
3851 | err = selinux_netlbl_socket_connect(sk, address); | ||
3852 | |||
3851 | out: | 3853 | out: |
3852 | return err; | 3854 | return err; |
3853 | } | 3855 | } |
@@ -4077,20 +4079,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | |||
4077 | } | 4079 | } |
4078 | 4080 | ||
4079 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4081 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
4080 | struct avc_audit_data *ad, | 4082 | u16 family) |
4081 | u16 family, char *addrp) | ||
4082 | { | 4083 | { |
4083 | int err; | 4084 | int err; |
4084 | struct sk_security_struct *sksec = sk->sk_security; | 4085 | struct sk_security_struct *sksec = sk->sk_security; |
4085 | u32 peer_sid; | 4086 | u32 peer_sid; |
4086 | u32 sk_sid = sksec->sid; | 4087 | u32 sk_sid = sksec->sid; |
4088 | struct avc_audit_data ad; | ||
4089 | char *addrp; | ||
4090 | |||
4091 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4092 | ad.u.net.netif = skb->iif; | ||
4093 | ad.u.net.family = family; | ||
4094 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | ||
4095 | if (err) | ||
4096 | return err; | ||
4087 | 4097 | ||
4088 | if (selinux_compat_net) | 4098 | if (selinux_compat_net) |
4089 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, | 4099 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, |
4090 | family, addrp); | 4100 | family, addrp); |
4091 | else | 4101 | else |
4092 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4102 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4093 | PACKET__RECV, ad); | 4103 | PACKET__RECV, &ad); |
4094 | if (err) | 4104 | if (err) |
4095 | return err; | 4105 | return err; |
4096 | 4106 | ||
@@ -4099,12 +4109,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4099 | if (err) | 4109 | if (err) |
4100 | return err; | 4110 | return err; |
4101 | err = avc_has_perm(sk_sid, peer_sid, | 4111 | err = avc_has_perm(sk_sid, peer_sid, |
4102 | SECCLASS_PEER, PEER__RECV, ad); | 4112 | SECCLASS_PEER, PEER__RECV, &ad); |
4113 | if (err) | ||
4114 | selinux_netlbl_err(skb, err, 0); | ||
4103 | } else { | 4115 | } else { |
4104 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | 4116 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
4105 | if (err) | 4117 | if (err) |
4106 | return err; | 4118 | return err; |
4107 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | 4119 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
4108 | } | 4120 | } |
4109 | 4121 | ||
4110 | return err; | 4122 | return err; |
@@ -4118,6 +4130,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4118 | u32 sk_sid = sksec->sid; | 4130 | u32 sk_sid = sksec->sid; |
4119 | struct avc_audit_data ad; | 4131 | struct avc_audit_data ad; |
4120 | char *addrp; | 4132 | char *addrp; |
4133 | u8 secmark_active; | ||
4134 | u8 peerlbl_active; | ||
4121 | 4135 | ||
4122 | if (family != PF_INET && family != PF_INET6) | 4136 | if (family != PF_INET && family != PF_INET6) |
4123 | return 0; | 4137 | return 0; |
@@ -4126,6 +4140,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4126 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 4140 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
4127 | family = PF_INET; | 4141 | family = PF_INET; |
4128 | 4142 | ||
4143 | /* If any sort of compatibility mode is enabled then handoff processing | ||
4144 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
4145 | * special handling. We do this in an attempt to keep this function | ||
4146 | * as fast and as clean as possible. */ | ||
4147 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
4148 | return selinux_sock_rcv_skb_compat(sk, skb, family); | ||
4149 | |||
4150 | secmark_active = selinux_secmark_enabled(); | ||
4151 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
4152 | if (!secmark_active && !peerlbl_active) | ||
4153 | return 0; | ||
4154 | |||
4129 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4155 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4130 | ad.u.net.netif = skb->iif; | 4156 | ad.u.net.netif = skb->iif; |
4131 | ad.u.net.family = family; | 4157 | ad.u.net.family = family; |
@@ -4133,15 +4159,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4133 | if (err) | 4159 | if (err) |
4134 | return err; | 4160 | return err; |
4135 | 4161 | ||
4136 | /* If any sort of compatibility mode is enabled then handoff processing | 4162 | if (peerlbl_active) { |
4137 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
4138 | * special handling. We do this in an attempt to keep this function | ||
4139 | * as fast and as clean as possible. */ | ||
4140 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
4141 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, | ||
4142 | family, addrp); | ||
4143 | |||
4144 | if (netlbl_enabled() || selinux_xfrm_enabled()) { | ||
4145 | u32 peer_sid; | 4163 | u32 peer_sid; |
4146 | 4164 | ||
4147 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4165 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
@@ -4149,13 +4167,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4149 | return err; | 4167 | return err; |
4150 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, | 4168 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, |
4151 | peer_sid, &ad); | 4169 | peer_sid, &ad); |
4152 | if (err) | 4170 | if (err) { |
4171 | selinux_netlbl_err(skb, err, 0); | ||
4153 | return err; | 4172 | return err; |
4173 | } | ||
4154 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4174 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
4155 | PEER__RECV, &ad); | 4175 | PEER__RECV, &ad); |
4176 | if (err) | ||
4177 | selinux_netlbl_err(skb, err, 0); | ||
4156 | } | 4178 | } |
4157 | 4179 | ||
4158 | if (selinux_secmark_enabled()) { | 4180 | if (secmark_active) { |
4159 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4181 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4160 | PACKET__RECV, &ad); | 4182 | PACKET__RECV, &ad); |
4161 | if (err) | 4183 | if (err) |
@@ -4214,10 +4236,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
4214 | u32 peer_secid = SECSID_NULL; | 4236 | u32 peer_secid = SECSID_NULL; |
4215 | u16 family; | 4237 | u16 family; |
4216 | 4238 | ||
4217 | if (sock) | 4239 | if (skb && skb->protocol == htons(ETH_P_IP)) |
4240 | family = PF_INET; | ||
4241 | else if (skb && skb->protocol == htons(ETH_P_IPV6)) | ||
4242 | family = PF_INET6; | ||
4243 | else if (sock) | ||
4218 | family = sock->sk->sk_family; | 4244 | family = sock->sk->sk_family; |
4219 | else if (skb && skb->sk) | ||
4220 | family = skb->sk->sk_family; | ||
4221 | else | 4245 | else |
4222 | goto out; | 4246 | goto out; |
4223 | 4247 | ||
@@ -4275,8 +4299,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
4275 | sk->sk_family == PF_UNIX) | 4299 | sk->sk_family == PF_UNIX) |
4276 | isec->sid = sksec->sid; | 4300 | isec->sid = sksec->sid; |
4277 | sksec->sclass = isec->sclass; | 4301 | sksec->sclass = isec->sclass; |
4278 | |||
4279 | selinux_netlbl_sock_graft(sk, parent); | ||
4280 | } | 4302 | } |
4281 | 4303 | ||
4282 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 4304 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
@@ -4284,10 +4306,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
4284 | { | 4306 | { |
4285 | struct sk_security_struct *sksec = sk->sk_security; | 4307 | struct sk_security_struct *sksec = sk->sk_security; |
4286 | int err; | 4308 | int err; |
4309 | u16 family = sk->sk_family; | ||
4287 | u32 newsid; | 4310 | u32 newsid; |
4288 | u32 peersid; | 4311 | u32 peersid; |
4289 | 4312 | ||
4290 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); | 4313 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
4314 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
4315 | family = PF_INET; | ||
4316 | |||
4317 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | ||
4291 | if (err) | 4318 | if (err) |
4292 | return err; | 4319 | return err; |
4293 | if (peersid == SECSID_NULL) { | 4320 | if (peersid == SECSID_NULL) { |
@@ -4322,12 +4349,18 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
4322 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4349 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); |
4323 | } | 4350 | } |
4324 | 4351 | ||
4325 | static void selinux_inet_conn_established(struct sock *sk, | 4352 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
4326 | struct sk_buff *skb) | ||
4327 | { | 4353 | { |
4354 | u16 family = sk->sk_family; | ||
4328 | struct sk_security_struct *sksec = sk->sk_security; | 4355 | struct sk_security_struct *sksec = sk->sk_security; |
4329 | 4356 | ||
4330 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); | 4357 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
4358 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
4359 | family = PF_INET; | ||
4360 | |||
4361 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | ||
4362 | |||
4363 | selinux_netlbl_inet_conn_established(sk, family); | ||
4331 | } | 4364 | } |
4332 | 4365 | ||
4333 | static void selinux_req_classify_flow(const struct request_sock *req, | 4366 | static void selinux_req_classify_flow(const struct request_sock *req, |
@@ -4377,39 +4410,54 @@ out: | |||
4377 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | 4410 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, |
4378 | u16 family) | 4411 | u16 family) |
4379 | { | 4412 | { |
4413 | int err; | ||
4380 | char *addrp; | 4414 | char *addrp; |
4381 | u32 peer_sid; | 4415 | u32 peer_sid; |
4382 | struct avc_audit_data ad; | 4416 | struct avc_audit_data ad; |
4383 | u8 secmark_active; | 4417 | u8 secmark_active; |
4418 | u8 netlbl_active; | ||
4384 | u8 peerlbl_active; | 4419 | u8 peerlbl_active; |
4385 | 4420 | ||
4386 | if (!selinux_policycap_netpeer) | 4421 | if (!selinux_policycap_netpeer) |
4387 | return NF_ACCEPT; | 4422 | return NF_ACCEPT; |
4388 | 4423 | ||
4389 | secmark_active = selinux_secmark_enabled(); | 4424 | secmark_active = selinux_secmark_enabled(); |
4390 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | 4425 | netlbl_active = netlbl_enabled(); |
4426 | peerlbl_active = netlbl_active || selinux_xfrm_enabled(); | ||
4391 | if (!secmark_active && !peerlbl_active) | 4427 | if (!secmark_active && !peerlbl_active) |
4392 | return NF_ACCEPT; | 4428 | return NF_ACCEPT; |
4393 | 4429 | ||
4430 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | ||
4431 | return NF_DROP; | ||
4432 | |||
4394 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4433 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4395 | ad.u.net.netif = ifindex; | 4434 | ad.u.net.netif = ifindex; |
4396 | ad.u.net.family = family; | 4435 | ad.u.net.family = family; |
4397 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4436 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
4398 | return NF_DROP; | 4437 | return NF_DROP; |
4399 | 4438 | ||
4400 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4439 | if (peerlbl_active) { |
4401 | return NF_DROP; | 4440 | err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, |
4402 | 4441 | peer_sid, &ad); | |
4403 | if (peerlbl_active) | 4442 | if (err) { |
4404 | if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, | 4443 | selinux_netlbl_err(skb, err, 1); |
4405 | peer_sid, &ad) != 0) | ||
4406 | return NF_DROP; | 4444 | return NF_DROP; |
4445 | } | ||
4446 | } | ||
4407 | 4447 | ||
4408 | if (secmark_active) | 4448 | if (secmark_active) |
4409 | if (avc_has_perm(peer_sid, skb->secmark, | 4449 | if (avc_has_perm(peer_sid, skb->secmark, |
4410 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | 4450 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) |
4411 | return NF_DROP; | 4451 | return NF_DROP; |
4412 | 4452 | ||
4453 | if (netlbl_active) | ||
4454 | /* we do this in the FORWARD path and not the POST_ROUTING | ||
4455 | * path because we want to make sure we apply the necessary | ||
4456 | * labeling before IPsec is applied so we can leverage AH | ||
4457 | * protection */ | ||
4458 | if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) | ||
4459 | return NF_DROP; | ||
4460 | |||
4413 | return NF_ACCEPT; | 4461 | return NF_ACCEPT; |
4414 | } | 4462 | } |
4415 | 4463 | ||
@@ -4433,6 +4481,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, | |||
4433 | } | 4481 | } |
4434 | #endif /* IPV6 */ | 4482 | #endif /* IPV6 */ |
4435 | 4483 | ||
4484 | static unsigned int selinux_ip_output(struct sk_buff *skb, | ||
4485 | u16 family) | ||
4486 | { | ||
4487 | u32 sid; | ||
4488 | |||
4489 | if (!netlbl_enabled()) | ||
4490 | return NF_ACCEPT; | ||
4491 | |||
4492 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | ||
4493 | * because we want to make sure we apply the necessary labeling | ||
4494 | * before IPsec is applied so we can leverage AH protection */ | ||
4495 | if (skb->sk) { | ||
4496 | struct sk_security_struct *sksec = skb->sk->sk_security; | ||
4497 | sid = sksec->sid; | ||
4498 | } else | ||
4499 | sid = SECINITSID_KERNEL; | ||
4500 | if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) | ||
4501 | return NF_DROP; | ||
4502 | |||
4503 | return NF_ACCEPT; | ||
4504 | } | ||
4505 | |||
4506 | static unsigned int selinux_ipv4_output(unsigned int hooknum, | ||
4507 | struct sk_buff *skb, | ||
4508 | const struct net_device *in, | ||
4509 | const struct net_device *out, | ||
4510 | int (*okfn)(struct sk_buff *)) | ||
4511 | { | ||
4512 | return selinux_ip_output(skb, PF_INET); | ||
4513 | } | ||
4514 | |||
4436 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | 4515 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, |
4437 | int ifindex, | 4516 | int ifindex, |
4438 | struct avc_audit_data *ad, | 4517 | struct avc_audit_data *ad, |
@@ -4500,30 +4579,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, | |||
4500 | 4579 | ||
4501 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 4580 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
4502 | int ifindex, | 4581 | int ifindex, |
4503 | struct avc_audit_data *ad, | 4582 | u16 family) |
4504 | u16 family, | ||
4505 | char *addrp, | ||
4506 | u8 proto) | ||
4507 | { | 4583 | { |
4508 | struct sock *sk = skb->sk; | 4584 | struct sock *sk = skb->sk; |
4509 | struct sk_security_struct *sksec; | 4585 | struct sk_security_struct *sksec; |
4586 | struct avc_audit_data ad; | ||
4587 | char *addrp; | ||
4588 | u8 proto; | ||
4510 | 4589 | ||
4511 | if (sk == NULL) | 4590 | if (sk == NULL) |
4512 | return NF_ACCEPT; | 4591 | return NF_ACCEPT; |
4513 | sksec = sk->sk_security; | 4592 | sksec = sk->sk_security; |
4514 | 4593 | ||
4594 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4595 | ad.u.net.netif = ifindex; | ||
4596 | ad.u.net.family = family; | ||
4597 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4598 | return NF_DROP; | ||
4599 | |||
4515 | if (selinux_compat_net) { | 4600 | if (selinux_compat_net) { |
4516 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | 4601 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
4517 | ad, family, addrp)) | 4602 | &ad, family, addrp)) |
4518 | return NF_DROP; | 4603 | return NF_DROP; |
4519 | } else { | 4604 | } else { |
4520 | if (avc_has_perm(sksec->sid, skb->secmark, | 4605 | if (avc_has_perm(sksec->sid, skb->secmark, |
4521 | SECCLASS_PACKET, PACKET__SEND, ad)) | 4606 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4522 | return NF_DROP; | 4607 | return NF_DROP; |
4523 | } | 4608 | } |
4524 | 4609 | ||
4525 | if (selinux_policycap_netpeer) | 4610 | if (selinux_policycap_netpeer) |
4526 | if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) | 4611 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
4527 | return NF_DROP; | 4612 | return NF_DROP; |
4528 | 4613 | ||
4529 | return NF_ACCEPT; | 4614 | return NF_ACCEPT; |
@@ -4537,23 +4622,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4537 | struct sock *sk; | 4622 | struct sock *sk; |
4538 | struct avc_audit_data ad; | 4623 | struct avc_audit_data ad; |
4539 | char *addrp; | 4624 | char *addrp; |
4540 | u8 proto; | ||
4541 | u8 secmark_active; | 4625 | u8 secmark_active; |
4542 | u8 peerlbl_active; | 4626 | u8 peerlbl_active; |
4543 | 4627 | ||
4544 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4545 | ad.u.net.netif = ifindex; | ||
4546 | ad.u.net.family = family; | ||
4547 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4548 | return NF_DROP; | ||
4549 | |||
4550 | /* If any sort of compatibility mode is enabled then handoff processing | 4628 | /* If any sort of compatibility mode is enabled then handoff processing |
4551 | * to the selinux_ip_postroute_compat() function to deal with the | 4629 | * to the selinux_ip_postroute_compat() function to deal with the |
4552 | * special handling. We do this in an attempt to keep this function | 4630 | * special handling. We do this in an attempt to keep this function |
4553 | * as fast and as clean as possible. */ | 4631 | * as fast and as clean as possible. */ |
4554 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4632 | if (selinux_compat_net || !selinux_policycap_netpeer) |
4555 | return selinux_ip_postroute_compat(skb, ifindex, &ad, | 4633 | return selinux_ip_postroute_compat(skb, ifindex, family); |
4556 | family, addrp, proto); | ||
4557 | 4634 | ||
4558 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4635 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
4559 | * packet transformation so allow the packet to pass without any checks | 4636 | * packet transformation so allow the packet to pass without any checks |
@@ -4569,21 +4646,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4569 | if (!secmark_active && !peerlbl_active) | 4646 | if (!secmark_active && !peerlbl_active) |
4570 | return NF_ACCEPT; | 4647 | return NF_ACCEPT; |
4571 | 4648 | ||
4572 | /* if the packet is locally generated (skb->sk != NULL) then use the | 4649 | /* if the packet is being forwarded then get the peer label from the |
4573 | * socket's label as the peer label, otherwise the packet is being | 4650 | * packet itself; otherwise check to see if it is from a local |
4574 | * forwarded through this system and we need to fetch the peer label | 4651 | * application or the kernel, if from an application get the peer label |
4575 | * directly from the packet */ | 4652 | * from the sending socket, otherwise use the kernel's sid */ |
4576 | sk = skb->sk; | 4653 | sk = skb->sk; |
4577 | if (sk) { | 4654 | if (sk == NULL) { |
4655 | switch (family) { | ||
4656 | case PF_INET: | ||
4657 | if (IPCB(skb)->flags & IPSKB_FORWARDED) | ||
4658 | secmark_perm = PACKET__FORWARD_OUT; | ||
4659 | else | ||
4660 | secmark_perm = PACKET__SEND; | ||
4661 | break; | ||
4662 | case PF_INET6: | ||
4663 | if (IP6CB(skb)->flags & IP6SKB_FORWARDED) | ||
4664 | secmark_perm = PACKET__FORWARD_OUT; | ||
4665 | else | ||
4666 | secmark_perm = PACKET__SEND; | ||
4667 | break; | ||
4668 | default: | ||
4669 | return NF_DROP; | ||
4670 | } | ||
4671 | if (secmark_perm == PACKET__FORWARD_OUT) { | ||
4672 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4673 | return NF_DROP; | ||
4674 | } else | ||
4675 | peer_sid = SECINITSID_KERNEL; | ||
4676 | } else { | ||
4578 | struct sk_security_struct *sksec = sk->sk_security; | 4677 | struct sk_security_struct *sksec = sk->sk_security; |
4579 | peer_sid = sksec->sid; | 4678 | peer_sid = sksec->sid; |
4580 | secmark_perm = PACKET__SEND; | 4679 | secmark_perm = PACKET__SEND; |
4581 | } else { | ||
4582 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4583 | return NF_DROP; | ||
4584 | secmark_perm = PACKET__FORWARD_OUT; | ||
4585 | } | 4680 | } |
4586 | 4681 | ||
4682 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4683 | ad.u.net.netif = ifindex; | ||
4684 | ad.u.net.family = family; | ||
4685 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) | ||
4686 | return NF_DROP; | ||
4687 | |||
4587 | if (secmark_active) | 4688 | if (secmark_active) |
4588 | if (avc_has_perm(peer_sid, skb->secmark, | 4689 | if (avc_has_perm(peer_sid, skb->secmark, |
4589 | SECCLASS_PACKET, secmark_perm, &ad)) | 4690 | SECCLASS_PACKET, secmark_perm, &ad)) |
@@ -5657,6 +5758,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { | |||
5657 | .pf = PF_INET, | 5758 | .pf = PF_INET, |
5658 | .hooknum = NF_INET_FORWARD, | 5759 | .hooknum = NF_INET_FORWARD, |
5659 | .priority = NF_IP_PRI_SELINUX_FIRST, | 5760 | .priority = NF_IP_PRI_SELINUX_FIRST, |
5761 | }, | ||
5762 | { | ||
5763 | .hook = selinux_ipv4_output, | ||
5764 | .owner = THIS_MODULE, | ||
5765 | .pf = PF_INET, | ||
5766 | .hooknum = NF_INET_LOCAL_OUT, | ||
5767 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
5660 | } | 5768 | } |
5661 | }; | 5769 | }; |
5662 | 5770 | ||
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 487a7d81fe20..b913c8d06038 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -39,6 +39,9 @@ | |||
39 | #ifdef CONFIG_NETLABEL | 39 | #ifdef CONFIG_NETLABEL |
40 | void selinux_netlbl_cache_invalidate(void); | 40 | void selinux_netlbl_cache_invalidate(void); |
41 | 41 | ||
42 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | ||
43 | |||
44 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); | ||
42 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 45 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, |
43 | int family); | 46 | int family); |
44 | 47 | ||
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
46 | u16 family, | 49 | u16 family, |
47 | u32 *type, | 50 | u32 *type, |
48 | u32 *sid); | 51 | u32 *sid); |
52 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
53 | u16 family, | ||
54 | u32 sid); | ||
49 | 55 | ||
50 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 56 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); |
51 | int selinux_netlbl_socket_post_create(struct socket *sock); | 57 | int selinux_netlbl_socket_post_create(struct socket *sock); |
52 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 58 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); |
53 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
57 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
58 | int level, | 64 | int level, |
59 | int optname); | 65 | int optname); |
66 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); | ||
67 | |||
60 | #else | 68 | #else |
61 | static inline void selinux_netlbl_cache_invalidate(void) | 69 | static inline void selinux_netlbl_cache_invalidate(void) |
62 | { | 70 | { |
63 | return; | 71 | return; |
64 | } | 72 | } |
65 | 73 | ||
74 | static inline void selinux_netlbl_err(struct sk_buff *skb, | ||
75 | int error, | ||
76 | int gateway) | ||
77 | { | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | static inline void selinux_netlbl_sk_security_free( | ||
82 | struct sk_security_struct *ssec) | ||
83 | { | ||
84 | return; | ||
85 | } | ||
86 | |||
66 | static inline void selinux_netlbl_sk_security_reset( | 87 | static inline void selinux_netlbl_sk_security_reset( |
67 | struct sk_security_struct *ssec, | 88 | struct sk_security_struct *ssec, |
68 | int family) | 89 | int family) |
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
79 | *sid = SECSID_NULL; | 100 | *sid = SECSID_NULL; |
80 | return 0; | 101 | return 0; |
81 | } | 102 | } |
103 | static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
104 | u16 family, | ||
105 | u32 sid) | ||
106 | { | ||
107 | return 0; | ||
108 | } | ||
82 | 109 | ||
83 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 110 | static inline int selinux_netlbl_conn_setsid(struct sock *sk, |
84 | struct socket *sock) | 111 | struct sockaddr *addr) |
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static inline void selinux_netlbl_inet_conn_established(struct sock *sk, | ||
117 | u16 family) | ||
85 | { | 118 | { |
86 | return; | 119 | return; |
87 | } | 120 | } |
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
107 | { | 140 | { |
108 | return 0; | 141 | return 0; |
109 | } | 142 | } |
143 | static inline int selinux_netlbl_socket_connect(struct sock *sk, | ||
144 | struct sockaddr *addr) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
110 | #endif /* CONFIG_NETLABEL */ | 148 | #endif /* CONFIG_NETLABEL */ |
111 | 149 | ||
112 | #endif | 150 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 91070ab874ce..f8be8d7fa26d 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -109,16 +109,19 @@ struct netport_security_struct { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | struct sk_security_struct { | 111 | struct sk_security_struct { |
112 | u32 sid; /* SID of this object */ | ||
113 | u32 peer_sid; /* SID of peer */ | ||
114 | u16 sclass; /* sock security class */ | ||
115 | #ifdef CONFIG_NETLABEL | 112 | #ifdef CONFIG_NETLABEL |
116 | enum { /* NetLabel state */ | 113 | enum { /* NetLabel state */ |
117 | NLBL_UNSET = 0, | 114 | NLBL_UNSET = 0, |
118 | NLBL_REQUIRE, | 115 | NLBL_REQUIRE, |
119 | NLBL_LABELED, | 116 | NLBL_LABELED, |
117 | NLBL_REQSKB, | ||
118 | NLBL_CONNLABELED, | ||
120 | } nlbl_state; | 119 | } nlbl_state; |
120 | struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */ | ||
121 | #endif | 121 | #endif |
122 | u32 sid; /* SID of this object */ | ||
123 | u32 peer_sid; /* SID of peer */ | ||
124 | u16 sclass; /* sock security class */ | ||
122 | }; | 125 | }; |
123 | 126 | ||
124 | struct key_security_struct { | 127 | struct key_security_struct { |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 89b418392f11..f58701a7b728 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -9,7 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* | 11 | /* |
12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 | 12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -29,8 +29,12 @@ | |||
29 | 29 | ||
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
32 | #include <linux/ip.h> | ||
33 | #include <linux/ipv6.h> | ||
32 | #include <net/sock.h> | 34 | #include <net/sock.h> |
33 | #include <net/netlabel.h> | 35 | #include <net/netlabel.h> |
36 | #include <net/ip.h> | ||
37 | #include <net/ipv6.h> | ||
34 | 38 | ||
35 | #include "objsec.h" | 39 | #include "objsec.h" |
36 | #include "security.h" | 40 | #include "security.h" |
@@ -64,32 +68,69 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | |||
64 | } | 68 | } |
65 | 69 | ||
66 | /** | 70 | /** |
71 | * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr | ||
72 | * @sk: the socket | ||
73 | * | ||
74 | * Description: | ||
75 | * Generate the NetLabel security attributes for a socket, making full use of | ||
76 | * the socket's attribute cache. Returns a pointer to the security attributes | ||
77 | * on success, NULL on failure. | ||
78 | * | ||
79 | */ | ||
80 | static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | ||
81 | { | ||
82 | int rc; | ||
83 | struct sk_security_struct *sksec = sk->sk_security; | ||
84 | struct netlbl_lsm_secattr *secattr; | ||
85 | |||
86 | if (sksec->nlbl_secattr != NULL) | ||
87 | return sksec->nlbl_secattr; | ||
88 | |||
89 | secattr = netlbl_secattr_alloc(GFP_ATOMIC); | ||
90 | if (secattr == NULL) | ||
91 | return NULL; | ||
92 | rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); | ||
93 | if (rc != 0) { | ||
94 | netlbl_secattr_free(secattr); | ||
95 | return NULL; | ||
96 | } | ||
97 | sksec->nlbl_secattr = secattr; | ||
98 | |||
99 | return secattr; | ||
100 | } | ||
101 | |||
102 | /** | ||
67 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism | 103 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism |
68 | * @sk: the socket to label | 104 | * @sk: the socket to label |
69 | * @sid: the SID to use | ||
70 | * | 105 | * |
71 | * Description: | 106 | * Description: |
72 | * Attempt to label a socket using the NetLabel mechanism using the given | 107 | * Attempt to label a socket using the NetLabel mechanism. Returns zero values |
73 | * SID. Returns zero values on success, negative values on failure. | 108 | * on success, negative values on failure. |
74 | * | 109 | * |
75 | */ | 110 | */ |
76 | static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) | 111 | static int selinux_netlbl_sock_setsid(struct sock *sk) |
77 | { | 112 | { |
78 | int rc; | 113 | int rc; |
79 | struct sk_security_struct *sksec = sk->sk_security; | 114 | struct sk_security_struct *sksec = sk->sk_security; |
80 | struct netlbl_lsm_secattr secattr; | 115 | struct netlbl_lsm_secattr *secattr; |
81 | 116 | ||
82 | netlbl_secattr_init(&secattr); | 117 | if (sksec->nlbl_state != NLBL_REQUIRE) |
118 | return 0; | ||
83 | 119 | ||
84 | rc = security_netlbl_sid_to_secattr(sid, &secattr); | 120 | secattr = selinux_netlbl_sock_genattr(sk); |
85 | if (rc != 0) | 121 | if (secattr == NULL) |
86 | goto sock_setsid_return; | 122 | return -ENOMEM; |
87 | rc = netlbl_sock_setattr(sk, &secattr); | 123 | rc = netlbl_sock_setattr(sk, secattr); |
88 | if (rc == 0) | 124 | switch (rc) { |
125 | case 0: | ||
89 | sksec->nlbl_state = NLBL_LABELED; | 126 | sksec->nlbl_state = NLBL_LABELED; |
127 | break; | ||
128 | case -EDESTADDRREQ: | ||
129 | sksec->nlbl_state = NLBL_REQSKB; | ||
130 | rc = 0; | ||
131 | break; | ||
132 | } | ||
90 | 133 | ||
91 | sock_setsid_return: | ||
92 | netlbl_secattr_destroy(&secattr); | ||
93 | return rc; | 134 | return rc; |
94 | } | 135 | } |
95 | 136 | ||
@@ -106,6 +147,38 @@ void selinux_netlbl_cache_invalidate(void) | |||
106 | } | 147 | } |
107 | 148 | ||
108 | /** | 149 | /** |
150 | * selinux_netlbl_err - Handle a NetLabel packet error | ||
151 | * @skb: the packet | ||
152 | * @error: the error code | ||
153 | * @gateway: true if host is acting as a gateway, false otherwise | ||
154 | * | ||
155 | * Description: | ||
156 | * When a packet is dropped due to a call to avc_has_perm() pass the error | ||
157 | * code to the NetLabel subsystem so any protocol specific processing can be | ||
158 | * done. This is safe to call even if you are unsure if NetLabel labeling is | ||
159 | * present on the packet, NetLabel is smart enough to only act when it should. | ||
160 | * | ||
161 | */ | ||
162 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) | ||
163 | { | ||
164 | netlbl_skbuff_err(skb, error, gateway); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * selinux_netlbl_sk_security_free - Free the NetLabel fields | ||
169 | * @sssec: the sk_security_struct | ||
170 | * | ||
171 | * Description: | ||
172 | * Free all of the memory in the NetLabel fields of a sk_security_struct. | ||
173 | * | ||
174 | */ | ||
175 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | ||
176 | { | ||
177 | if (ssec->nlbl_secattr != NULL) | ||
178 | netlbl_secattr_free(ssec->nlbl_secattr); | ||
179 | } | ||
180 | |||
181 | /** | ||
109 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields | 182 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields |
110 | * @ssec: the sk_security_struct | 183 | * @ssec: the sk_security_struct |
111 | * @family: the socket family | 184 | * @family: the socket family |
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
163 | } | 236 | } |
164 | 237 | ||
165 | /** | 238 | /** |
166 | * selinux_netlbl_sock_graft - Netlabel the new socket | 239 | * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid |
240 | * @skb: the packet | ||
241 | * @family: protocol family | ||
242 | * @sid: the SID | ||
243 | * | ||
244 | * Description | ||
245 | * Call the NetLabel mechanism to set the label of a packet using @sid. | ||
246 | * Returns zero on auccess, negative values on failure. | ||
247 | * | ||
248 | */ | ||
249 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
250 | u16 family, | ||
251 | u32 sid) | ||
252 | { | ||
253 | int rc; | ||
254 | struct netlbl_lsm_secattr secattr_storage; | ||
255 | struct netlbl_lsm_secattr *secattr = NULL; | ||
256 | struct sock *sk; | ||
257 | |||
258 | /* if this is a locally generated packet check to see if it is already | ||
259 | * being labeled by it's parent socket, if it is just exit */ | ||
260 | sk = skb->sk; | ||
261 | if (sk != NULL) { | ||
262 | struct sk_security_struct *sksec = sk->sk_security; | ||
263 | if (sksec->nlbl_state != NLBL_REQSKB) | ||
264 | return 0; | ||
265 | secattr = sksec->nlbl_secattr; | ||
266 | } | ||
267 | if (secattr == NULL) { | ||
268 | secattr = &secattr_storage; | ||
269 | netlbl_secattr_init(secattr); | ||
270 | rc = security_netlbl_sid_to_secattr(sid, secattr); | ||
271 | if (rc != 0) | ||
272 | goto skbuff_setsid_return; | ||
273 | } | ||
274 | |||
275 | rc = netlbl_skbuff_setattr(skb, family, secattr); | ||
276 | |||
277 | skbuff_setsid_return: | ||
278 | if (secattr == &secattr_storage) | ||
279 | netlbl_secattr_destroy(secattr); | ||
280 | return rc; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection | ||
167 | * @sk: the new connection | 285 | * @sk: the new connection |
168 | * @sock: the new socket | ||
169 | * | 286 | * |
170 | * Description: | 287 | * Description: |
171 | * The connection represented by @sk is being grafted onto @sock so set the | 288 | * A new connection has been established on @sk so make sure it is labeled |
172 | * socket's NetLabel to match the SID of @sk. | 289 | * correctly with the NetLabel susbsystem. |
173 | * | 290 | * |
174 | */ | 291 | */ |
175 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | 292 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) |
176 | { | 293 | { |
294 | int rc; | ||
177 | struct sk_security_struct *sksec = sk->sk_security; | 295 | struct sk_security_struct *sksec = sk->sk_security; |
178 | struct netlbl_lsm_secattr secattr; | 296 | struct netlbl_lsm_secattr *secattr; |
179 | u32 nlbl_peer_sid; | 297 | struct inet_sock *sk_inet = inet_sk(sk); |
298 | struct sockaddr_in addr; | ||
180 | 299 | ||
181 | if (sksec->nlbl_state != NLBL_REQUIRE) | 300 | if (sksec->nlbl_state != NLBL_REQUIRE) |
182 | return; | 301 | return; |
183 | 302 | ||
184 | netlbl_secattr_init(&secattr); | 303 | secattr = selinux_netlbl_sock_genattr(sk); |
185 | if (netlbl_sock_getattr(sk, &secattr) == 0 && | 304 | if (secattr == NULL) |
186 | secattr.flags != NETLBL_SECATTR_NONE && | 305 | return; |
187 | security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0) | ||
188 | sksec->peer_sid = nlbl_peer_sid; | ||
189 | netlbl_secattr_destroy(&secattr); | ||
190 | 306 | ||
191 | /* Try to set the NetLabel on the socket to save time later, if we fail | 307 | rc = netlbl_sock_setattr(sk, secattr); |
192 | * here we will pick up the pieces in later calls to | 308 | switch (rc) { |
193 | * selinux_netlbl_inode_permission(). */ | 309 | case 0: |
194 | selinux_netlbl_sock_setsid(sk, sksec->sid); | 310 | sksec->nlbl_state = NLBL_LABELED; |
311 | break; | ||
312 | case -EDESTADDRREQ: | ||
313 | /* no PF_INET6 support yet because we don't support any IPv6 | ||
314 | * labeling protocols */ | ||
315 | if (family != PF_INET) { | ||
316 | sksec->nlbl_state = NLBL_UNSET; | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | addr.sin_family = family; | ||
321 | addr.sin_addr.s_addr = sk_inet->daddr; | ||
322 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | ||
323 | secattr) != 0) { | ||
324 | /* we failed to label the connected socket (could be | ||
325 | * for a variety of reasons, the actual "why" isn't | ||
326 | * important here) so we have to go to our backup plan, | ||
327 | * labeling the packets individually in the netfilter | ||
328 | * local output hook. this is okay but we need to | ||
329 | * adjust the MSS of the connection to take into | ||
330 | * account any labeling overhead, since we don't know | ||
331 | * the exact overhead at this point we'll use the worst | ||
332 | * case value which is 40 bytes for IPv4 */ | ||
333 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
334 | sk_conn->icsk_ext_hdr_len += 40 - | ||
335 | (sk_inet->opt ? sk_inet->opt->optlen : 0); | ||
336 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
337 | |||
338 | sksec->nlbl_state = NLBL_REQSKB; | ||
339 | } else | ||
340 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
341 | break; | ||
342 | default: | ||
343 | /* note that we are failing to label the socket which could be | ||
344 | * a bad thing since it means traffic could leave the system | ||
345 | * without the desired labeling, however, all is not lost as | ||
346 | * we have a check in selinux_netlbl_inode_permission() to | ||
347 | * pick up the pieces that we might drop here because we can't | ||
348 | * return an error code */ | ||
349 | break; | ||
350 | } | ||
195 | } | 351 | } |
196 | 352 | ||
197 | /** | 353 | /** |
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | |||
205 | */ | 361 | */ |
206 | int selinux_netlbl_socket_post_create(struct socket *sock) | 362 | int selinux_netlbl_socket_post_create(struct socket *sock) |
207 | { | 363 | { |
208 | struct sock *sk = sock->sk; | 364 | return selinux_netlbl_sock_setsid(sock->sk); |
209 | struct sk_security_struct *sksec = sk->sk_security; | ||
210 | |||
211 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
212 | return 0; | ||
213 | |||
214 | return selinux_netlbl_sock_setsid(sk, sksec->sid); | ||
215 | } | 365 | } |
216 | 366 | ||
217 | /** | 367 | /** |
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) | |||
246 | local_bh_disable(); | 396 | local_bh_disable(); |
247 | bh_lock_sock_nested(sk); | 397 | bh_lock_sock_nested(sk); |
248 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) | 398 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) |
249 | rc = selinux_netlbl_sock_setsid(sk, sksec->sid); | 399 | rc = selinux_netlbl_sock_setsid(sk); |
250 | else | 400 | else |
251 | rc = 0; | 401 | rc = 0; |
252 | bh_unlock_sock(sk); | 402 | bh_unlock_sock(sk); |
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
307 | return 0; | 457 | return 0; |
308 | 458 | ||
309 | if (nlbl_sid != SECINITSID_UNLABELED) | 459 | if (nlbl_sid != SECINITSID_UNLABELED) |
310 | netlbl_skbuff_err(skb, rc); | 460 | netlbl_skbuff_err(skb, rc, 0); |
311 | return rc; | 461 | return rc; |
312 | } | 462 | } |
313 | 463 | ||
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
334 | struct netlbl_lsm_secattr secattr; | 484 | struct netlbl_lsm_secattr secattr; |
335 | 485 | ||
336 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | 486 | if (level == IPPROTO_IP && optname == IP_OPTIONS && |
337 | sksec->nlbl_state == NLBL_LABELED) { | 487 | (sksec->nlbl_state == NLBL_LABELED || |
488 | sksec->nlbl_state == NLBL_CONNLABELED)) { | ||
338 | netlbl_secattr_init(&secattr); | 489 | netlbl_secattr_init(&secattr); |
339 | lock_sock(sk); | 490 | lock_sock(sk); |
340 | rc = netlbl_sock_getattr(sk, &secattr); | 491 | rc = netlbl_sock_getattr(sk, &secattr); |
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
346 | 497 | ||
347 | return rc; | 498 | return rc; |
348 | } | 499 | } |
500 | |||
501 | /** | ||
502 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
503 | * @sk: the socket to label | ||
504 | * @addr: the destination address | ||
505 | * | ||
506 | * Description: | ||
507 | * Attempt to label a connected socket with NetLabel using the given address. | ||
508 | * Returns zero values on success, negative values on failure. | ||
509 | * | ||
510 | */ | ||
511 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
512 | { | ||
513 | int rc; | ||
514 | struct sk_security_struct *sksec = sk->sk_security; | ||
515 | struct netlbl_lsm_secattr *secattr; | ||
516 | |||
517 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
518 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
519 | return 0; | ||
520 | |||
521 | local_bh_disable(); | ||
522 | bh_lock_sock_nested(sk); | ||
523 | |||
524 | /* connected sockets are allowed to disconnect when the address family | ||
525 | * is set to AF_UNSPEC, if that is what is happening we want to reset | ||
526 | * the socket */ | ||
527 | if (addr->sa_family == AF_UNSPEC) { | ||
528 | netlbl_sock_delattr(sk); | ||
529 | sksec->nlbl_state = NLBL_REQSKB; | ||
530 | rc = 0; | ||
531 | goto socket_connect_return; | ||
532 | } | ||
533 | secattr = selinux_netlbl_sock_genattr(sk); | ||
534 | if (secattr == NULL) { | ||
535 | rc = -ENOMEM; | ||
536 | goto socket_connect_return; | ||
537 | } | ||
538 | rc = netlbl_conn_setattr(sk, addr, secattr); | ||
539 | if (rc == 0) | ||
540 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
541 | |||
542 | socket_connect_return: | ||
543 | bh_unlock_sock(sk); | ||
544 | local_bh_enable(); | ||
545 | return rc; | ||
546 | } | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ab0cc0c7b944..343c8ab14af0 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2955,7 +2955,7 @@ netlbl_secattr_to_sid_return_cleanup: | |||
2955 | */ | 2955 | */ |
2956 | int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | 2956 | int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) |
2957 | { | 2957 | { |
2958 | int rc = -ENOENT; | 2958 | int rc; |
2959 | struct context *ctx; | 2959 | struct context *ctx; |
2960 | 2960 | ||
2961 | if (!ss_initialized) | 2961 | if (!ss_initialized) |
@@ -2963,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | |||
2963 | 2963 | ||
2964 | read_lock(&policy_rwlock); | 2964 | read_lock(&policy_rwlock); |
2965 | ctx = sidtab_search(&sidtab, sid); | 2965 | ctx = sidtab_search(&sidtab, sid); |
2966 | if (ctx == NULL) | 2966 | if (ctx == NULL) { |
2967 | rc = -ENOENT; | ||
2967 | goto netlbl_sid_to_secattr_failure; | 2968 | goto netlbl_sid_to_secattr_failure; |
2969 | } | ||
2968 | secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], | 2970 | secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], |
2969 | GFP_ATOMIC); | 2971 | GFP_ATOMIC); |
2970 | secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; | 2972 | if (secattr->domain == NULL) { |
2973 | rc = -ENOMEM; | ||
2974 | goto netlbl_sid_to_secattr_failure; | ||
2975 | } | ||
2976 | secattr->attr.secid = sid; | ||
2977 | secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; | ||
2971 | mls_export_netlbl_lvl(ctx, secattr); | 2978 | mls_export_netlbl_lvl(ctx, secattr); |
2972 | rc = mls_export_netlbl_cat(ctx, secattr); | 2979 | rc = mls_export_netlbl_cat(ctx, secattr); |
2973 | if (rc != 0) | 2980 | if (rc != 0) |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 87d75417ea93..6e2dc0bab70d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -2179,7 +2179,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
2179 | * This is the simplist possible security model | 2179 | * This is the simplist possible security model |
2180 | * for networking. | 2180 | * for networking. |
2181 | */ | 2181 | */ |
2182 | return smk_access(smack, ssp->smk_in, MAY_WRITE); | 2182 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); |
2183 | if (rc != 0) | ||
2184 | netlbl_skbuff_err(skb, rc, 0); | ||
2185 | return rc; | ||
2183 | } | 2186 | } |
2184 | 2187 | ||
2185 | /** | 2188 | /** |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index e7c642458ec9..c21d8c8bf0c7 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -354,9 +354,11 @@ static void smk_cipso_doi(void) | |||
354 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; | 354 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; |
355 | 355 | ||
356 | rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); | 356 | rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); |
357 | if (rc != 0) | 357 | if (rc != 0) { |
358 | printk(KERN_WARNING "%s:%d add rc = %d\n", | 358 | printk(KERN_WARNING "%s:%d add rc = %d\n", |
359 | __func__, __LINE__, rc); | 359 | __func__, __LINE__, rc); |
360 | kfree(doip); | ||
361 | } | ||
360 | } | 362 | } |
361 | 363 | ||
362 | /** | 364 | /** |
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index b63839e8f9bd..456a1b4d7832 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c | |||
@@ -30,7 +30,7 @@ | |||
30 | ************************************************************************** | 30 | ************************************************************************** |
31 | * | 31 | * |
32 | * History | 32 | * History |
33 | * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 33 | * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk> |
34 | * Removed non existant WM9700 | 34 | * Removed non existant WM9700 |
35 | * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 | 35 | * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 |
36 | * WM9712 and WM9717 | 36 | * WM9712 and WM9717 |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 6ce3cbe98a6a..6e831aff1bd0 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97) | |||
476 | } | 476 | } |
477 | 477 | ||
478 | /* | 478 | /* |
479 | * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 479 | * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk> |
480 | * removed broken wolfson00 patch. | 480 | * removed broken wolfson00 patch. |
481 | * added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. | 481 | * added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. |
482 | */ | 482 | */ |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c461baa83c2a..c59065513118 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = { | |||
322 | 0x1a, 0x1b | 322 | 0x1a, 0x1b |
323 | }; | 323 | }; |
324 | 324 | ||
325 | static hda_nid_t stac92hd71bxx_dmux_nids[1] = { | 325 | static hda_nid_t stac92hd71bxx_dmux_nids[2] = { |
326 | 0x1c, | 326 | 0x1c, 0x1d, |
327 | }; | 327 | }; |
328 | 328 | ||
329 | static hda_nid_t stac92hd71bxx_smux_nids[2] = { | 329 | static hda_nid_t stac92hd71bxx_smux_nids[2] = { |
@@ -861,20 +861,18 @@ static struct hda_verb stac92hd71bxx_core_init[] = { | |||
861 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 861 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
862 | /* connect headphone jack to dac1 */ | 862 | /* connect headphone jack to dac1 */ |
863 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | 863 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, |
864 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
865 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | 864 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ |
866 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 865 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
867 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 866 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
868 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 867 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
869 | }; | 868 | }; |
870 | 869 | ||
871 | #define HD_DISABLE_PORTF 3 | 870 | #define HD_DISABLE_PORTF 2 |
872 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { | 871 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { |
873 | /* start of config #1 */ | 872 | /* start of config #1 */ |
874 | 873 | ||
875 | /* connect port 0f to audio mixer */ | 874 | /* connect port 0f to audio mixer */ |
876 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | 875 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, |
877 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
878 | /* unmute right and left channels for node 0x0f */ | 876 | /* unmute right and left channels for node 0x0f */ |
879 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 877 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
880 | /* start of config #2 */ | 878 | /* start of config #2 */ |
@@ -883,10 +881,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = { | |||
883 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 881 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
884 | /* connect headphone jack to dac1 */ | 882 | /* connect headphone jack to dac1 */ |
885 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | 883 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, |
886 | /* connect port 0d to audio mixer */ | ||
887 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
888 | /* unmute dac0 input in audio mixer */ | ||
889 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, | ||
890 | /* unmute right and left channels for nodes 0x0a, 0xd */ | 884 | /* unmute right and left channels for nodes 0x0a, 0xd */ |
891 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 885 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
892 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 886 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
@@ -1107,6 +1101,7 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { | |||
1107 | 1101 | ||
1108 | static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { | 1102 | static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { |
1109 | STAC_INPUT_SOURCE(2), | 1103 | STAC_INPUT_SOURCE(2), |
1104 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2), | ||
1110 | 1105 | ||
1111 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), | 1106 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), |
1112 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), | 1107 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), |
@@ -1119,8 +1114,17 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { | |||
1119 | HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), | 1114 | HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), |
1120 | */ | 1115 | */ |
1121 | 1116 | ||
1122 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), | 1117 | HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT), |
1123 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), | 1118 | HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT), |
1119 | |||
1120 | HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT), | ||
1121 | HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT), | ||
1122 | |||
1123 | HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT), | ||
1124 | HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT), | ||
1125 | |||
1126 | HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT), | ||
1127 | HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT), | ||
1124 | { } /* end */ | 1128 | { } /* end */ |
1125 | }; | 1129 | }; |
1126 | 1130 | ||
@@ -1649,7 +1653,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | |||
1649 | 1653 | ||
1650 | static unsigned int ref92hd71bxx_pin_configs[11] = { | 1654 | static unsigned int ref92hd71bxx_pin_configs[11] = { |
1651 | 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, | 1655 | 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, |
1652 | 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0, | 1656 | 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, |
1653 | 0x90a000f0, 0x01452050, 0x01452050, | 1657 | 0x90a000f0, 0x01452050, 0x01452050, |
1654 | }; | 1658 | }; |
1655 | 1659 | ||
@@ -3000,7 +3004,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) | |||
3000 | 3004 | ||
3001 | /* labels for amp mux outputs */ | 3005 | /* labels for amp mux outputs */ |
3002 | static const char *stac92xx_amp_labels[3] = { | 3006 | static const char *stac92xx_amp_labels[3] = { |
3003 | "Front Microphone", "Microphone", "Line In" | 3007 | "Front Microphone", "Microphone", "Line In", |
3004 | }; | 3008 | }; |
3005 | 3009 | ||
3006 | /* create amp out controls mux on capable codecs */ | 3010 | /* create amp out controls mux on capable codecs */ |
@@ -4327,6 +4331,16 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = { | |||
4327 | #endif | 4331 | #endif |
4328 | }; | 4332 | }; |
4329 | 4333 | ||
4334 | static struct hda_input_mux stac92hd71bxx_dmux = { | ||
4335 | .num_items = 4, | ||
4336 | .items = { | ||
4337 | { "Analog Inputs", 0x00 }, | ||
4338 | { "Mixer", 0x01 }, | ||
4339 | { "Digital Mic 1", 0x02 }, | ||
4340 | { "Digital Mic 2", 0x03 }, | ||
4341 | } | ||
4342 | }; | ||
4343 | |||
4330 | static int patch_stac92hd71bxx(struct hda_codec *codec) | 4344 | static int patch_stac92hd71bxx(struct hda_codec *codec) |
4331 | { | 4345 | { |
4332 | struct sigmatel_spec *spec; | 4346 | struct sigmatel_spec *spec; |
@@ -4341,6 +4355,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
4341 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); | 4355 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); |
4342 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | 4356 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); |
4343 | spec->pin_nids = stac92hd71bxx_pin_nids; | 4357 | spec->pin_nids = stac92hd71bxx_pin_nids; |
4358 | memcpy(&spec->private_dimux, &stac92hd71bxx_dmux, | ||
4359 | sizeof(stac92hd71bxx_dmux)); | ||
4344 | spec->board_config = snd_hda_check_board_config(codec, | 4360 | spec->board_config = snd_hda_check_board_config(codec, |
4345 | STAC_92HD71BXX_MODELS, | 4361 | STAC_92HD71BXX_MODELS, |
4346 | stac92hd71bxx_models, | 4362 | stac92hd71bxx_models, |
@@ -4392,6 +4408,7 @@ again: | |||
4392 | /* no output amps */ | 4408 | /* no output amps */ |
4393 | spec->num_pwrs = 0; | 4409 | spec->num_pwrs = 0; |
4394 | spec->mixer = stac92hd71bxx_analog_mixer; | 4410 | spec->mixer = stac92hd71bxx_analog_mixer; |
4411 | spec->dinput_mux = &spec->private_dimux; | ||
4395 | 4412 | ||
4396 | /* disable VSW */ | 4413 | /* disable VSW */ |
4397 | spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; | 4414 | spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; |
@@ -4409,12 +4426,13 @@ again: | |||
4409 | spec->num_pwrs = 0; | 4426 | spec->num_pwrs = 0; |
4410 | /* fallthru */ | 4427 | /* fallthru */ |
4411 | default: | 4428 | default: |
4429 | spec->dinput_mux = &spec->private_dimux; | ||
4412 | spec->mixer = stac92hd71bxx_analog_mixer; | 4430 | spec->mixer = stac92hd71bxx_analog_mixer; |
4413 | spec->init = stac92hd71bxx_analog_core_init; | 4431 | spec->init = stac92hd71bxx_analog_core_init; |
4414 | codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; | 4432 | codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; |
4415 | } | 4433 | } |
4416 | 4434 | ||
4417 | spec->aloopback_mask = 0x20; | 4435 | spec->aloopback_mask = 0x50; |
4418 | spec->aloopback_shift = 0; | 4436 | spec->aloopback_shift = 0; |
4419 | 4437 | ||
4420 | if (spec->board_config > STAC_92HD71BXX_REF) { | 4438 | if (spec->board_config > STAC_92HD71BXX_REF) { |
@@ -4456,6 +4474,10 @@ again: | |||
4456 | spec->multiout.num_dacs = 1; | 4474 | spec->multiout.num_dacs = 1; |
4457 | spec->multiout.hp_nid = 0x11; | 4475 | spec->multiout.hp_nid = 0x11; |
4458 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; | 4476 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; |
4477 | if (spec->dinput_mux) | ||
4478 | spec->private_dimux.num_items += | ||
4479 | spec->num_dmics - | ||
4480 | (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1); | ||
4459 | 4481 | ||
4460 | err = stac92xx_parse_auto_config(codec, 0x21, 0x23); | 4482 | err = stac92xx_parse_auto_config(codec, 0x21, 0x23); |
4461 | if (!err) { | 4483 | if (!err) { |
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig index 905186502e00..85a883299c2e 100644 --- a/sound/soc/at91/Kconfig +++ b/sound/soc/at91/Kconfig | |||
@@ -8,20 +8,3 @@ config SND_AT91_SOC | |||
8 | 8 | ||
9 | config SND_AT91_SOC_SSC | 9 | config SND_AT91_SOC_SSC |
10 | tristate | 10 | tristate |
11 | |||
12 | config SND_AT91_SOC_ETI_B1_WM8731 | ||
13 | tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards" | ||
14 | depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1) | ||
15 | select SND_AT91_SOC_SSC | ||
16 | select SND_SOC_WM8731 | ||
17 | help | ||
18 | Say Y if you want to add support for SoC audio on WM8731-based | ||
19 | Endrelia Technologies Inc ETI-B1 or ETI-C1 boards. | ||
20 | |||
21 | config SND_AT91_SOC_ETI_SLAVE | ||
22 | bool "Run codec in slave Mode on Endrelia boards" | ||
23 | depends on SND_AT91_SOC_ETI_B1_WM8731 | ||
24 | default n | ||
25 | help | ||
26 | Say Y if you want to run with the AT91 SSC generating the BCLK | ||
27 | and LRC signals on Endrelia boards. | ||
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile index f23da17cc328..b817f11df286 100644 --- a/sound/soc/at91/Makefile +++ b/sound/soc/at91/Makefile | |||
@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o | |||
4 | 4 | ||
5 | obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o | 5 | obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o |
6 | obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o | 6 | obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o |
7 | |||
8 | # AT91 Machine Support | ||
9 | snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o | ||
10 | |||
11 | obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o | ||
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c index a5b1a79ebffb..1b61cc461261 100644 --- a/sound/soc/at91/at91-ssc.c +++ b/sound/soc/at91/at91-ssc.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Endrelia Technologies Inc. | 5 | * Endrelia Technologies Inc. |
6 | * | 6 | * |
7 | * Based on pxa2xx Platform drivers by | 7 | * Based on pxa2xx Platform drivers by |
8 | * Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 8 | * Liam Girdwood <lrg@slimlogic.co.uk> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c deleted file mode 100644 index 684781e4088b..000000000000 --- a/sound/soc/at91/eti_b1_wm8731.c +++ /dev/null | |||
@@ -1,349 +0,0 @@ | |||
1 | /* | ||
2 | * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board. | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * Created: Mar 29, 2006 | ||
7 | * | ||
8 | * Based on corgi.c by: | ||
9 | * | ||
10 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
11 | * Copyright 2005 Openedhand Ltd. | ||
12 | * | ||
13 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
14 | * Richard Purdie <richard@openedhand.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify it | ||
17 | * under the terms of the GNU General Public License as published by the | ||
18 | * Free Software Foundation; either version 2 of the License, or (at your | ||
19 | * option) any later version. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <sound/soc-dapm.h> | ||
34 | |||
35 | #include <mach/hardware.h> | ||
36 | #include <mach/gpio.h> | ||
37 | |||
38 | #include "../codecs/wm8731.h" | ||
39 | #include "at91-pcm.h" | ||
40 | #include "at91-ssc.h" | ||
41 | |||
42 | #if 0 | ||
43 | #define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x) | ||
44 | #else | ||
45 | #define DBG(x...) | ||
46 | #endif | ||
47 | |||
48 | static struct clk *pck1_clk; | ||
49 | static struct clk *pllb_clk; | ||
50 | |||
51 | |||
52 | static int eti_b1_startup(struct snd_pcm_substream *substream) | ||
53 | { | ||
54 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
55 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
56 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
57 | int ret; | ||
58 | |||
59 | /* cpu clock is the AT91 master clock sent to the SSC */ | ||
60 | ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK, | ||
61 | 60000000, SND_SOC_CLOCK_IN); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | |||
65 | /* codec system clock is supplied by PCK1, set to 12MHz */ | ||
66 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, | ||
67 | 12000000, SND_SOC_CLOCK_IN); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
71 | /* Start PCK1 clock. */ | ||
72 | clk_enable(pck1_clk); | ||
73 | DBG("pck1 started\n"); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static void eti_b1_shutdown(struct snd_pcm_substream *substream) | ||
79 | { | ||
80 | /* Stop PCK1 clock. */ | ||
81 | clk_disable(pck1_clk); | ||
82 | DBG("pck1 stopped\n"); | ||
83 | } | ||
84 | |||
85 | static int eti_b1_hw_params(struct snd_pcm_substream *substream, | ||
86 | struct snd_pcm_hw_params *params) | ||
87 | { | ||
88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
89 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
90 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
91 | int ret; | ||
92 | |||
93 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | ||
94 | unsigned int rate; | ||
95 | int cmr_div, period; | ||
96 | |||
97 | /* set codec DAI configuration */ | ||
98 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
99 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
100 | if (ret < 0) | ||
101 | return ret; | ||
102 | |||
103 | /* set cpu DAI configuration */ | ||
104 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
105 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
106 | if (ret < 0) | ||
107 | return ret; | ||
108 | |||
109 | /* | ||
110 | * The SSC clock dividers depend on the sample rate. The CMR.DIV | ||
111 | * field divides the system master clock MCK to drive the SSC TK | ||
112 | * signal which provides the codec BCLK. The TCMR.PERIOD and | ||
113 | * RCMR.PERIOD fields further divide the BCLK signal to drive | ||
114 | * the SSC TF and RF signals which provide the codec DACLRC and | ||
115 | * ADCLRC clocks. | ||
116 | * | ||
117 | * The dividers were determined through trial and error, where a | ||
118 | * CMR.DIV value is chosen such that the resulting BCLK value is | ||
119 | * divisible, or almost divisible, by (2 * sample rate), and then | ||
120 | * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. | ||
121 | */ | ||
122 | rate = params_rate(params); | ||
123 | |||
124 | switch (rate) { | ||
125 | case 8000: | ||
126 | cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */ | ||
127 | period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */ | ||
128 | break; | ||
129 | case 32000: | ||
130 | cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */ | ||
131 | period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */ | ||
132 | break; | ||
133 | case 48000: | ||
134 | cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */ | ||
135 | period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */ | ||
136 | break; | ||
137 | default: | ||
138 | printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | /* set the MCK divider for BCLK */ | ||
143 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
148 | /* set the BCLK divider for DACLRC */ | ||
149 | ret = snd_soc_dai_set_clkdiv(cpu_dai, | ||
150 | AT91SSC_TCMR_PERIOD, period); | ||
151 | } else { | ||
152 | /* set the BCLK divider for ADCLRC */ | ||
153 | ret = snd_soc_dai_set_clkdiv(cpu_dai, | ||
154 | AT91SSC_RCMR_PERIOD, period); | ||
155 | } | ||
156 | if (ret < 0) | ||
157 | return ret; | ||
158 | |||
159 | #else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ | ||
160 | /* | ||
161 | * Codec in Master Mode. | ||
162 | */ | ||
163 | |||
164 | /* set codec DAI configuration */ | ||
165 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
166 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
167 | if (ret < 0) | ||
168 | return ret; | ||
169 | |||
170 | /* set cpu DAI configuration */ | ||
171 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
172 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
173 | if (ret < 0) | ||
174 | return ret; | ||
175 | |||
176 | #endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static struct snd_soc_ops eti_b1_ops = { | ||
182 | .startup = eti_b1_startup, | ||
183 | .hw_params = eti_b1_hw_params, | ||
184 | .shutdown = eti_b1_shutdown, | ||
185 | }; | ||
186 | |||
187 | |||
188 | static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { | ||
189 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
190 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
191 | }; | ||
192 | |||
193 | static const struct snd_soc_dapm_route intercon[] = { | ||
194 | |||
195 | /* speaker connected to LHPOUT */ | ||
196 | {"Ext Spk", NULL, "LHPOUT"}, | ||
197 | |||
198 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | ||
199 | {"MICIN", NULL, "Mic Bias"}, | ||
200 | {"Mic Bias", NULL, "Int Mic"}, | ||
201 | }; | ||
202 | |||
203 | /* | ||
204 | * Logic for a wm8731 as connected on a Endrelia ETI-B1 board. | ||
205 | */ | ||
206 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) | ||
207 | { | ||
208 | DBG("eti_b1_wm8731_init() called\n"); | ||
209 | |||
210 | /* Add specific widgets */ | ||
211 | snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets, | ||
212 | ARRAY_SIZE(eti_b1_dapm_widgets)); | ||
213 | |||
214 | /* Set up specific audio path interconnects */ | ||
215 | snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon)); | ||
216 | |||
217 | /* not connected */ | ||
218 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); | ||
219 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); | ||
220 | |||
221 | /* always connected */ | ||
222 | snd_soc_dapm_enable_pin(codec, "Int Mic"); | ||
223 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
224 | |||
225 | snd_soc_dapm_sync(codec); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static struct snd_soc_dai_link eti_b1_dai = { | ||
231 | .name = "WM8731", | ||
232 | .stream_name = "WM8731 PCM", | ||
233 | .cpu_dai = &at91_ssc_dai[1], | ||
234 | .codec_dai = &wm8731_dai, | ||
235 | .init = eti_b1_wm8731_init, | ||
236 | .ops = &eti_b1_ops, | ||
237 | }; | ||
238 | |||
239 | static struct snd_soc_machine snd_soc_machine_eti_b1 = { | ||
240 | .name = "ETI_B1_WM8731", | ||
241 | .dai_link = &eti_b1_dai, | ||
242 | .num_links = 1, | ||
243 | }; | ||
244 | |||
245 | static struct wm8731_setup_data eti_b1_wm8731_setup = { | ||
246 | .i2c_bus = 0, | ||
247 | .i2c_address = 0x1a, | ||
248 | }; | ||
249 | |||
250 | static struct snd_soc_device eti_b1_snd_devdata = { | ||
251 | .machine = &snd_soc_machine_eti_b1, | ||
252 | .platform = &at91_soc_platform, | ||
253 | .codec_dev = &soc_codec_dev_wm8731, | ||
254 | .codec_data = &eti_b1_wm8731_setup, | ||
255 | }; | ||
256 | |||
257 | static struct platform_device *eti_b1_snd_device; | ||
258 | |||
259 | static int __init eti_b1_init(void) | ||
260 | { | ||
261 | int ret; | ||
262 | struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; | ||
263 | |||
264 | if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) { | ||
265 | DBG("SSC1 memory region is busy\n"); | ||
266 | return -EBUSY; | ||
267 | } | ||
268 | |||
269 | ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K); | ||
270 | if (!ssc->base) { | ||
271 | DBG("SSC1 memory ioremap failed\n"); | ||
272 | ret = -ENOMEM; | ||
273 | goto fail_release_mem; | ||
274 | } | ||
275 | |||
276 | ssc->pid = AT91RM9200_ID_SSC1; | ||
277 | |||
278 | eti_b1_snd_device = platform_device_alloc("soc-audio", -1); | ||
279 | if (!eti_b1_snd_device) { | ||
280 | DBG("platform device allocation failed\n"); | ||
281 | ret = -ENOMEM; | ||
282 | goto fail_io_unmap; | ||
283 | } | ||
284 | |||
285 | platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata); | ||
286 | eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev; | ||
287 | |||
288 | ret = platform_device_add(eti_b1_snd_device); | ||
289 | if (ret) { | ||
290 | DBG("platform device add failed\n"); | ||
291 | platform_device_put(eti_b1_snd_device); | ||
292 | goto fail_io_unmap; | ||
293 | } | ||
294 | |||
295 | at91_set_A_periph(AT91_PIN_PB6, 0); /* TF1 */ | ||
296 | at91_set_A_periph(AT91_PIN_PB7, 0); /* TK1 */ | ||
297 | at91_set_A_periph(AT91_PIN_PB8, 0); /* TD1 */ | ||
298 | at91_set_A_periph(AT91_PIN_PB9, 0); /* RD1 */ | ||
299 | /* at91_set_A_periph(AT91_PIN_PB10, 0);*/ /* RK1 */ | ||
300 | at91_set_A_periph(AT91_PIN_PB11, 0); /* RF1 */ | ||
301 | |||
302 | /* | ||
303 | * Set PCK1 parent to PLLB and its rate to 12 Mhz. | ||
304 | */ | ||
305 | pllb_clk = clk_get(NULL, "pllb"); | ||
306 | pck1_clk = clk_get(NULL, "pck1"); | ||
307 | |||
308 | clk_set_parent(pck1_clk, pllb_clk); | ||
309 | clk_set_rate(pck1_clk, 12000000); | ||
310 | |||
311 | DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk)); | ||
312 | |||
313 | /* assign the GPIO pin to PCK1 */ | ||
314 | at91_set_B_periph(AT91_PIN_PA24, 0); | ||
315 | |||
316 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | ||
317 | printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n"); | ||
318 | #else | ||
319 | printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n"); | ||
320 | #endif | ||
321 | return ret; | ||
322 | |||
323 | fail_io_unmap: | ||
324 | iounmap(ssc->base); | ||
325 | fail_release_mem: | ||
326 | release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static void __exit eti_b1_exit(void) | ||
331 | { | ||
332 | struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; | ||
333 | |||
334 | clk_put(pck1_clk); | ||
335 | clk_put(pllb_clk); | ||
336 | |||
337 | platform_device_unregister(eti_b1_snd_device); | ||
338 | |||
339 | iounmap(ssc->base); | ||
340 | release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); | ||
341 | } | ||
342 | |||
343 | module_init(eti_b1_init); | ||
344 | module_exit(eti_b1_exit); | ||
345 | |||
346 | /* Module information */ | ||
347 | MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>"); | ||
348 | MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731"); | ||
349 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index f98331d099e7..dc006206f622 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
@@ -17,6 +17,22 @@ config SND_BF5XX_SOC_SSM2602 | |||
17 | help | 17 | help |
18 | Say Y if you want to add support for SoC audio on BF527-EZKIT. | 18 | Say Y if you want to add support for SoC audio on BF527-EZKIT. |
19 | 19 | ||
20 | config SND_BF5XX_SOC_AD73311 | ||
21 | tristate "SoC AD73311 Audio support for Blackfin" | ||
22 | depends on SND_BF5XX_I2S | ||
23 | select SND_BF5XX_SOC_I2S | ||
24 | select SND_SOC_AD73311 | ||
25 | help | ||
26 | Say Y if you want to add support for AD73311 codec on Blackfin. | ||
27 | |||
28 | config SND_BFIN_AD73311_SE | ||
29 | int "PF pin for AD73311L Chip Select" | ||
30 | depends on SND_BF5XX_SOC_AD73311 | ||
31 | default 4 | ||
32 | help | ||
33 | Enter the GPIO used to control AD73311's SE pin. Acceptable | ||
34 | values are 0 to 7 | ||
35 | |||
20 | config SND_BF5XX_AC97 | 36 | config SND_BF5XX_AC97 |
21 | tristate "SoC AC97 Audio for the ADI BF5xx chip" | 37 | tristate "SoC AC97 Audio for the ADI BF5xx chip" |
22 | depends on BLACKFIN && SND_SOC | 38 | depends on BLACKFIN && SND_SOC |
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index 9ea8bd9e0ba3..97bb37a6359c 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile | |||
@@ -14,7 +14,8 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o | |||
14 | # Blackfin Machine Support | 14 | # Blackfin Machine Support |
15 | snd-ad1980-objs := bf5xx-ad1980.o | 15 | snd-ad1980-objs := bf5xx-ad1980.o |
16 | snd-ssm2602-objs := bf5xx-ssm2602.o | 16 | snd-ssm2602-objs := bf5xx-ssm2602.o |
17 | 17 | snd-ad73311-objs := bf5xx-ad73311.o | |
18 | 18 | ||
19 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o | 19 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o |
20 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o | 20 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o |
21 | obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 51f4907c4831..25e50d2ea1ec 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, | |||
56 | sport->tx_pos += runtime->period_size; | 56 | sport->tx_pos += runtime->period_size; |
57 | if (sport->tx_pos >= runtime->buffer_size) | 57 | if (sport->tx_pos >= runtime->buffer_size) |
58 | sport->tx_pos %= runtime->buffer_size; | 58 | sport->tx_pos %= runtime->buffer_size; |
59 | sport->tx_delay_pos = sport->tx_pos; | ||
59 | } else { | 60 | } else { |
60 | bf5xx_ac97_to_pcm( | 61 | bf5xx_ac97_to_pcm( |
61 | (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, | 62 | (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, |
@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data) | |||
72 | struct snd_pcm_substream *pcm = data; | 73 | struct snd_pcm_substream *pcm = data; |
73 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 74 | #if defined(CONFIG_SND_MMAP_SUPPORT) |
74 | struct snd_pcm_runtime *runtime = pcm->runtime; | 75 | struct snd_pcm_runtime *runtime = pcm->runtime; |
76 | struct sport_device *sport = runtime->private_data; | ||
75 | bf5xx_mmap_copy(pcm, runtime->period_size); | 77 | bf5xx_mmap_copy(pcm, runtime->period_size); |
78 | if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
79 | if (sport->once == 0) { | ||
80 | snd_pcm_period_elapsed(pcm); | ||
81 | bf5xx_mmap_copy(pcm, runtime->period_size); | ||
82 | sport->once = 1; | ||
83 | } | ||
84 | } | ||
76 | #endif | 85 | #endif |
77 | snd_pcm_period_elapsed(pcm); | 86 | snd_pcm_period_elapsed(pcm); |
78 | } | 87 | } |
@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
114 | 123 | ||
115 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | 124 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) |
116 | { | 125 | { |
126 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
127 | |||
128 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
129 | memset(runtime->dma_area, 0, runtime->buffer_size); | ||
117 | snd_pcm_lib_free_pages(substream); | 130 | snd_pcm_lib_free_pages(substream); |
118 | return 0; | 131 | return 0; |
119 | } | 132 | } |
@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
127 | * SPORT working in TMD mode(include AC97). | 140 | * SPORT working in TMD mode(include AC97). |
128 | */ | 141 | */ |
129 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 142 | #if defined(CONFIG_SND_MMAP_SUPPORT) |
130 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max | ||
131 | * sizeof(struct ac97_frame) / 4; | ||
132 | /*clean up intermediate buffer*/ | ||
133 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 143 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
134 | memset(sport->tx_dma_buf, 0, size); | ||
135 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); | 144 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); |
136 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, | 145 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, |
137 | runtime->period_size * sizeof(struct ac97_frame)); | 146 | runtime->period_size * sizeof(struct ac97_frame)); |
138 | } else { | 147 | } else { |
139 | memset(sport->rx_dma_buf, 0, size); | ||
140 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); | 148 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); |
141 | sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, | 149 | sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, |
142 | runtime->period_size * sizeof(struct ac97_frame)); | 150 | runtime->period_size * sizeof(struct ac97_frame)); |
@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
164 | pr_debug("%s enter\n", __func__); | 172 | pr_debug("%s enter\n", __func__); |
165 | switch (cmd) { | 173 | switch (cmd) { |
166 | case SNDRV_PCM_TRIGGER_START: | 174 | case SNDRV_PCM_TRIGGER_START: |
167 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 175 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
176 | bf5xx_mmap_copy(substream, runtime->period_size); | ||
177 | snd_pcm_period_elapsed(substream); | ||
178 | sport->tx_delay_pos = 0; | ||
168 | sport_tx_start(sport); | 179 | sport_tx_start(sport); |
180 | } | ||
169 | else | 181 | else |
170 | sport_rx_start(sport); | 182 | sport_rx_start(sport); |
171 | break; | 183 | break; |
@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
198 | 210 | ||
199 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 211 | #if defined(CONFIG_SND_MMAP_SUPPORT) |
200 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 212 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
201 | curr = sport->tx_pos; | 213 | curr = sport->tx_delay_pos; |
202 | else | 214 | else |
203 | curr = sport->rx_pos; | 215 | curr = sport->rx_pos; |
204 | #else | 216 | #else |
@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) | |||
237 | return ret; | 249 | return ret; |
238 | } | 250 | } |
239 | 251 | ||
252 | static int bf5xx_pcm_close(struct snd_pcm_substream *substream) | ||
253 | { | ||
254 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
255 | struct sport_device *sport = runtime->private_data; | ||
256 | |||
257 | pr_debug("%s enter\n", __func__); | ||
258 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
259 | sport->once = 0; | ||
260 | memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); | ||
261 | } else | ||
262 | memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
240 | #ifdef CONFIG_SND_MMAP_SUPPORT | 267 | #ifdef CONFIG_SND_MMAP_SUPPORT |
241 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | 268 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, |
242 | struct vm_area_struct *vma) | 269 | struct vm_area_struct *vma) |
@@ -272,6 +299,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
272 | 299 | ||
273 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { | 300 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { |
274 | .open = bf5xx_pcm_open, | 301 | .open = bf5xx_pcm_open, |
302 | .close = bf5xx_pcm_close, | ||
275 | .ioctl = snd_pcm_lib_ioctl, | 303 | .ioctl = snd_pcm_lib_ioctl, |
276 | .hw_params = bf5xx_pcm_hw_params, | 304 | .hw_params = bf5xx_pcm_hw_params, |
277 | .hw_free = bf5xx_pcm_hw_free, | 305 | .hw_free = bf5xx_pcm_hw_free, |
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index c782e311fd56..5e5aafb6485f 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) | |||
129 | struct ac97_frame *nextwrite; | 129 | struct ac97_frame *nextwrite; |
130 | 130 | ||
131 | sport_incfrag(sport, &nextfrag, 1); | 131 | sport_incfrag(sport, &nextfrag, 1); |
132 | sport_incfrag(sport, &nextfrag, 1); | ||
133 | 132 | ||
134 | nextwrite = (struct ac97_frame *)(sport->tx_buf + \ | 133 | nextwrite = (struct ac97_frame *)(sport->tx_buf + \ |
135 | nextfrag * sport->tx_fragsize); | 134 | nextfrag * sport->tx_fragsize); |
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c new file mode 100644 index 000000000000..622c9b909532 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ad73311.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-ad73311.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Thur Sep 25 2008 | ||
6 | * Description: Board driver for ad73311 sound chip | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/gpio.h> | ||
34 | |||
35 | #include <sound/core.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/soc.h> | ||
38 | #include <sound/soc-dapm.h> | ||
39 | #include <sound/pcm_params.h> | ||
40 | |||
41 | #include <asm/blackfin.h> | ||
42 | #include <asm/cacheflush.h> | ||
43 | #include <asm/irq.h> | ||
44 | #include <asm/dma.h> | ||
45 | #include <asm/portmux.h> | ||
46 | |||
47 | #include "../codecs/ad73311.h" | ||
48 | #include "bf5xx-sport.h" | ||
49 | #include "bf5xx-i2s-pcm.h" | ||
50 | #include "bf5xx-i2s.h" | ||
51 | |||
52 | #if CONFIG_SND_BF5XX_SPORT_NUM == 0 | ||
53 | #define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1 | ||
54 | #define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1 | ||
55 | #define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2 | ||
56 | #define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16 | ||
57 | #define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT | ||
58 | #else | ||
59 | #define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1 | ||
60 | #define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1 | ||
61 | #define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2 | ||
62 | #define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16 | ||
63 | #define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT | ||
64 | #endif | ||
65 | |||
66 | #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE | ||
67 | |||
68 | static struct snd_soc_machine bf5xx_ad73311; | ||
69 | |||
70 | static int snd_ad73311_startup(void) | ||
71 | { | ||
72 | pr_debug("%s enter\n", __func__); | ||
73 | |||
74 | /* Pull up SE pin on AD73311L */ | ||
75 | gpio_set_value(GPIO_SE, 1); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int snd_ad73311_configure(void) | ||
80 | { | ||
81 | unsigned short ctrl_regs[6]; | ||
82 | unsigned short status = 0; | ||
83 | int count = 0; | ||
84 | |||
85 | /* DMCLK = MCLK = 16.384 MHz | ||
86 | * SCLK = DMCLK/8 = 2.048 MHz | ||
87 | * Sample Rate = DMCLK/2048 = 8 KHz | ||
88 | */ | ||
89 | ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \ | ||
90 | REGB_SCDIV(0) | REGB_DIRATE(0); | ||
91 | ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \ | ||
92 | REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ; | ||
93 | ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \ | ||
94 | REGD_IGS(2); | ||
95 | ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f); | ||
96 | ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ; | ||
97 | ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA; | ||
98 | |||
99 | local_irq_disable(); | ||
100 | snd_ad73311_startup(); | ||
101 | udelay(1); | ||
102 | |||
103 | bfin_write_SPORT_TCR1(TFSR); | ||
104 | bfin_write_SPORT_TCR2(0xF); | ||
105 | SSYNC(); | ||
106 | |||
107 | /* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to | ||
108 | * FIFO before enable SPORT to transfer the data | ||
109 | */ | ||
110 | for (count = 0; count < 6; count++) | ||
111 | bfin_write_SPORT_TX16(ctrl_regs[count]); | ||
112 | SSYNC(); | ||
113 | bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN); | ||
114 | SSYNC(); | ||
115 | |||
116 | /* When TUVF is set, the data is already send out */ | ||
117 | while (!(status & TUVF) && count++ < 10000) { | ||
118 | udelay(1); | ||
119 | status = bfin_read_SPORT_STAT(); | ||
120 | SSYNC(); | ||
121 | } | ||
122 | bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN); | ||
123 | SSYNC(); | ||
124 | local_irq_enable(); | ||
125 | |||
126 | if (count == 10000) { | ||
127 | printk(KERN_ERR "ad73311: failed to configure codec\n"); | ||
128 | return -1; | ||
129 | } | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int bf5xx_probe(struct platform_device *pdev) | ||
134 | { | ||
135 | int err; | ||
136 | if (gpio_request(GPIO_SE, "AD73311_SE")) { | ||
137 | printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE); | ||
138 | return -EBUSY; | ||
139 | } | ||
140 | |||
141 | gpio_direction_output(GPIO_SE, 0); | ||
142 | |||
143 | err = snd_ad73311_configure(); | ||
144 | if (err < 0) | ||
145 | return -EFAULT; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream) | ||
151 | { | ||
152 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
153 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
154 | |||
155 | pr_debug("%s enter\n", __func__); | ||
156 | cpu_dai->private_data = sport_handle; | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, | ||
161 | struct snd_pcm_hw_params *params) | ||
162 | { | ||
163 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
164 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
165 | int ret = 0; | ||
166 | |||
167 | pr_debug("%s rate %d format %x\n", __func__, params_rate(params), | ||
168 | params_format(params)); | ||
169 | |||
170 | /* set cpu DAI configuration */ | ||
171 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | | ||
172 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
173 | if (ret < 0) | ||
174 | return ret; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | |||
180 | static struct snd_soc_ops bf5xx_ad73311_ops = { | ||
181 | .startup = bf5xx_ad73311_startup, | ||
182 | .hw_params = bf5xx_ad73311_hw_params, | ||
183 | }; | ||
184 | |||
185 | static struct snd_soc_dai_link bf5xx_ad73311_dai = { | ||
186 | .name = "ad73311", | ||
187 | .stream_name = "AD73311", | ||
188 | .cpu_dai = &bf5xx_i2s_dai, | ||
189 | .codec_dai = &ad73311_dai, | ||
190 | .ops = &bf5xx_ad73311_ops, | ||
191 | }; | ||
192 | |||
193 | static struct snd_soc_machine bf5xx_ad73311 = { | ||
194 | .name = "bf5xx_ad73311", | ||
195 | .probe = bf5xx_probe, | ||
196 | .dai_link = &bf5xx_ad73311_dai, | ||
197 | .num_links = 1, | ||
198 | }; | ||
199 | |||
200 | static struct snd_soc_device bf5xx_ad73311_snd_devdata = { | ||
201 | .machine = &bf5xx_ad73311, | ||
202 | .platform = &bf5xx_i2s_soc_platform, | ||
203 | .codec_dev = &soc_codec_dev_ad73311, | ||
204 | }; | ||
205 | |||
206 | static struct platform_device *bf52x_ad73311_snd_device; | ||
207 | |||
208 | static int __init bf5xx_ad73311_init(void) | ||
209 | { | ||
210 | int ret; | ||
211 | |||
212 | pr_debug("%s enter\n", __func__); | ||
213 | bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1); | ||
214 | if (!bf52x_ad73311_snd_device) | ||
215 | return -ENOMEM; | ||
216 | |||
217 | platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata); | ||
218 | bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev; | ||
219 | ret = platform_device_add(bf52x_ad73311_snd_device); | ||
220 | |||
221 | if (ret) | ||
222 | platform_device_put(bf52x_ad73311_snd_device); | ||
223 | |||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | static void __exit bf5xx_ad73311_exit(void) | ||
228 | { | ||
229 | pr_debug("%s enter\n", __func__); | ||
230 | platform_device_unregister(bf52x_ad73311_snd_device); | ||
231 | } | ||
232 | |||
233 | module_init(bf5xx_ad73311_init); | ||
234 | module_exit(bf5xx_ad73311_exit); | ||
235 | |||
236 | /* Module information */ | ||
237 | MODULE_AUTHOR("Cliff Cai"); | ||
238 | MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin"); | ||
239 | MODULE_LICENSE("GPL"); | ||
240 | |||
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 43a4092eeb89..827587f08180 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -70,6 +70,13 @@ static struct sport_param sport_params[2] = { | |||
70 | } | 70 | } |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static u16 sport_req[][7] = { | ||
74 | { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
75 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}, | ||
76 | { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, | ||
77 | P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}, | ||
78 | }; | ||
79 | |||
73 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 80 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
74 | unsigned int fmt) | 81 | unsigned int fmt) |
75 | { | 82 | { |
@@ -78,6 +85,14 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
78 | /* interface format:support I2S,slave mode */ | 85 | /* interface format:support I2S,slave mode */ |
79 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 86 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
80 | case SND_SOC_DAIFMT_I2S: | 87 | case SND_SOC_DAIFMT_I2S: |
88 | bf5xx_i2s.tcr1 |= TFSR | TCKFE; | ||
89 | bf5xx_i2s.rcr1 |= RFSR | RCKFE; | ||
90 | bf5xx_i2s.tcr2 |= TSFSE; | ||
91 | bf5xx_i2s.rcr2 |= RSFSE; | ||
92 | break; | ||
93 | case SND_SOC_DAIFMT_DSP_A: | ||
94 | bf5xx_i2s.tcr1 |= TFSR; | ||
95 | bf5xx_i2s.rcr1 |= RFSR; | ||
81 | break; | 96 | break; |
82 | case SND_SOC_DAIFMT_LEFT_J: | 97 | case SND_SOC_DAIFMT_LEFT_J: |
83 | ret = -EINVAL; | 98 | ret = -EINVAL; |
@@ -127,14 +142,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
127 | case SNDRV_PCM_FORMAT_S16_LE: | 142 | case SNDRV_PCM_FORMAT_S16_LE: |
128 | bf5xx_i2s.tcr2 |= 15; | 143 | bf5xx_i2s.tcr2 |= 15; |
129 | bf5xx_i2s.rcr2 |= 15; | 144 | bf5xx_i2s.rcr2 |= 15; |
145 | sport_handle->wdsize = 2; | ||
130 | break; | 146 | break; |
131 | case SNDRV_PCM_FORMAT_S24_LE: | 147 | case SNDRV_PCM_FORMAT_S24_LE: |
132 | bf5xx_i2s.tcr2 |= 23; | 148 | bf5xx_i2s.tcr2 |= 23; |
133 | bf5xx_i2s.rcr2 |= 23; | 149 | bf5xx_i2s.rcr2 |= 23; |
150 | sport_handle->wdsize = 3; | ||
134 | break; | 151 | break; |
135 | case SNDRV_PCM_FORMAT_S32_LE: | 152 | case SNDRV_PCM_FORMAT_S32_LE: |
136 | bf5xx_i2s.tcr2 |= 31; | 153 | bf5xx_i2s.tcr2 |= 31; |
137 | bf5xx_i2s.rcr2 |= 31; | 154 | bf5xx_i2s.rcr2 |= 31; |
155 | sport_handle->wdsize = 4; | ||
138 | break; | 156 | break; |
139 | } | 157 | } |
140 | 158 | ||
@@ -145,17 +163,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
145 | * need to configure both of them at the time when the first | 163 | * need to configure both of them at the time when the first |
146 | * stream is opened. | 164 | * stream is opened. |
147 | * | 165 | * |
148 | * CPU DAI format:I2S, slave mode. | 166 | * CPU DAI:slave mode. |
149 | */ | 167 | */ |
150 | ret = sport_config_rx(sport_handle, RFSR | RCKFE, | 168 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, |
151 | RSFSE|bf5xx_i2s.rcr2, 0, 0); | 169 | bf5xx_i2s.rcr2, 0, 0); |
152 | if (ret) { | 170 | if (ret) { |
153 | pr_err("SPORT is busy!\n"); | 171 | pr_err("SPORT is busy!\n"); |
154 | return -EBUSY; | 172 | return -EBUSY; |
155 | } | 173 | } |
156 | 174 | ||
157 | ret = sport_config_tx(sport_handle, TFSR | TCKFE, | 175 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, |
158 | TSFSE|bf5xx_i2s.tcr2, 0, 0); | 176 | bf5xx_i2s.tcr2, 0, 0); |
159 | if (ret) { | 177 | if (ret) { |
160 | pr_err("SPORT is busy!\n"); | 178 | pr_err("SPORT is busy!\n"); |
161 | return -EBUSY; | 179 | return -EBUSY; |
@@ -174,13 +192,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) | |||
174 | static int bf5xx_i2s_probe(struct platform_device *pdev, | 192 | static int bf5xx_i2s_probe(struct platform_device *pdev, |
175 | struct snd_soc_dai *dai) | 193 | struct snd_soc_dai *dai) |
176 | { | 194 | { |
177 | u16 sport_req[][7] = { | ||
178 | { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
179 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}, | ||
180 | { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, | ||
181 | P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}, | ||
182 | }; | ||
183 | |||
184 | pr_debug("%s enter\n", __func__); | 195 | pr_debug("%s enter\n", __func__); |
185 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | 196 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { |
186 | pr_err("Requesting Peripherals failed\n"); | 197 | pr_err("Requesting Peripherals failed\n"); |
@@ -198,6 +209,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, | |||
198 | return 0; | 209 | return 0; |
199 | } | 210 | } |
200 | 211 | ||
212 | static void bf5xx_i2s_remove(struct platform_device *pdev, | ||
213 | struct snd_soc_dai *dai) | ||
214 | { | ||
215 | pr_debug("%s enter\n", __func__); | ||
216 | peripheral_free_list(&sport_req[sport_num][0]); | ||
217 | } | ||
218 | |||
201 | #ifdef CONFIG_PM | 219 | #ifdef CONFIG_PM |
202 | static int bf5xx_i2s_suspend(struct platform_device *dev, | 220 | static int bf5xx_i2s_suspend(struct platform_device *dev, |
203 | struct snd_soc_dai *dai) | 221 | struct snd_soc_dai *dai) |
@@ -263,15 +281,16 @@ struct snd_soc_dai bf5xx_i2s_dai = { | |||
263 | .id = 0, | 281 | .id = 0, |
264 | .type = SND_SOC_DAI_I2S, | 282 | .type = SND_SOC_DAI_I2S, |
265 | .probe = bf5xx_i2s_probe, | 283 | .probe = bf5xx_i2s_probe, |
284 | .remove = bf5xx_i2s_remove, | ||
266 | .suspend = bf5xx_i2s_suspend, | 285 | .suspend = bf5xx_i2s_suspend, |
267 | .resume = bf5xx_i2s_resume, | 286 | .resume = bf5xx_i2s_resume, |
268 | .playback = { | 287 | .playback = { |
269 | .channels_min = 2, | 288 | .channels_min = 1, |
270 | .channels_max = 2, | 289 | .channels_max = 2, |
271 | .rates = BF5XX_I2S_RATES, | 290 | .rates = BF5XX_I2S_RATES, |
272 | .formats = BF5XX_I2S_FORMATS,}, | 291 | .formats = BF5XX_I2S_FORMATS,}, |
273 | .capture = { | 292 | .capture = { |
274 | .channels_min = 2, | 293 | .channels_min = 1, |
275 | .channels_max = 2, | 294 | .channels_max = 2, |
276 | .rates = BF5XX_I2S_RATES, | 295 | .rates = BF5XX_I2S_RATES, |
277 | .formats = BF5XX_I2S_FORMATS,}, | 296 | .formats = BF5XX_I2S_FORMATS,}, |
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index 4c163454bbf8..fcadcc081f7f 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h | |||
@@ -123,6 +123,8 @@ struct sport_device { | |||
123 | int rx_pos; | 123 | int rx_pos; |
124 | unsigned int tx_buffer_size; | 124 | unsigned int tx_buffer_size; |
125 | unsigned int rx_buffer_size; | 125 | unsigned int rx_buffer_size; |
126 | int tx_delay_pos; | ||
127 | int once; | ||
126 | #endif | 128 | #endif |
127 | void *private_data; | 129 | void *private_data; |
128 | }; | 130 | }; |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e0b9869df0f1..4975d8573e4f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -3,9 +3,11 @@ config SND_SOC_ALL_CODECS | |||
3 | depends on I2C | 3 | depends on I2C |
4 | select SPI | 4 | select SPI |
5 | select SPI_MASTER | 5 | select SPI_MASTER |
6 | select SND_SOC_AD73311 | ||
6 | select SND_SOC_AK4535 | 7 | select SND_SOC_AK4535 |
7 | select SND_SOC_CS4270 | 8 | select SND_SOC_CS4270 |
8 | select SND_SOC_SSM2602 | 9 | select SND_SOC_SSM2602 |
10 | select SND_SOC_TLV320AIC23 | ||
9 | select SND_SOC_TLV320AIC26 | 11 | select SND_SOC_TLV320AIC26 |
10 | select SND_SOC_TLV320AIC3X | 12 | select SND_SOC_TLV320AIC3X |
11 | select SND_SOC_UDA1380 | 13 | select SND_SOC_UDA1380 |
@@ -34,6 +36,9 @@ config SND_SOC_AC97_CODEC | |||
34 | config SND_SOC_AD1980 | 36 | config SND_SOC_AD1980 |
35 | tristate | 37 | tristate |
36 | 38 | ||
39 | config SND_SOC_AD73311 | ||
40 | tristate | ||
41 | |||
37 | config SND_SOC_AK4535 | 42 | config SND_SOC_AK4535 |
38 | tristate | 43 | tristate |
39 | 44 | ||
@@ -58,9 +63,13 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
58 | config SND_SOC_SSM2602 | 63 | config SND_SOC_SSM2602 |
59 | tristate | 64 | tristate |
60 | 65 | ||
66 | config SND_SOC_TLV320AIC23 | ||
67 | tristate | ||
68 | depends on I2C | ||
69 | |||
61 | config SND_SOC_TLV320AIC26 | 70 | config SND_SOC_TLV320AIC26 |
62 | tristate "TI TLV320AIC26 Codec support" | 71 | tristate "TI TLV320AIC26 Codec support" |
63 | depends on SND_SOC && SPI | 72 | depends on SPI |
64 | 73 | ||
65 | config SND_SOC_TLV320AIC3X | 74 | config SND_SOC_TLV320AIC3X |
66 | tristate | 75 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f977978a3409..90f0a585fc70 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,8 +1,10 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ad1980-objs := ad1980.o | 2 | snd-soc-ad1980-objs := ad1980.o |
3 | snd-soc-ad73311-objs := ad73311.o | ||
3 | snd-soc-ak4535-objs := ak4535.o | 4 | snd-soc-ak4535-objs := ak4535.o |
4 | snd-soc-cs4270-objs := cs4270.o | 5 | snd-soc-cs4270-objs := cs4270.o |
5 | snd-soc-ssm2602-objs := ssm2602.o | 6 | snd-soc-ssm2602-objs := ssm2602.o |
7 | snd-soc-tlv320aic23-objs := tlv320aic23.o | ||
6 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 8 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
7 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 9 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
8 | snd-soc-uda1380-objs := uda1380.o | 10 | snd-soc-uda1380-objs := uda1380.o |
@@ -20,9 +22,11 @@ snd-soc-wm9713-objs := wm9713.o | |||
20 | 22 | ||
21 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 23 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
22 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 24 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
25 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | ||
23 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 26 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 27 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
25 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 28 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
29 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | ||
26 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 30 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
27 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 31 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
28 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | 32 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 61fd96ca7bc7..bd1ebdc6c86c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * ac97.c -- ALSA Soc AC97 codec support | 2 | * ac97.c -- ALSA Soc AC97 codec support |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 4e09c1f2c063..1397b8e06c0b 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -13,7 +13,6 @@ | |||
13 | 13 | ||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
18 | #include <linux/device.h> | 17 | #include <linux/device.h> |
19 | #include <sound/core.h> | 18 | #include <sound/core.h> |
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c new file mode 100644 index 000000000000..37af8607b00a --- /dev/null +++ b/sound/soc/codecs/ad73311.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * ad73311.c -- ALSA Soc AD73311 codec support | ||
3 | * | ||
4 | * Copyright: Analog Device Inc. | ||
5 | * Author: Cliff Cai <cliff.cai@analog.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * Revision history | ||
13 | * 25th Sep 2008 Initial version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/ac97_codec.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "ad73311.h" | ||
28 | |||
29 | struct snd_soc_dai ad73311_dai = { | ||
30 | .name = "AD73311", | ||
31 | .playback = { | ||
32 | .stream_name = "Playback", | ||
33 | .channels_min = 1, | ||
34 | .channels_max = 1, | ||
35 | .rates = SNDRV_PCM_RATE_8000, | ||
36 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
37 | .capture = { | ||
38 | .stream_name = "Capture", | ||
39 | .channels_min = 1, | ||
40 | .channels_max = 1, | ||
41 | .rates = SNDRV_PCM_RATE_8000, | ||
42 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
43 | }; | ||
44 | EXPORT_SYMBOL_GPL(ad73311_dai); | ||
45 | |||
46 | static int ad73311_soc_probe(struct platform_device *pdev) | ||
47 | { | ||
48 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
49 | struct snd_soc_codec *codec; | ||
50 | int ret = 0; | ||
51 | |||
52 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
53 | if (codec == NULL) | ||
54 | return -ENOMEM; | ||
55 | mutex_init(&codec->mutex); | ||
56 | codec->name = "AD73311"; | ||
57 | codec->owner = THIS_MODULE; | ||
58 | codec->dai = &ad73311_dai; | ||
59 | codec->num_dai = 1; | ||
60 | socdev->codec = codec; | ||
61 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
62 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
63 | |||
64 | /* register pcms */ | ||
65 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
66 | if (ret < 0) { | ||
67 | printk(KERN_ERR "ad73311: failed to create pcms\n"); | ||
68 | goto pcm_err; | ||
69 | } | ||
70 | |||
71 | ret = snd_soc_register_card(socdev); | ||
72 | if (ret < 0) { | ||
73 | printk(KERN_ERR "ad73311: failed to register card\n"); | ||
74 | goto register_err; | ||
75 | } | ||
76 | |||
77 | return ret; | ||
78 | |||
79 | register_err: | ||
80 | snd_soc_free_pcms(socdev); | ||
81 | pcm_err: | ||
82 | kfree(socdev->codec); | ||
83 | socdev->codec = NULL; | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static int ad73311_soc_remove(struct platform_device *pdev) | ||
88 | { | ||
89 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
90 | struct snd_soc_codec *codec = socdev->codec; | ||
91 | |||
92 | if (codec == NULL) | ||
93 | return 0; | ||
94 | snd_soc_free_pcms(socdev); | ||
95 | kfree(codec); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | struct snd_soc_codec_device soc_codec_dev_ad73311 = { | ||
100 | .probe = ad73311_soc_probe, | ||
101 | .remove = ad73311_soc_remove, | ||
102 | }; | ||
103 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); | ||
104 | |||
105 | MODULE_DESCRIPTION("ASoC ad73311 driver"); | ||
106 | MODULE_AUTHOR("Cliff Cai "); | ||
107 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h new file mode 100644 index 000000000000..507ce0c30edf --- /dev/null +++ b/sound/soc/codecs/ad73311.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * File: sound/soc/codec/ad73311.h | ||
3 | * Based on: | ||
4 | * Author: Cliff Cai <cliff.cai@analog.com> | ||
5 | * | ||
6 | * Created: Thur Sep 25, 2008 | ||
7 | * Description: definitions for AD73311 registers | ||
8 | * | ||
9 | * | ||
10 | * Modified: | ||
11 | * Copyright 2006 Analog Devices Inc. | ||
12 | * | ||
13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, see the file COPYING, or write | ||
27 | * to the Free Software Foundation, Inc., | ||
28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
29 | */ | ||
30 | |||
31 | #ifndef __AD73311_H__ | ||
32 | #define __AD73311_H__ | ||
33 | |||
34 | #define AD_CONTROL 0x8000 | ||
35 | #define AD_DATA 0x0000 | ||
36 | #define AD_READ 0x4000 | ||
37 | #define AD_WRITE 0x0000 | ||
38 | |||
39 | /* Control register A */ | ||
40 | #define CTRL_REG_A (0 << 8) | ||
41 | |||
42 | #define REGA_MODE_PRO 0x00 | ||
43 | #define REGA_MODE_DATA 0x01 | ||
44 | #define REGA_MODE_MIXED 0x03 | ||
45 | #define REGA_DLB 0x04 | ||
46 | #define REGA_SLB 0x08 | ||
47 | #define REGA_DEVC(x) ((x & 0x7) << 4) | ||
48 | #define REGA_RESET 0x80 | ||
49 | |||
50 | /* Control register B */ | ||
51 | #define CTRL_REG_B (1 << 8) | ||
52 | |||
53 | #define REGB_DIRATE(x) (x & 0x3) | ||
54 | #define REGB_SCDIV(x) ((x & 0x3) << 2) | ||
55 | #define REGB_MCDIV(x) ((x & 0x7) << 4) | ||
56 | #define REGB_CEE (1 << 7) | ||
57 | |||
58 | /* Control register C */ | ||
59 | #define CTRL_REG_C (2 << 8) | ||
60 | |||
61 | #define REGC_PUDEV (1 << 0) | ||
62 | #define REGC_PUADC (1 << 3) | ||
63 | #define REGC_PUDAC (1 << 4) | ||
64 | #define REGC_PUREF (1 << 5) | ||
65 | #define REGC_REFUSE (1 << 6) | ||
66 | |||
67 | /* Control register D */ | ||
68 | #define CTRL_REG_D (3 << 8) | ||
69 | |||
70 | #define REGD_IGS(x) (x & 0x7) | ||
71 | #define REGD_RMOD (1 << 3) | ||
72 | #define REGD_OGS(x) ((x & 0x7) << 4) | ||
73 | #define REGD_MUTE (x << 7) | ||
74 | |||
75 | /* Control register E */ | ||
76 | #define CTRL_REG_E (4 << 8) | ||
77 | |||
78 | #define REGE_DA(x) (x & 0x1f) | ||
79 | #define REGE_IBYP (1 << 5) | ||
80 | |||
81 | /* Control register F */ | ||
82 | #define CTRL_REG_F (5 << 8) | ||
83 | |||
84 | #define REGF_SEEN (1 << 5) | ||
85 | #define REGF_INV (1 << 6) | ||
86 | #define REGF_ALB (1 << 7) | ||
87 | |||
88 | extern struct snd_soc_dai ad73311_dai; | ||
89 | extern struct snd_soc_codec_device soc_codec_dev_ad73311; | ||
90 | #endif | ||
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 088cf9927720..2a89b5888e11 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -28,7 +28,6 @@ | |||
28 | 28 | ||
29 | #include "ak4535.h" | 29 | #include "ak4535.h" |
30 | 30 | ||
31 | #define AUDIO_NAME "ak4535" | ||
32 | #define AK4535_VERSION "0.3" | 31 | #define AK4535_VERSION "0.3" |
33 | 32 | ||
34 | struct snd_soc_codec_device soc_codec_dev_ak4535; | 33 | struct snd_soc_codec_device soc_codec_dev_ak4535; |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 940ce1c3522e..44ef0dacd564 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -42,7 +42,6 @@ | |||
42 | 42 | ||
43 | #include "ssm2602.h" | 43 | #include "ssm2602.h" |
44 | 44 | ||
45 | #define AUDIO_NAME "ssm2602" | ||
46 | #define SSM2602_VERSION "0.1" | 45 | #define SSM2602_VERSION "0.1" |
47 | 46 | ||
48 | struct snd_soc_codec_device soc_codec_dev_ssm2602; | 47 | struct snd_soc_codec_device soc_codec_dev_ssm2602; |
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c new file mode 100644 index 000000000000..bac7815e00fb --- /dev/null +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -0,0 +1,714 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC23 codec driver | ||
3 | * | ||
4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., | ||
6 | * | ||
7 | * Based on sound/soc/codecs/wm8731.c by Richard Purdie | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Notes: | ||
14 | * The AIC23 is a driver for a low power stereo audio | ||
15 | * codec tlv320aic23 | ||
16 | * | ||
17 | * The machine layer should disable unsupported inputs/outputs by | ||
18 | * snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | #include <sound/tlv.h> | ||
34 | #include <sound/initval.h> | ||
35 | |||
36 | #include "tlv320aic23.h" | ||
37 | |||
38 | #define AIC23_VERSION "0.1" | ||
39 | |||
40 | struct tlv320aic23_srate_reg_info { | ||
41 | u32 sample_rate; | ||
42 | u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ | ||
43 | u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ | ||
44 | }; | ||
45 | |||
46 | /* | ||
47 | * AIC23 register cache | ||
48 | */ | ||
49 | static const u16 tlv320aic23_reg[] = { | ||
50 | 0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */ | ||
51 | 0x001A, 0x0004, 0x0007, 0x0001, /* 4 */ | ||
52 | 0x0020, 0x0000, 0x0000, 0x0000, /* 8 */ | ||
53 | 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */ | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * read tlv320aic23 register cache | ||
58 | */ | ||
59 | static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec | ||
60 | *codec, unsigned int reg) | ||
61 | { | ||
62 | u16 *cache = codec->reg_cache; | ||
63 | if (reg >= ARRAY_SIZE(tlv320aic23_reg)) | ||
64 | return -1; | ||
65 | return cache[reg]; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * write tlv320aic23 register cache | ||
70 | */ | ||
71 | static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec, | ||
72 | u8 reg, u16 value) | ||
73 | { | ||
74 | u16 *cache = codec->reg_cache; | ||
75 | if (reg >= ARRAY_SIZE(tlv320aic23_reg)) | ||
76 | return; | ||
77 | cache[reg] = value; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * write to the tlv320aic23 register space | ||
82 | */ | ||
83 | static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, | ||
84 | unsigned int value) | ||
85 | { | ||
86 | |||
87 | u8 data; | ||
88 | |||
89 | /* TLV320AIC23 has 7 bit address and 9 bits of data | ||
90 | * so we need to switch one data bit into reg and rest | ||
91 | * of data into val | ||
92 | */ | ||
93 | |||
94 | if ((reg < 0 || reg > 9) && (reg != 15)) { | ||
95 | printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg); | ||
96 | return -1; | ||
97 | } | ||
98 | |||
99 | data = (reg << 1) | (value >> 8 & 0x01); | ||
100 | |||
101 | tlv320aic23_write_reg_cache(codec, reg, value); | ||
102 | |||
103 | if (codec->hw_write(codec->control_data, data, | ||
104 | (value & 0xff)) == 0) | ||
105 | return 0; | ||
106 | |||
107 | printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__, | ||
108 | value, reg); | ||
109 | |||
110 | return -EIO; | ||
111 | } | ||
112 | |||
113 | static const char *rec_src_text[] = { "Line", "Mic" }; | ||
114 | static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
115 | |||
116 | static const struct soc_enum rec_src_enum = | ||
117 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | ||
118 | |||
119 | static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = | ||
120 | SOC_DAPM_ENUM("Input Select", rec_src_enum); | ||
121 | |||
122 | static const struct soc_enum tlv320aic23_rec_src = | ||
123 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | ||
124 | static const struct soc_enum tlv320aic23_deemph = | ||
125 | SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text); | ||
126 | |||
127 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); | ||
128 | static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); | ||
129 | static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0); | ||
130 | |||
131 | static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol, | ||
132 | struct snd_ctl_elem_value *ucontrol) | ||
133 | { | ||
134 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
135 | u16 val, reg; | ||
136 | |||
137 | val = (ucontrol->value.integer.value[0] & 0x07); | ||
138 | |||
139 | /* linear conversion to userspace | ||
140 | * 000 = -6db | ||
141 | * 001 = -9db | ||
142 | * 010 = -12db | ||
143 | * 011 = -18db (Min) | ||
144 | * 100 = 0db (Max) | ||
145 | */ | ||
146 | val = (val >= 4) ? 4 : (3 - val); | ||
147 | |||
148 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0); | ||
149 | tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6)); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol, | ||
155 | struct snd_ctl_elem_value *ucontrol) | ||
156 | { | ||
157 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
158 | u16 val; | ||
159 | |||
160 | val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0); | ||
161 | val = val >> 6; | ||
162 | val = (val >= 4) ? 4 : (3 - val); | ||
163 | ucontrol->value.integer.value[0] = val; | ||
164 | return 0; | ||
165 | |||
166 | } | ||
167 | |||
168 | #define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ | ||
169 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
170 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
171 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
172 | .tlv.p = (tlv_array), \ | ||
173 | .info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\ | ||
174 | .put = snd_soc_tlv320aic23_put_volsw, \ | ||
175 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
176 | |||
177 | static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = { | ||
178 | SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL, | ||
179 | TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv), | ||
180 | SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1), | ||
181 | SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL, | ||
182 | TLV320AIC23_RINVOL, 7, 1, 0), | ||
183 | SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL, | ||
184 | TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv), | ||
185 | SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1), | ||
186 | SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0), | ||
187 | SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG, | ||
188 | 6, 4, 0, sidetone_vol_tlv), | ||
189 | SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), | ||
190 | }; | ||
191 | |||
192 | /* add non dapm controls */ | ||
193 | static int tlv320aic23_add_controls(struct snd_soc_codec *codec) | ||
194 | { | ||
195 | |||
196 | int err, i; | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) { | ||
199 | err = snd_ctl_add(codec->card, | ||
200 | snd_soc_cnew(&tlv320aic23_snd_controls[i], | ||
201 | codec, NULL)); | ||
202 | if (err < 0) | ||
203 | return err; | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | |||
208 | } | ||
209 | |||
210 | /* PGA Mixer controls for Line and Mic switch */ | ||
211 | static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = { | ||
212 | SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0), | ||
213 | SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0), | ||
214 | SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0), | ||
215 | }; | ||
216 | |||
217 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
218 | SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1), | ||
219 | SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1), | ||
220 | SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0, | ||
221 | &tlv320aic23_rec_src_mux_controls), | ||
222 | SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1, | ||
223 | &tlv320aic23_output_mixer_controls[0], | ||
224 | ARRAY_SIZE(tlv320aic23_output_mixer_controls)), | ||
225 | SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0), | ||
226 | SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0), | ||
227 | |||
228 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
229 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
230 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
231 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
232 | |||
233 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
234 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
235 | |||
236 | SND_SOC_DAPM_INPUT("MICIN"), | ||
237 | }; | ||
238 | |||
239 | static const struct snd_soc_dapm_route intercon[] = { | ||
240 | /* Output Mixer */ | ||
241 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
242 | {"Output Mixer", "Playback Switch", "DAC"}, | ||
243 | {"Output Mixer", "Mic Sidetone Switch", "Mic Input"}, | ||
244 | |||
245 | /* Outputs */ | ||
246 | {"RHPOUT", NULL, "Output Mixer"}, | ||
247 | {"LHPOUT", NULL, "Output Mixer"}, | ||
248 | {"LOUT", NULL, "Output Mixer"}, | ||
249 | {"ROUT", NULL, "Output Mixer"}, | ||
250 | |||
251 | /* Inputs */ | ||
252 | {"Line Input", "NULL", "LLINEIN"}, | ||
253 | {"Line Input", "NULL", "RLINEIN"}, | ||
254 | |||
255 | {"Mic Input", "NULL", "MICIN"}, | ||
256 | |||
257 | /* input mux */ | ||
258 | {"Capture Source", "Line", "Line Input"}, | ||
259 | {"Capture Source", "Mic", "Mic Input"}, | ||
260 | {"ADC", NULL, "Capture Source"}, | ||
261 | |||
262 | }; | ||
263 | |||
264 | /* tlv320aic23 related */ | ||
265 | static const struct tlv320aic23_srate_reg_info srate_reg_info[] = { | ||
266 | {4000, 0x06, 1}, /* 4000 */ | ||
267 | {8000, 0x06, 0}, /* 8000 */ | ||
268 | {16000, 0x0C, 1}, /* 16000 */ | ||
269 | {22050, 0x11, 1}, /* 22050 */ | ||
270 | {24000, 0x00, 1}, /* 24000 */ | ||
271 | {32000, 0x0C, 0}, /* 32000 */ | ||
272 | {44100, 0x11, 0}, /* 44100 */ | ||
273 | {48000, 0x00, 0}, /* 48000 */ | ||
274 | {88200, 0x1F, 0}, /* 88200 */ | ||
275 | {96000, 0x0E, 0}, /* 96000 */ | ||
276 | }; | ||
277 | |||
278 | static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) | ||
279 | { | ||
280 | snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, | ||
281 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | ||
282 | |||
283 | /* set up audio path interconnects */ | ||
284 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
285 | |||
286 | snd_soc_dapm_new_widgets(codec); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, | ||
291 | struct snd_pcm_hw_params *params) | ||
292 | { | ||
293 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
294 | struct snd_soc_device *socdev = rtd->socdev; | ||
295 | struct snd_soc_codec *codec = socdev->codec; | ||
296 | u16 iface_reg, data; | ||
297 | u8 count = 0; | ||
298 | |||
299 | iface_reg = | ||
300 | tlv320aic23_read_reg_cache(codec, | ||
301 | TLV320AIC23_DIGT_FMT) & ~(0x03 << 2); | ||
302 | |||
303 | /* Search for the right sample rate */ | ||
304 | /* Verify what happens if the rate is not supported | ||
305 | * now it goes to 96Khz */ | ||
306 | while ((srate_reg_info[count].sample_rate != params_rate(params)) && | ||
307 | (count < ARRAY_SIZE(srate_reg_info))) { | ||
308 | count++; | ||
309 | } | ||
310 | |||
311 | data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) | | ||
312 | (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) | | ||
313 | TLV320AIC23_USB_CLK_ON; | ||
314 | |||
315 | tlv320aic23_write(codec, TLV320AIC23_SRATE, data); | ||
316 | |||
317 | switch (params_format(params)) { | ||
318 | case SNDRV_PCM_FORMAT_S16_LE: | ||
319 | break; | ||
320 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
321 | iface_reg |= (0x01 << 2); | ||
322 | break; | ||
323 | case SNDRV_PCM_FORMAT_S24_LE: | ||
324 | iface_reg |= (0x02 << 2); | ||
325 | break; | ||
326 | case SNDRV_PCM_FORMAT_S32_LE: | ||
327 | iface_reg |= (0x03 << 2); | ||
328 | break; | ||
329 | } | ||
330 | tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg); | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) | ||
336 | { | ||
337 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
338 | struct snd_soc_device *socdev = rtd->socdev; | ||
339 | struct snd_soc_codec *codec = socdev->codec; | ||
340 | |||
341 | /* set active */ | ||
342 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) | ||
348 | { | ||
349 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
350 | struct snd_soc_device *socdev = rtd->socdev; | ||
351 | struct snd_soc_codec *codec = socdev->codec; | ||
352 | |||
353 | /* deactivate */ | ||
354 | if (!codec->active) { | ||
355 | udelay(50); | ||
356 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute) | ||
361 | { | ||
362 | struct snd_soc_codec *codec = dai->codec; | ||
363 | u16 reg; | ||
364 | |||
365 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT); | ||
366 | if (mute) | ||
367 | reg |= TLV320AIC23_DACM_MUTE; | ||
368 | |||
369 | else | ||
370 | reg &= ~TLV320AIC23_DACM_MUTE; | ||
371 | |||
372 | tlv320aic23_write(codec, TLV320AIC23_DIGT, reg); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
378 | unsigned int fmt) | ||
379 | { | ||
380 | struct snd_soc_codec *codec = codec_dai->codec; | ||
381 | u16 iface_reg; | ||
382 | |||
383 | iface_reg = | ||
384 | tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03); | ||
385 | |||
386 | /* set master/slave audio interface */ | ||
387 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
388 | case SND_SOC_DAIFMT_CBM_CFM: | ||
389 | iface_reg |= TLV320AIC23_MS_MASTER; | ||
390 | break; | ||
391 | case SND_SOC_DAIFMT_CBS_CFS: | ||
392 | break; | ||
393 | default: | ||
394 | return -EINVAL; | ||
395 | |||
396 | } | ||
397 | |||
398 | /* interface format */ | ||
399 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
400 | case SND_SOC_DAIFMT_I2S: | ||
401 | iface_reg |= TLV320AIC23_FOR_I2S; | ||
402 | break; | ||
403 | case SND_SOC_DAIFMT_DSP_A: | ||
404 | iface_reg |= TLV320AIC23_FOR_DSP; | ||
405 | break; | ||
406 | case SND_SOC_DAIFMT_RIGHT_J: | ||
407 | break; | ||
408 | case SND_SOC_DAIFMT_LEFT_J: | ||
409 | iface_reg |= TLV320AIC23_FOR_LJUST; | ||
410 | break; | ||
411 | default: | ||
412 | return -EINVAL; | ||
413 | |||
414 | } | ||
415 | |||
416 | tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
422 | int clk_id, unsigned int freq, int dir) | ||
423 | { | ||
424 | struct snd_soc_codec *codec = codec_dai->codec; | ||
425 | |||
426 | switch (freq) { | ||
427 | case 12000000: | ||
428 | return 0; | ||
429 | } | ||
430 | return -EINVAL; | ||
431 | } | ||
432 | |||
433 | static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | ||
434 | enum snd_soc_bias_level level) | ||
435 | { | ||
436 | u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f; | ||
437 | |||
438 | switch (level) { | ||
439 | case SND_SOC_BIAS_ON: | ||
440 | /* vref/mid, osc on, dac unmute */ | ||
441 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg); | ||
442 | break; | ||
443 | case SND_SOC_BIAS_PREPARE: | ||
444 | break; | ||
445 | case SND_SOC_BIAS_STANDBY: | ||
446 | /* everything off except vref/vmid, */ | ||
447 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040); | ||
448 | break; | ||
449 | case SND_SOC_BIAS_OFF: | ||
450 | /* everything off, dac mute, inactive */ | ||
451 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
452 | tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff); | ||
453 | break; | ||
454 | } | ||
455 | codec->bias_level = level; | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | #define AIC23_RATES SNDRV_PCM_RATE_8000_96000 | ||
460 | #define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
461 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
462 | |||
463 | struct snd_soc_dai tlv320aic23_dai = { | ||
464 | .name = "tlv320aic23", | ||
465 | .playback = { | ||
466 | .stream_name = "Playback", | ||
467 | .channels_min = 2, | ||
468 | .channels_max = 2, | ||
469 | .rates = AIC23_RATES, | ||
470 | .formats = AIC23_FORMATS,}, | ||
471 | .capture = { | ||
472 | .stream_name = "Capture", | ||
473 | .channels_min = 2, | ||
474 | .channels_max = 2, | ||
475 | .rates = AIC23_RATES, | ||
476 | .formats = AIC23_FORMATS,}, | ||
477 | .ops = { | ||
478 | .prepare = tlv320aic23_pcm_prepare, | ||
479 | .hw_params = tlv320aic23_hw_params, | ||
480 | .shutdown = tlv320aic23_shutdown, | ||
481 | }, | ||
482 | .dai_ops = { | ||
483 | .digital_mute = tlv320aic23_mute, | ||
484 | .set_fmt = tlv320aic23_set_dai_fmt, | ||
485 | .set_sysclk = tlv320aic23_set_dai_sysclk, | ||
486 | } | ||
487 | }; | ||
488 | EXPORT_SYMBOL_GPL(tlv320aic23_dai); | ||
489 | |||
490 | static int tlv320aic23_suspend(struct platform_device *pdev, | ||
491 | pm_message_t state) | ||
492 | { | ||
493 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
494 | struct snd_soc_codec *codec = socdev->codec; | ||
495 | |||
496 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
497 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int tlv320aic23_resume(struct platform_device *pdev) | ||
503 | { | ||
504 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
505 | struct snd_soc_codec *codec = socdev->codec; | ||
506 | int i; | ||
507 | u16 reg; | ||
508 | |||
509 | /* Sync reg_cache with the hardware */ | ||
510 | for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) { | ||
511 | u16 val = tlv320aic23_read_reg_cache(codec, reg); | ||
512 | tlv320aic23_write(codec, reg, val); | ||
513 | } | ||
514 | |||
515 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
516 | tlv320aic23_set_bias_level(codec, codec->suspend_bias_level); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * initialise the AIC23 driver | ||
523 | * register the mixer and dsp interfaces with the kernel | ||
524 | */ | ||
525 | static int tlv320aic23_init(struct snd_soc_device *socdev) | ||
526 | { | ||
527 | struct snd_soc_codec *codec = socdev->codec; | ||
528 | int ret = 0; | ||
529 | u16 reg; | ||
530 | |||
531 | codec->name = "tlv320aic23"; | ||
532 | codec->owner = THIS_MODULE; | ||
533 | codec->read = tlv320aic23_read_reg_cache; | ||
534 | codec->write = tlv320aic23_write; | ||
535 | codec->set_bias_level = tlv320aic23_set_bias_level; | ||
536 | codec->dai = &tlv320aic23_dai; | ||
537 | codec->num_dai = 1; | ||
538 | codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg); | ||
539 | codec->reg_cache = | ||
540 | kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL); | ||
541 | if (codec->reg_cache == NULL) | ||
542 | return -ENOMEM; | ||
543 | |||
544 | /* Reset codec */ | ||
545 | tlv320aic23_write(codec, TLV320AIC23_RESET, 0); | ||
546 | |||
547 | /* register pcms */ | ||
548 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
549 | if (ret < 0) { | ||
550 | printk(KERN_ERR "tlv320aic23: failed to create pcms\n"); | ||
551 | goto pcm_err; | ||
552 | } | ||
553 | |||
554 | /* power on device */ | ||
555 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
556 | |||
557 | tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); | ||
558 | |||
559 | /* Unmute input */ | ||
560 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL); | ||
561 | tlv320aic23_write(codec, TLV320AIC23_LINVOL, | ||
562 | (reg & (~TLV320AIC23_LIM_MUTED)) | | ||
563 | (TLV320AIC23_LRS_ENABLED)); | ||
564 | |||
565 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL); | ||
566 | tlv320aic23_write(codec, TLV320AIC23_RINVOL, | ||
567 | (reg & (~TLV320AIC23_LIM_MUTED)) | | ||
568 | TLV320AIC23_LRS_ENABLED); | ||
569 | |||
570 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG); | ||
571 | tlv320aic23_write(codec, TLV320AIC23_ANLG, | ||
572 | (reg) & (~TLV320AIC23_BYPASS_ON) & | ||
573 | (~TLV320AIC23_MICM_MUTED)); | ||
574 | |||
575 | /* Default output volume */ | ||
576 | tlv320aic23_write(codec, TLV320AIC23_LCHNVOL, | ||
577 | TLV320AIC23_DEFAULT_OUT_VOL & | ||
578 | TLV320AIC23_OUT_VOL_MASK); | ||
579 | tlv320aic23_write(codec, TLV320AIC23_RCHNVOL, | ||
580 | TLV320AIC23_DEFAULT_OUT_VOL & | ||
581 | TLV320AIC23_OUT_VOL_MASK); | ||
582 | |||
583 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); | ||
584 | |||
585 | tlv320aic23_add_controls(codec); | ||
586 | tlv320aic23_add_widgets(codec); | ||
587 | ret = snd_soc_register_card(socdev); | ||
588 | if (ret < 0) { | ||
589 | printk(KERN_ERR "tlv320aic23: failed to register card\n"); | ||
590 | goto card_err; | ||
591 | } | ||
592 | |||
593 | return ret; | ||
594 | |||
595 | card_err: | ||
596 | snd_soc_free_pcms(socdev); | ||
597 | snd_soc_dapm_free(socdev); | ||
598 | pcm_err: | ||
599 | kfree(codec->reg_cache); | ||
600 | return ret; | ||
601 | } | ||
602 | static struct snd_soc_device *tlv320aic23_socdev; | ||
603 | |||
604 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
605 | /* | ||
606 | * If the i2c layer weren't so broken, we could pass this kind of data | ||
607 | * around | ||
608 | */ | ||
609 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, | ||
610 | const struct i2c_device_id *i2c_id) | ||
611 | { | ||
612 | struct snd_soc_device *socdev = tlv320aic23_socdev; | ||
613 | struct snd_soc_codec *codec = socdev->codec; | ||
614 | int ret; | ||
615 | |||
616 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
617 | return -EINVAL; | ||
618 | |||
619 | i2c_set_clientdata(i2c, codec); | ||
620 | codec->control_data = i2c; | ||
621 | |||
622 | ret = tlv320aic23_init(socdev); | ||
623 | if (ret < 0) { | ||
624 | printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n"); | ||
625 | goto err; | ||
626 | } | ||
627 | return ret; | ||
628 | |||
629 | err: | ||
630 | kfree(codec); | ||
631 | kfree(i2c); | ||
632 | return ret; | ||
633 | } | ||
634 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | ||
635 | { | ||
636 | put_device(&i2c->dev); | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static const struct i2c_device_id tlv320aic23_id[] = { | ||
641 | {"tlv320aic23", 0}, | ||
642 | {} | ||
643 | }; | ||
644 | |||
645 | MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | ||
646 | |||
647 | static struct i2c_driver tlv320aic23_i2c_driver = { | ||
648 | .driver = { | ||
649 | .name = "tlv320aic23", | ||
650 | }, | ||
651 | .probe = tlv320aic23_codec_probe, | ||
652 | .remove = __exit_p(tlv320aic23_i2c_remove), | ||
653 | .id_table = tlv320aic23_id, | ||
654 | }; | ||
655 | |||
656 | #endif | ||
657 | |||
658 | static int tlv320aic23_probe(struct platform_device *pdev) | ||
659 | { | ||
660 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
661 | struct snd_soc_codec *codec; | ||
662 | int ret = 0; | ||
663 | |||
664 | printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); | ||
665 | |||
666 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
667 | if (codec == NULL) | ||
668 | return -ENOMEM; | ||
669 | |||
670 | socdev->codec = codec; | ||
671 | mutex_init(&codec->mutex); | ||
672 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
673 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
674 | |||
675 | tlv320aic23_socdev = socdev; | ||
676 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
677 | codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data; | ||
678 | codec->hw_read = NULL; | ||
679 | ret = i2c_add_driver(&tlv320aic23_i2c_driver); | ||
680 | if (ret != 0) | ||
681 | printk(KERN_ERR "can't add i2c driver"); | ||
682 | #endif | ||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | static int tlv320aic23_remove(struct platform_device *pdev) | ||
687 | { | ||
688 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
689 | struct snd_soc_codec *codec = socdev->codec; | ||
690 | |||
691 | if (codec->control_data) | ||
692 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
693 | |||
694 | snd_soc_free_pcms(socdev); | ||
695 | snd_soc_dapm_free(socdev); | ||
696 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
697 | i2c_del_driver(&tlv320aic23_i2c_driver); | ||
698 | #endif | ||
699 | kfree(codec->reg_cache); | ||
700 | kfree(codec); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { | ||
705 | .probe = tlv320aic23_probe, | ||
706 | .remove = tlv320aic23_remove, | ||
707 | .suspend = tlv320aic23_suspend, | ||
708 | .resume = tlv320aic23_resume, | ||
709 | }; | ||
710 | EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); | ||
711 | |||
712 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); | ||
713 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
714 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h new file mode 100644 index 000000000000..79d1faf8e570 --- /dev/null +++ b/sound/soc/codecs/tlv320aic23.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC23 codec driver | ||
3 | * | ||
4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _TLV320AIC23_H | ||
13 | #define _TLV320AIC23_H | ||
14 | |||
15 | /* Codec TLV320AIC23 */ | ||
16 | #define TLV320AIC23_LINVOL 0x00 | ||
17 | #define TLV320AIC23_RINVOL 0x01 | ||
18 | #define TLV320AIC23_LCHNVOL 0x02 | ||
19 | #define TLV320AIC23_RCHNVOL 0x03 | ||
20 | #define TLV320AIC23_ANLG 0x04 | ||
21 | #define TLV320AIC23_DIGT 0x05 | ||
22 | #define TLV320AIC23_PWR 0x06 | ||
23 | #define TLV320AIC23_DIGT_FMT 0x07 | ||
24 | #define TLV320AIC23_SRATE 0x08 | ||
25 | #define TLV320AIC23_ACTIVE 0x09 | ||
26 | #define TLV320AIC23_RESET 0x0F | ||
27 | |||
28 | /* Left (right) line input volume control register */ | ||
29 | #define TLV320AIC23_LRS_ENABLED 0x0100 | ||
30 | #define TLV320AIC23_LIM_MUTED 0x0080 | ||
31 | #define TLV320AIC23_LIV_DEFAULT 0x0017 | ||
32 | #define TLV320AIC23_LIV_MAX 0x001f | ||
33 | #define TLV320AIC23_LIV_MIN 0x0000 | ||
34 | |||
35 | /* Left (right) channel headphone volume control register */ | ||
36 | #define TLV320AIC23_LZC_ON 0x0080 | ||
37 | #define TLV320AIC23_LHV_DEFAULT 0x0079 | ||
38 | #define TLV320AIC23_LHV_MAX 0x007f | ||
39 | #define TLV320AIC23_LHV_MIN 0x0000 | ||
40 | |||
41 | /* Analog audio path control register */ | ||
42 | #define TLV320AIC23_STA_REG(x) ((x)<<6) | ||
43 | #define TLV320AIC23_STE_ENABLED 0x0020 | ||
44 | #define TLV320AIC23_DAC_SELECTED 0x0010 | ||
45 | #define TLV320AIC23_BYPASS_ON 0x0008 | ||
46 | #define TLV320AIC23_INSEL_MIC 0x0004 | ||
47 | #define TLV320AIC23_MICM_MUTED 0x0002 | ||
48 | #define TLV320AIC23_MICB_20DB 0x0001 | ||
49 | |||
50 | /* Digital audio path control register */ | ||
51 | #define TLV320AIC23_DACM_MUTE 0x0008 | ||
52 | #define TLV320AIC23_DEEMP_32K 0x0002 | ||
53 | #define TLV320AIC23_DEEMP_44K 0x0004 | ||
54 | #define TLV320AIC23_DEEMP_48K 0x0006 | ||
55 | #define TLV320AIC23_ADCHP_ON 0x0001 | ||
56 | |||
57 | /* Power control down register */ | ||
58 | #define TLV320AIC23_DEVICE_PWR_OFF 0x0080 | ||
59 | #define TLV320AIC23_CLK_OFF 0x0040 | ||
60 | #define TLV320AIC23_OSC_OFF 0x0020 | ||
61 | #define TLV320AIC23_OUT_OFF 0x0010 | ||
62 | #define TLV320AIC23_DAC_OFF 0x0008 | ||
63 | #define TLV320AIC23_ADC_OFF 0x0004 | ||
64 | #define TLV320AIC23_MIC_OFF 0x0002 | ||
65 | #define TLV320AIC23_LINE_OFF 0x0001 | ||
66 | |||
67 | /* Digital audio interface register */ | ||
68 | #define TLV320AIC23_MS_MASTER 0x0040 | ||
69 | #define TLV320AIC23_LRSWAP_ON 0x0020 | ||
70 | #define TLV320AIC23_LRP_ON 0x0010 | ||
71 | #define TLV320AIC23_IWL_16 0x0000 | ||
72 | #define TLV320AIC23_IWL_20 0x0004 | ||
73 | #define TLV320AIC23_IWL_24 0x0008 | ||
74 | #define TLV320AIC23_IWL_32 0x000C | ||
75 | #define TLV320AIC23_FOR_I2S 0x0002 | ||
76 | #define TLV320AIC23_FOR_DSP 0x0003 | ||
77 | #define TLV320AIC23_FOR_LJUST 0x0001 | ||
78 | |||
79 | /* Sample rate control register */ | ||
80 | #define TLV320AIC23_CLKOUT_HALF 0x0080 | ||
81 | #define TLV320AIC23_CLKIN_HALF 0x0040 | ||
82 | #define TLV320AIC23_BOSR_384fs 0x0002 /* BOSR_272fs in USB mode */ | ||
83 | #define TLV320AIC23_USB_CLK_ON 0x0001 | ||
84 | #define TLV320AIC23_SR_MASK 0xf | ||
85 | #define TLV320AIC23_CLKOUT_SHIFT 7 | ||
86 | #define TLV320AIC23_CLKIN_SHIFT 6 | ||
87 | #define TLV320AIC23_SR_SHIFT 2 | ||
88 | #define TLV320AIC23_BOSR_SHIFT 1 | ||
89 | |||
90 | /* Digital interface register */ | ||
91 | #define TLV320AIC23_ACT_ON 0x0001 | ||
92 | |||
93 | /* | ||
94 | * AUDIO related MACROS | ||
95 | */ | ||
96 | |||
97 | #define TLV320AIC23_DEFAULT_OUT_VOL 0x70 | ||
98 | #define TLV320AIC23_DEFAULT_IN_VOLUME 0x10 | ||
99 | |||
100 | #define TLV320AIC23_OUT_VOL_MIN TLV320AIC23_LHV_MIN | ||
101 | #define TLV320AIC23_OUT_VOL_MAX TLV320AIC23_LHV_MAX | ||
102 | #define TLV320AIC23_OUT_VO_RANGE (TLV320AIC23_OUT_VOL_MAX - \ | ||
103 | TLV320AIC23_OUT_VOL_MIN) | ||
104 | #define TLV320AIC23_OUT_VOL_MASK TLV320AIC23_OUT_VOL_MAX | ||
105 | |||
106 | #define TLV320AIC23_IN_VOL_MIN TLV320AIC23_LIV_MIN | ||
107 | #define TLV320AIC23_IN_VOL_MAX TLV320AIC23_LIV_MAX | ||
108 | #define TLV320AIC23_IN_VOL_RANGE (TLV320AIC23_IN_VOL_MAX - \ | ||
109 | TLV320AIC23_IN_VOL_MIN) | ||
110 | #define TLV320AIC23_IN_VOL_MASK TLV320AIC23_IN_VOL_MAX | ||
111 | |||
112 | #define TLV320AIC23_SIDETONE_MASK 0x1c0 | ||
113 | #define TLV320AIC23_SIDETONE_0 0x100 | ||
114 | #define TLV320AIC23_SIDETONE_6 0x000 | ||
115 | #define TLV320AIC23_SIDETONE_9 0x040 | ||
116 | #define TLV320AIC23_SIDETONE_12 0x080 | ||
117 | #define TLV320AIC23_SIDETONE_18 0x0c0 | ||
118 | |||
119 | extern struct snd_soc_dai tlv320aic23_dai; | ||
120 | extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23; | ||
121 | |||
122 | #endif /* _TLV320AIC23_H */ | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 566a427c928f..05336ed7e493 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -48,7 +48,6 @@ | |||
48 | 48 | ||
49 | #include "tlv320aic3x.h" | 49 | #include "tlv320aic3x.h" |
50 | 50 | ||
51 | #define AUDIO_NAME "aic3x" | ||
52 | #define AIC3X_VERSION "0.2" | 51 | #define AIC3X_VERSION "0.2" |
53 | 52 | ||
54 | /* codec private data */ | 53 | /* codec private data */ |
@@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected); | |||
991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 990 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
992 | 991 | ||
993 | struct snd_soc_dai aic3x_dai = { | 992 | struct snd_soc_dai aic3x_dai = { |
994 | .name = "aic3x", | 993 | .name = "tlv320aic3x", |
995 | .playback = { | 994 | .playback = { |
996 | .stream_name = "Playback", | 995 | .stream_name = "Playback", |
997 | .channels_min = 1, | 996 | .channels_min = 1, |
@@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1055 | struct aic3x_setup_data *setup = socdev->codec_data; | 1054 | struct aic3x_setup_data *setup = socdev->codec_data; |
1056 | int reg, ret = 0; | 1055 | int reg, ret = 0; |
1057 | 1056 | ||
1058 | codec->name = "aic3x"; | 1057 | codec->name = "tlv320aic3x"; |
1059 | codec->owner = THIS_MODULE; | 1058 | codec->owner = THIS_MODULE; |
1060 | codec->read = aic3x_read_reg_cache; | 1059 | codec->read = aic3x_read_reg_cache; |
1061 | codec->write = aic3x_write; | 1060 | codec->write = aic3x_write; |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index d206d7f892b6..a69ee72a7af5 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include "uda1380.h" | 36 | #include "uda1380.h" |
37 | 37 | ||
38 | #define UDA1380_VERSION "0.6" | 38 | #define UDA1380_VERSION "0.6" |
39 | #define AUDIO_NAME "uda1380" | ||
40 | 39 | ||
41 | /* | 40 | /* |
42 | * uda1380 register cache | 41 | * uda1380 register cache |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 9a37c8d95ed2..d8ca2da8d634 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 6 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/spi/spi.h> | ||
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
@@ -27,7 +28,6 @@ | |||
27 | 28 | ||
28 | #include "wm8510.h" | 29 | #include "wm8510.h" |
29 | 30 | ||
30 | #define AUDIO_NAME "wm8510" | ||
31 | #define WM8510_VERSION "0.6" | 31 | #define WM8510_VERSION "0.6" |
32 | 32 | ||
33 | struct snd_soc_codec_device soc_codec_dev_wm8510; | 33 | struct snd_soc_codec_device soc_codec_dev_wm8510; |
@@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | |||
55 | 0x0001, | 55 | 0x0001, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | #define WM8510_POWER1_BIASEN 0x08 | ||
59 | #define WM8510_POWER1_BUFIOEN 0x10 | ||
60 | |||
58 | /* | 61 | /* |
59 | * read wm8510 register cache | 62 | * read wm8510 register cache |
60 | */ | 63 | */ |
@@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), | |||
224 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), | 227 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), |
225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), | 228 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), |
226 | 229 | ||
227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, | 230 | SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0, |
228 | &wm8510_micpga_controls[0], | 231 | &wm8510_micpga_controls[0], |
229 | ARRAY_SIZE(wm8510_micpga_controls)), | 232 | ARRAY_SIZE(wm8510_micpga_controls)), |
230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, | 233 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, |
231 | &wm8510_boost_controls[0], | 234 | &wm8510_boost_controls[0], |
232 | ARRAY_SIZE(wm8510_boost_controls)), | 235 | ARRAY_SIZE(wm8510_boost_controls)), |
@@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute) | |||
526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | 529 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, |
527 | enum snd_soc_bias_level level) | 530 | enum snd_soc_bias_level level) |
528 | { | 531 | { |
532 | u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3; | ||
529 | 533 | ||
530 | switch (level) { | 534 | switch (level) { |
531 | case SND_SOC_BIAS_ON: | 535 | case SND_SOC_BIAS_ON: |
532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); | ||
533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); | ||
534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); | ||
535 | break; | ||
536 | case SND_SOC_BIAS_PREPARE: | 536 | case SND_SOC_BIAS_PREPARE: |
537 | power1 |= 0x1; /* VMID 50k */ | ||
538 | wm8510_write(codec, WM8510_POWER1, power1); | ||
539 | break; | ||
540 | |||
537 | case SND_SOC_BIAS_STANDBY: | 541 | case SND_SOC_BIAS_STANDBY: |
542 | power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN; | ||
543 | |||
544 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
545 | /* Initial cap charge at VMID 5k */ | ||
546 | wm8510_write(codec, WM8510_POWER1, power1 | 0x3); | ||
547 | mdelay(100); | ||
548 | } | ||
549 | |||
550 | power1 |= 0x2; /* VMID 500k */ | ||
551 | wm8510_write(codec, WM8510_POWER1, power1); | ||
538 | break; | 552 | break; |
553 | |||
539 | case SND_SOC_BIAS_OFF: | 554 | case SND_SOC_BIAS_OFF: |
540 | /* everything off, dac mute, inactive */ | 555 | wm8510_write(codec, WM8510_POWER1, 0); |
541 | wm8510_write(codec, WM8510_POWER1, 0x0); | 556 | wm8510_write(codec, WM8510_POWER2, 0); |
542 | wm8510_write(codec, WM8510_POWER2, 0x0); | 557 | wm8510_write(codec, WM8510_POWER3, 0); |
543 | wm8510_write(codec, WM8510_POWER3, 0x0); | ||
544 | break; | 558 | break; |
545 | } | 559 | } |
560 | |||
546 | codec->bias_level = level; | 561 | codec->bias_level = level; |
547 | return 0; | 562 | return 0; |
548 | } | 563 | } |
@@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
640 | } | 655 | } |
641 | 656 | ||
642 | /* power on device */ | 657 | /* power on device */ |
658 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 659 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
644 | wm8510_add_controls(codec); | 660 | wm8510_add_controls(codec); |
645 | wm8510_add_widgets(codec); | 661 | wm8510_add_widgets(codec); |
@@ -747,6 +763,62 @@ err_driver: | |||
747 | } | 763 | } |
748 | #endif | 764 | #endif |
749 | 765 | ||
766 | #if defined(CONFIG_SPI_MASTER) | ||
767 | static int __devinit wm8510_spi_probe(struct spi_device *spi) | ||
768 | { | ||
769 | struct snd_soc_device *socdev = wm8510_socdev; | ||
770 | struct snd_soc_codec *codec = socdev->codec; | ||
771 | int ret; | ||
772 | |||
773 | codec->control_data = spi; | ||
774 | |||
775 | ret = wm8510_init(socdev); | ||
776 | if (ret < 0) | ||
777 | dev_err(&spi->dev, "failed to initialise WM8510\n"); | ||
778 | |||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | static int __devexit wm8510_spi_remove(struct spi_device *spi) | ||
783 | { | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static struct spi_driver wm8510_spi_driver = { | ||
788 | .driver = { | ||
789 | .name = "wm8510", | ||
790 | .bus = &spi_bus_type, | ||
791 | .owner = THIS_MODULE, | ||
792 | }, | ||
793 | .probe = wm8510_spi_probe, | ||
794 | .remove = __devexit_p(wm8510_spi_remove), | ||
795 | }; | ||
796 | |||
797 | static int wm8510_spi_write(struct spi_device *spi, const char *data, int len) | ||
798 | { | ||
799 | struct spi_transfer t; | ||
800 | struct spi_message m; | ||
801 | u8 msg[2]; | ||
802 | |||
803 | if (len <= 0) | ||
804 | return 0; | ||
805 | |||
806 | msg[0] = data[0]; | ||
807 | msg[1] = data[1]; | ||
808 | |||
809 | spi_message_init(&m); | ||
810 | memset(&t, 0, (sizeof t)); | ||
811 | |||
812 | t.tx_buf = &msg[0]; | ||
813 | t.len = len; | ||
814 | |||
815 | spi_message_add_tail(&t, &m); | ||
816 | spi_sync(spi, &m); | ||
817 | |||
818 | return len; | ||
819 | } | ||
820 | #endif /* CONFIG_SPI_MASTER */ | ||
821 | |||
750 | static int wm8510_probe(struct platform_device *pdev) | 822 | static int wm8510_probe(struct platform_device *pdev) |
751 | { | 823 | { |
752 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 824 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -772,8 +844,14 @@ static int wm8510_probe(struct platform_device *pdev) | |||
772 | codec->hw_write = (hw_write_t)i2c_master_send; | 844 | codec->hw_write = (hw_write_t)i2c_master_send; |
773 | ret = wm8510_add_i2c_device(pdev, setup); | 845 | ret = wm8510_add_i2c_device(pdev, setup); |
774 | } | 846 | } |
775 | #else | 847 | #endif |
776 | /* Add other interfaces here */ | 848 | #if defined(CONFIG_SPI_MASTER) |
849 | if (setup->spi) { | ||
850 | codec->hw_write = (hw_write_t)wm8510_spi_write; | ||
851 | ret = spi_register_driver(&wm8510_spi_driver); | ||
852 | if (ret != 0) | ||
853 | printk(KERN_ERR "can't add spi driver"); | ||
854 | } | ||
777 | #endif | 855 | #endif |
778 | 856 | ||
779 | if (ret != 0) | 857 | if (ret != 0) |
@@ -796,6 +874,9 @@ static int wm8510_remove(struct platform_device *pdev) | |||
796 | i2c_unregister_device(codec->control_data); | 874 | i2c_unregister_device(codec->control_data); |
797 | i2c_del_driver(&wm8510_i2c_driver); | 875 | i2c_del_driver(&wm8510_i2c_driver); |
798 | #endif | 876 | #endif |
877 | #if defined(CONFIG_SPI_MASTER) | ||
878 | spi_unregister_driver(&wm8510_spi_driver); | ||
879 | #endif | ||
799 | kfree(codec); | 880 | kfree(codec); |
800 | 881 | ||
801 | return 0; | 882 | return 0; |
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h index c53683960456..bdefcf5c69ff 100644 --- a/sound/soc/codecs/wm8510.h +++ b/sound/soc/codecs/wm8510.h | |||
@@ -94,6 +94,7 @@ | |||
94 | #define WM8510_MCLKDIV_12 (7 << 5) | 94 | #define WM8510_MCLKDIV_12 (7 << 5) |
95 | 95 | ||
96 | struct wm8510_setup_data { | 96 | struct wm8510_setup_data { |
97 | int spi; | ||
97 | int i2c_bus; | 98 | int i2c_bus; |
98 | unsigned short i2c_address; | 99 | unsigned short i2c_address; |
99 | }; | 100 | }; |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index df1ffbe305bf..627ebfb4209b 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
@@ -36,7 +35,6 @@ | |||
36 | 35 | ||
37 | #include "wm8580.h" | 36 | #include "wm8580.h" |
38 | 37 | ||
39 | #define AUDIO_NAME "wm8580" | ||
40 | #define WM8580_VERSION "0.1" | 38 | #define WM8580_VERSION "0.1" |
41 | 39 | ||
42 | struct pll_state { | 40 | struct pll_state { |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7b64d9a7ff76..7f8a7e36b33e 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | #include "wm8731.h" | 30 | #include "wm8731.h" |
31 | 31 | ||
32 | #define AUDIO_NAME "wm8731" | ||
33 | #define WM8731_VERSION "0.13" | 32 | #define WM8731_VERSION "0.13" |
34 | 33 | ||
35 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 4892e398a598..9b7296ee5b08 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | #include "wm8750.h" | 30 | #include "wm8750.h" |
31 | 31 | ||
32 | #define AUDIO_NAME "WM8750" | ||
33 | #define WM8750_VERSION "0.12" | 32 | #define WM8750_VERSION "0.12" |
34 | 33 | ||
35 | /* codec private data */ | 34 | /* codec private data */ |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 8c4df44f3345..d426eaa22185 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm8753.c -- WM8753 ALSA Soc Audio driver | 2 | * wm8753.c -- WM8753 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
@@ -40,6 +39,7 @@ | |||
40 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
41 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
42 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/spi/spi.h> | ||
43 | #include <sound/core.h> | 43 | #include <sound/core.h> |
44 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
45 | #include <sound/pcm_params.h> | 45 | #include <sound/pcm_params.h> |
@@ -51,7 +51,6 @@ | |||
51 | 51 | ||
52 | #include "wm8753.h" | 52 | #include "wm8753.h" |
53 | 53 | ||
54 | #define AUDIO_NAME "wm8753" | ||
55 | #define WM8753_VERSION "0.16" | 54 | #define WM8753_VERSION "0.16" |
56 | 55 | ||
57 | static int caps_charge = 2000; | 56 | static int caps_charge = 2000; |
@@ -1719,6 +1718,63 @@ err_driver: | |||
1719 | } | 1718 | } |
1720 | #endif | 1719 | #endif |
1721 | 1720 | ||
1721 | #if defined(CONFIG_SPI_MASTER) | ||
1722 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | ||
1723 | { | ||
1724 | struct snd_soc_device *socdev = wm8753_socdev; | ||
1725 | struct snd_soc_codec *codec = socdev->codec; | ||
1726 | int ret; | ||
1727 | |||
1728 | codec->control_data = spi; | ||
1729 | |||
1730 | ret = wm8753_init(socdev); | ||
1731 | if (ret < 0) | ||
1732 | dev_err(&spi->dev, "failed to initialise WM8753\n"); | ||
1733 | |||
1734 | return ret; | ||
1735 | } | ||
1736 | |||
1737 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | ||
1738 | { | ||
1739 | return 0; | ||
1740 | } | ||
1741 | |||
1742 | static struct spi_driver wm8753_spi_driver = { | ||
1743 | .driver = { | ||
1744 | .name = "wm8753", | ||
1745 | .bus = &spi_bus_type, | ||
1746 | .owner = THIS_MODULE, | ||
1747 | }, | ||
1748 | .probe = wm8753_spi_probe, | ||
1749 | .remove = __devexit_p(wm8753_spi_remove), | ||
1750 | }; | ||
1751 | |||
1752 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | ||
1753 | { | ||
1754 | struct spi_transfer t; | ||
1755 | struct spi_message m; | ||
1756 | u8 msg[2]; | ||
1757 | |||
1758 | if (len <= 0) | ||
1759 | return 0; | ||
1760 | |||
1761 | msg[0] = data[0]; | ||
1762 | msg[1] = data[1]; | ||
1763 | |||
1764 | spi_message_init(&m); | ||
1765 | memset(&t, 0, (sizeof t)); | ||
1766 | |||
1767 | t.tx_buf = &msg[0]; | ||
1768 | t.len = len; | ||
1769 | |||
1770 | spi_message_add_tail(&t, &m); | ||
1771 | spi_sync(spi, &m); | ||
1772 | |||
1773 | return len; | ||
1774 | } | ||
1775 | #endif | ||
1776 | |||
1777 | |||
1722 | static int wm8753_probe(struct platform_device *pdev) | 1778 | static int wm8753_probe(struct platform_device *pdev) |
1723 | { | 1779 | { |
1724 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1780 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -1753,8 +1809,14 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1753 | codec->hw_write = (hw_write_t)i2c_master_send; | 1809 | codec->hw_write = (hw_write_t)i2c_master_send; |
1754 | ret = wm8753_add_i2c_device(pdev, setup); | 1810 | ret = wm8753_add_i2c_device(pdev, setup); |
1755 | } | 1811 | } |
1756 | #else | 1812 | #endif |
1757 | /* Add other interfaces here */ | 1813 | #if defined(CONFIG_SPI_MASTER) |
1814 | if (setup->spi) { | ||
1815 | codec->hw_write = (hw_write_t)wm8753_spi_write; | ||
1816 | ret = spi_register_driver(&wm8753_spi_driver); | ||
1817 | if (ret != 0) | ||
1818 | printk(KERN_ERR "can't add spi driver"); | ||
1819 | } | ||
1758 | #endif | 1820 | #endif |
1759 | 1821 | ||
1760 | if (ret != 0) { | 1822 | if (ret != 0) { |
@@ -1798,6 +1860,9 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1798 | i2c_unregister_device(codec->control_data); | 1860 | i2c_unregister_device(codec->control_data); |
1799 | i2c_del_driver(&wm8753_i2c_driver); | 1861 | i2c_del_driver(&wm8753_i2c_driver); |
1800 | #endif | 1862 | #endif |
1863 | #if defined(CONFIG_SPI_MASTER) | ||
1864 | spi_unregister_driver(&wm8753_spi_driver); | ||
1865 | #endif | ||
1801 | kfree(codec->private_data); | 1866 | kfree(codec->private_data); |
1802 | kfree(codec); | 1867 | kfree(codec); |
1803 | 1868 | ||
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 7defde069f1d..f55704ce931b 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm8753.h -- audio driver for WM8753 | 2 | * wm8753.h -- audio driver for WM8753 |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
@@ -79,6 +78,7 @@ | |||
79 | #define WM8753_ADCTL2 0x3f | 78 | #define WM8753_ADCTL2 0x3f |
80 | 79 | ||
81 | struct wm8753_setup_data { | 80 | struct wm8753_setup_data { |
81 | int spi; | ||
82 | int i2c_bus; | 82 | int i2c_bus; |
83 | unsigned short i2c_address; | 83 | unsigned short i2c_address; |
84 | }; | 84 | }; |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 0b8c6d38b48f..3b326c9b5586 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index a3f54ec4226e..ce40d7877605 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -653,14 +653,14 @@ static const struct snd_kcontrol_new wm8903_snd_controls[] = { | |||
653 | 653 | ||
654 | /* Input PGAs - No TLV since the scale depends on PGA mode */ | 654 | /* Input PGAs - No TLV since the scale depends on PGA mode */ |
655 | SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0, | 655 | SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0, |
656 | 7, 1, 0), | 656 | 7, 1, 1), |
657 | SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0, | 657 | SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0, |
658 | 0, 31, 0), | 658 | 0, 31, 0), |
659 | SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1, | 659 | SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1, |
660 | 6, 1, 0), | 660 | 6, 1, 0), |
661 | 661 | ||
662 | SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0, | 662 | SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0, |
663 | 7, 1, 0), | 663 | 7, 1, 1), |
664 | SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0, | 664 | SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0, |
665 | 0, 31, 0), | 665 | 0, 31, 0), |
666 | SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1, | 666 | SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1, |
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 974a4cd0f3fd..f41a578ddd4f 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c | |||
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | #include "wm8971.h" | 30 | #include "wm8971.h" |
31 | 31 | ||
32 | #define AUDIO_NAME "wm8971" | ||
33 | #define WM8971_VERSION "0.9" | 32 | #define WM8971_VERSION "0.9" |
34 | 33 | ||
35 | #define WM8971_REG_COUNT 43 | 34 | #define WM8971_REG_COUNT 43 |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 63410d7b5efb..572d22b0880b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -30,7 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8990.h" | 31 | #include "wm8990.h" |
32 | 32 | ||
33 | #define AUDIO_NAME "wm8990" | ||
34 | #define WM8990_VERSION "0.2" | 33 | #define WM8990_VERSION "0.2" |
35 | 34 | ||
36 | /* codec private data */ | 35 | /* codec private data */ |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 2f1c91b1d556..ffb471e420e2 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm9712.c -- ALSA Soc WM9712 codec support | 2 | * wm9712.c -- ALSA Soc WM9712 codec support |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 441d0580db1f..aba402b3c999 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm9713.c -- ALSA Soc WM9713 codec support | 2 | * wm9713.c -- ALSA Soc WM9713 codec support |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index aea27e70043c..8b7766b998d7 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -13,3 +13,11 @@ config SND_OMAP_SOC_N810 | |||
13 | select SND_SOC_TLV320AIC3X | 13 | select SND_SOC_TLV320AIC3X |
14 | help | 14 | help |
15 | Say Y if you want to add support for SoC audio on Nokia N810. | 15 | Say Y if you want to add support for SoC audio on Nokia N810. |
16 | |||
17 | config SND_OMAP_SOC_OSK5912 | ||
18 | tristate "SoC Audio support for omap osk5912" | ||
19 | depends on SND_OMAP_SOC && MACH_OMAP_OSK | ||
20 | select SND_OMAP_SOC_MCBSP | ||
21 | select SND_SOC_TLV320AIC23 | ||
22 | help | ||
23 | Say Y if you want to add support for SoC audio on osk5912. | ||
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index d8d8d58075e3..e09d1f297f64 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o | |||
7 | 7 | ||
8 | # OMAP Machine Support | 8 | # OMAP Machine Support |
9 | snd-soc-n810-objs := n810.o | 9 | snd-soc-n810-objs := n810.o |
10 | snd-soc-osk5912-objs := osk5912.o | ||
10 | 11 | ||
11 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 12 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
13 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o | ||
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d166b6b2a60d..fae3ad36e0bf 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) | |||
247 | int i, err; | 247 | int i, err; |
248 | 248 | ||
249 | /* Not connected */ | 249 | /* Not connected */ |
250 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); | 250 | snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); |
251 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); | 251 | snd_soc_dapm_nc_pin(codec, "HPLCOM"); |
252 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); | 252 | snd_soc_dapm_nc_pin(codec, "HPRCOM"); |
253 | 253 | ||
254 | /* Add N810 specific controls */ | 254 | /* Add N810 specific controls */ |
255 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { | 255 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { |
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 35310e16d7f3..0a063a98a661 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -59,12 +59,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS]; | |||
59 | * Stream DMA parameters. DMA request line and port address are set runtime | 59 | * Stream DMA parameters. DMA request line and port address are set runtime |
60 | * since they are different between OMAP1 and later OMAPs | 60 | * since they are different between OMAP1 and later OMAPs |
61 | */ | 61 | */ |
62 | static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = { | 62 | static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2]; |
63 | { | ||
64 | { .name = "I2S PCM Stereo out", }, | ||
65 | { .name = "I2S PCM Stereo in", }, | ||
66 | }, | ||
67 | }; | ||
68 | 63 | ||
69 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) | 64 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) |
70 | static const int omap1_dma_reqs[][2] = { | 65 | static const int omap1_dma_reqs[][2] = { |
@@ -84,11 +79,22 @@ static const unsigned long omap1_mcbsp_port[][2] = { | |||
84 | static const int omap1_dma_reqs[][2] = {}; | 79 | static const int omap1_dma_reqs[][2] = {}; |
85 | static const unsigned long omap1_mcbsp_port[][2] = {}; | 80 | static const unsigned long omap1_mcbsp_port[][2] = {}; |
86 | #endif | 81 | #endif |
87 | #if defined(CONFIG_ARCH_OMAP2420) | 82 | |
88 | static const int omap2420_dma_reqs[][2] = { | 83 | #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) |
84 | static const int omap24xx_dma_reqs[][2] = { | ||
89 | { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, | 85 | { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, |
90 | { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, | 86 | { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, |
87 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) | ||
88 | { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, | ||
89 | { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, | ||
90 | { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, | ||
91 | #endif | ||
91 | }; | 92 | }; |
93 | #else | ||
94 | static const int omap24xx_dma_reqs[][2] = {}; | ||
95 | #endif | ||
96 | |||
97 | #if defined(CONFIG_ARCH_OMAP2420) | ||
92 | static const unsigned long omap2420_mcbsp_port[][2] = { | 98 | static const unsigned long omap2420_mcbsp_port[][2] = { |
93 | { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, | 99 | { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, |
94 | OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, | 100 | OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, |
@@ -96,10 +102,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = { | |||
96 | OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 }, | 102 | OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 }, |
97 | }; | 103 | }; |
98 | #else | 104 | #else |
99 | static const int omap2420_dma_reqs[][2] = {}; | ||
100 | static const unsigned long omap2420_mcbsp_port[][2] = {}; | 105 | static const unsigned long omap2420_mcbsp_port[][2] = {}; |
101 | #endif | 106 | #endif |
102 | 107 | ||
108 | #if defined(CONFIG_ARCH_OMAP2430) | ||
109 | static const unsigned long omap2430_mcbsp_port[][2] = { | ||
110 | { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, | ||
111 | OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, | ||
112 | { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR, | ||
113 | OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR }, | ||
114 | { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR, | ||
115 | OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR }, | ||
116 | { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR, | ||
117 | OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR }, | ||
118 | { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR, | ||
119 | OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR }, | ||
120 | }; | ||
121 | #else | ||
122 | static const unsigned long omap2430_mcbsp_port[][2] = {}; | ||
123 | #endif | ||
124 | |||
125 | #if defined(CONFIG_ARCH_OMAP34XX) | ||
126 | static const unsigned long omap34xx_mcbsp_port[][2] = { | ||
127 | { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, | ||
128 | OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, | ||
129 | { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR, | ||
130 | OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR }, | ||
131 | { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR, | ||
132 | OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR }, | ||
133 | { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR, | ||
134 | OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR }, | ||
135 | { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR, | ||
136 | OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR }, | ||
137 | }; | ||
138 | #else | ||
139 | static const unsigned long omap34xx_mcbsp_port[][2] = {}; | ||
140 | #endif | ||
141 | |||
103 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) | 142 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) |
104 | { | 143 | { |
105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 144 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
@@ -167,14 +206,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
167 | dma = omap1_dma_reqs[bus_id][substream->stream]; | 206 | dma = omap1_dma_reqs[bus_id][substream->stream]; |
168 | port = omap1_mcbsp_port[bus_id][substream->stream]; | 207 | port = omap1_mcbsp_port[bus_id][substream->stream]; |
169 | } else if (cpu_is_omap2420()) { | 208 | } else if (cpu_is_omap2420()) { |
170 | dma = omap2420_dma_reqs[bus_id][substream->stream]; | 209 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; |
171 | port = omap2420_mcbsp_port[bus_id][substream->stream]; | 210 | port = omap2420_mcbsp_port[bus_id][substream->stream]; |
211 | } else if (cpu_is_omap2430()) { | ||
212 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | ||
213 | port = omap2430_mcbsp_port[bus_id][substream->stream]; | ||
214 | } else if (cpu_is_omap343x()) { | ||
215 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | ||
216 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; | ||
172 | } else { | 217 | } else { |
173 | /* | ||
174 | * TODO: Add support for 2430 and 3430 | ||
175 | */ | ||
176 | return -ENODEV; | 218 | return -ENODEV; |
177 | } | 219 | } |
220 | omap_mcbsp_dai_dma_params[id][substream->stream].name = | ||
221 | substream->stream ? "Audio Capture" : "Audio Playback"; | ||
178 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; | 222 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; |
179 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; | 223 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; |
180 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; | 224 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; |
@@ -245,6 +289,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
245 | regs->rcr2 |= RDATDLY(1); | 289 | regs->rcr2 |= RDATDLY(1); |
246 | regs->xcr2 |= XDATDLY(1); | 290 | regs->xcr2 |= XDATDLY(1); |
247 | break; | 291 | break; |
292 | case SND_SOC_DAIFMT_DSP_A: | ||
293 | /* 0-bit data delay */ | ||
294 | regs->rcr2 |= RDATDLY(0); | ||
295 | regs->xcr2 |= XDATDLY(0); | ||
296 | break; | ||
248 | default: | 297 | default: |
249 | /* Unsupported data format */ | 298 | /* Unsupported data format */ |
250 | return -EINVAL; | 299 | return -EINVAL; |
@@ -310,7 +359,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
310 | int clk_id) | 359 | int clk_id) |
311 | { | 360 | { |
312 | int sel_bit; | 361 | int sel_bit; |
313 | u16 reg; | 362 | u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1; |
314 | 363 | ||
315 | if (cpu_class_is_omap1()) { | 364 | if (cpu_class_is_omap1()) { |
316 | /* OMAP1's can use only external source clock */ | 365 | /* OMAP1's can use only external source clock */ |
@@ -320,6 +369,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
320 | return 0; | 369 | return 0; |
321 | } | 370 | } |
322 | 371 | ||
372 | if (cpu_is_omap2420() && mcbsp_data->bus_id > 1) | ||
373 | return -EINVAL; | ||
374 | |||
375 | if (cpu_is_omap343x()) | ||
376 | reg_devconf1 = OMAP343X_CONTROL_DEVCONF1; | ||
377 | |||
323 | switch (mcbsp_data->bus_id) { | 378 | switch (mcbsp_data->bus_id) { |
324 | case 0: | 379 | case 0: |
325 | reg = OMAP2_CONTROL_DEVCONF0; | 380 | reg = OMAP2_CONTROL_DEVCONF0; |
@@ -329,20 +384,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
329 | reg = OMAP2_CONTROL_DEVCONF0; | 384 | reg = OMAP2_CONTROL_DEVCONF0; |
330 | sel_bit = 6; | 385 | sel_bit = 6; |
331 | break; | 386 | break; |
332 | /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */ | 387 | case 2: |
388 | reg = reg_devconf1; | ||
389 | sel_bit = 0; | ||
390 | break; | ||
391 | case 3: | ||
392 | reg = reg_devconf1; | ||
393 | sel_bit = 2; | ||
394 | break; | ||
395 | case 4: | ||
396 | reg = reg_devconf1; | ||
397 | sel_bit = 4; | ||
398 | break; | ||
333 | default: | 399 | default: |
334 | return -EINVAL; | 400 | return -EINVAL; |
335 | } | 401 | } |
336 | 402 | ||
337 | if (cpu_class_is_omap2()) { | 403 | if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) |
338 | if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) { | 404 | omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg); |
339 | omap_ctrl_writel(omap_ctrl_readl(reg) & | 405 | else |
340 | ~(1 << sel_bit), reg); | 406 | omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg); |
341 | } else { | ||
342 | omap_ctrl_writel(omap_ctrl_readl(reg) | | ||
343 | (1 << sel_bit), reg); | ||
344 | } | ||
345 | } | ||
346 | 407 | ||
347 | return 0; | 408 | return 0; |
348 | } | 409 | } |
@@ -376,37 +437,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
376 | return err; | 437 | return err; |
377 | } | 438 | } |
378 | 439 | ||
379 | struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = { | 440 | #define OMAP_MCBSP_DAI_BUILDER(link_id) \ |
380 | { | 441 | { \ |
381 | .name = "omap-mcbsp-dai", | 442 | .name = "omap-mcbsp-dai-(link_id)", \ |
382 | .id = 0, | 443 | .id = (link_id), \ |
383 | .type = SND_SOC_DAI_I2S, | 444 | .type = SND_SOC_DAI_I2S, \ |
384 | .playback = { | 445 | .playback = { \ |
385 | .channels_min = 2, | 446 | .channels_min = 2, \ |
386 | .channels_max = 2, | 447 | .channels_max = 2, \ |
387 | .rates = OMAP_MCBSP_RATES, | 448 | .rates = OMAP_MCBSP_RATES, \ |
388 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 449 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ |
389 | }, | 450 | }, \ |
390 | .capture = { | 451 | .capture = { \ |
391 | .channels_min = 2, | 452 | .channels_min = 2, \ |
392 | .channels_max = 2, | 453 | .channels_max = 2, \ |
393 | .rates = OMAP_MCBSP_RATES, | 454 | .rates = OMAP_MCBSP_RATES, \ |
394 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 455 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ |
395 | }, | 456 | }, \ |
396 | .ops = { | 457 | .ops = { \ |
397 | .startup = omap_mcbsp_dai_startup, | 458 | .startup = omap_mcbsp_dai_startup, \ |
398 | .shutdown = omap_mcbsp_dai_shutdown, | 459 | .shutdown = omap_mcbsp_dai_shutdown, \ |
399 | .trigger = omap_mcbsp_dai_trigger, | 460 | .trigger = omap_mcbsp_dai_trigger, \ |
400 | .hw_params = omap_mcbsp_dai_hw_params, | 461 | .hw_params = omap_mcbsp_dai_hw_params, \ |
401 | }, | 462 | }, \ |
402 | .dai_ops = { | 463 | .dai_ops = { \ |
403 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, | 464 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ |
404 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, | 465 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ |
405 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, | 466 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ |
406 | }, | 467 | }, \ |
407 | .private_data = &mcbsp_data[0].bus_id, | 468 | .private_data = &mcbsp_data[(link_id)].bus_id, \ |
408 | }, | 469 | } |
470 | |||
471 | struct snd_soc_dai omap_mcbsp_dai[] = { | ||
472 | OMAP_MCBSP_DAI_BUILDER(0), | ||
473 | OMAP_MCBSP_DAI_BUILDER(1), | ||
474 | #if NUM_LINKS >= 3 | ||
475 | OMAP_MCBSP_DAI_BUILDER(2), | ||
476 | #endif | ||
477 | #if NUM_LINKS == 5 | ||
478 | OMAP_MCBSP_DAI_BUILDER(3), | ||
479 | OMAP_MCBSP_DAI_BUILDER(4), | ||
480 | #endif | ||
409 | }; | 481 | }; |
482 | |||
410 | EXPORT_SYMBOL_GPL(omap_mcbsp_dai); | 483 | EXPORT_SYMBOL_GPL(omap_mcbsp_dai); |
411 | 484 | ||
412 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); | 485 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); |
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index ed8afb550671..df7ad13ba73d 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h | |||
@@ -38,11 +38,17 @@ enum omap_mcbsp_div { | |||
38 | OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ | 38 | OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /* | 41 | #if defined(CONFIG_ARCH_OMAP2420) |
42 | * REVISIT: Preparation for the ASoC v2. Let the number of available links to | 42 | #define NUM_LINKS 2 |
43 | * be same than number of McBSP ports found in OMAP(s) we are compiling for. | 43 | #endif |
44 | */ | 44 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) |
45 | #define NUM_LINKS 1 | 45 | #undef NUM_LINKS |
46 | #define NUM_LINKS 3 | ||
47 | #endif | ||
48 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) | ||
49 | #undef NUM_LINKS | ||
50 | #define NUM_LINKS 5 | ||
51 | #endif | ||
46 | 52 | ||
47 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; | 53 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; |
48 | 54 | ||
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 690bfeaec4a0..e9084fdd2082 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, | |||
97 | prtd->dma_data = dma_data; | 97 | prtd->dma_data = dma_data; |
98 | err = omap_request_dma(dma_data->dma_req, dma_data->name, | 98 | err = omap_request_dma(dma_data->dma_req, dma_data->name, |
99 | omap_pcm_dma_irq, substream, &prtd->dma_ch); | 99 | omap_pcm_dma_irq, substream, &prtd->dma_ch); |
100 | if (!cpu_is_omap1510()) { | 100 | if (!err & !cpu_is_omap1510()) { |
101 | /* | 101 | /* |
102 | * Link channel with itself so DMA doesn't need any | 102 | * Link channel with itself so DMA doesn't need any |
103 | * reprogramming while looping the buffer | 103 | * reprogramming while looping the buffer |
@@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
147 | dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; | 147 | dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; |
148 | dma_params.src_start = runtime->dma_addr; | 148 | dma_params.src_start = runtime->dma_addr; |
149 | dma_params.dst_start = dma_data->port_addr; | 149 | dma_params.dst_start = dma_data->port_addr; |
150 | dma_params.dst_port = OMAP_DMA_PORT_MPUI; | ||
150 | } else { | 151 | } else { |
151 | dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; | 152 | dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; |
152 | dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; | 153 | dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; |
153 | dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; | 154 | dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; |
154 | dma_params.src_start = dma_data->port_addr; | 155 | dma_params.src_start = dma_data->port_addr; |
155 | dma_params.dst_start = runtime->dma_addr; | 156 | dma_params.dst_start = runtime->dma_addr; |
157 | dma_params.src_port = OMAP_DMA_PORT_MPUI; | ||
156 | } | 158 | } |
157 | /* | 159 | /* |
158 | * Set DMA transfer frame size equal to ALSA period size and frame | 160 | * Set DMA transfer frame size equal to ALSA period size and frame |
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c new file mode 100644 index 000000000000..0fe733796898 --- /dev/null +++ b/sound/soc/omap/osk5912.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * osk5912.c -- SoC audio for OSK 5912 | ||
3 | * | ||
4 | * Copyright (C) 2008 Mistral Solutions | ||
5 | * | ||
6 | * Contact: Arun KS <arunks@mistralsolutions.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | #include <mach/hardware.h> | ||
33 | #include <linux/gpio.h> | ||
34 | #include <mach/mcbsp.h> | ||
35 | |||
36 | #include "omap-mcbsp.h" | ||
37 | #include "omap-pcm.h" | ||
38 | #include "../codecs/tlv320aic23.h" | ||
39 | |||
40 | #define CODEC_CLOCK 12000000 | ||
41 | |||
42 | static struct clk *tlv320aic23_mclk; | ||
43 | |||
44 | static int osk_startup(struct snd_pcm_substream *substream) | ||
45 | { | ||
46 | return clk_enable(tlv320aic23_mclk); | ||
47 | } | ||
48 | |||
49 | static void osk_shutdown(struct snd_pcm_substream *substream) | ||
50 | { | ||
51 | clk_disable(tlv320aic23_mclk); | ||
52 | } | ||
53 | |||
54 | static int osk_hw_params(struct snd_pcm_substream *substream, | ||
55 | struct snd_pcm_hw_params *params) | ||
56 | { | ||
57 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
58 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
59 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
60 | int err; | ||
61 | |||
62 | /* Set codec DAI configuration */ | ||
63 | err = snd_soc_dai_set_fmt(codec_dai, | ||
64 | SND_SOC_DAIFMT_DSP_A | | ||
65 | SND_SOC_DAIFMT_NB_IF | | ||
66 | SND_SOC_DAIFMT_CBM_CFM); | ||
67 | if (err < 0) { | ||
68 | printk(KERN_ERR "can't set codec DAI configuration\n"); | ||
69 | return err; | ||
70 | } | ||
71 | |||
72 | /* Set cpu DAI configuration */ | ||
73 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
74 | SND_SOC_DAIFMT_DSP_A | | ||
75 | SND_SOC_DAIFMT_NB_IF | | ||
76 | SND_SOC_DAIFMT_CBM_CFM); | ||
77 | if (err < 0) { | ||
78 | printk(KERN_ERR "can't set cpu DAI configuration\n"); | ||
79 | return err; | ||
80 | } | ||
81 | |||
82 | /* Set the codec system clock for DAC and ADC */ | ||
83 | err = | ||
84 | snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
85 | |||
86 | if (err < 0) { | ||
87 | printk(KERN_ERR "can't set codec system clock\n"); | ||
88 | return err; | ||
89 | } | ||
90 | |||
91 | return err; | ||
92 | } | ||
93 | |||
94 | static struct snd_soc_ops osk_ops = { | ||
95 | .startup = osk_startup, | ||
96 | .hw_params = osk_hw_params, | ||
97 | .shutdown = osk_shutdown, | ||
98 | }; | ||
99 | |||
100 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
101 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
102 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
103 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
104 | }; | ||
105 | |||
106 | static const struct snd_soc_dapm_route audio_map[] = { | ||
107 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
108 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
109 | |||
110 | {"LLINEIN", NULL, "Line In"}, | ||
111 | {"RLINEIN", NULL, "Line In"}, | ||
112 | |||
113 | {"MICIN", NULL, "Mic Jack"}, | ||
114 | }; | ||
115 | |||
116 | static int osk_tlv320aic23_init(struct snd_soc_codec *codec) | ||
117 | { | ||
118 | |||
119 | /* Add osk5912 specific widgets */ | ||
120 | snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, | ||
121 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | ||
122 | |||
123 | /* Set up osk5912 specific audio path audio_map */ | ||
124 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
125 | |||
126 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
127 | snd_soc_dapm_enable_pin(codec, "Line In"); | ||
128 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
129 | |||
130 | snd_soc_dapm_sync(codec); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
136 | static struct snd_soc_dai_link osk_dai = { | ||
137 | .name = "TLV320AIC23", | ||
138 | .stream_name = "AIC23", | ||
139 | .cpu_dai = &omap_mcbsp_dai[0], | ||
140 | .codec_dai = &tlv320aic23_dai, | ||
141 | .init = osk_tlv320aic23_init, | ||
142 | .ops = &osk_ops, | ||
143 | }; | ||
144 | |||
145 | /* Audio machine driver */ | ||
146 | static struct snd_soc_machine snd_soc_machine_osk = { | ||
147 | .name = "OSK5912", | ||
148 | .dai_link = &osk_dai, | ||
149 | .num_links = 1, | ||
150 | }; | ||
151 | |||
152 | /* Audio subsystem */ | ||
153 | static struct snd_soc_device osk_snd_devdata = { | ||
154 | .machine = &snd_soc_machine_osk, | ||
155 | .platform = &omap_soc_platform, | ||
156 | .codec_dev = &soc_codec_dev_tlv320aic23, | ||
157 | }; | ||
158 | |||
159 | static struct platform_device *osk_snd_device; | ||
160 | |||
161 | static int __init osk_soc_init(void) | ||
162 | { | ||
163 | int err; | ||
164 | u32 curRate; | ||
165 | struct device *dev; | ||
166 | |||
167 | if (!(machine_is_omap_osk())) | ||
168 | return -ENODEV; | ||
169 | |||
170 | osk_snd_device = platform_device_alloc("soc-audio", -1); | ||
171 | if (!osk_snd_device) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | platform_set_drvdata(osk_snd_device, &osk_snd_devdata); | ||
175 | osk_snd_devdata.dev = &osk_snd_device->dev; | ||
176 | *(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */ | ||
177 | err = platform_device_add(osk_snd_device); | ||
178 | if (err) | ||
179 | goto err1; | ||
180 | |||
181 | dev = &osk_snd_device->dev; | ||
182 | |||
183 | tlv320aic23_mclk = clk_get(dev, "mclk"); | ||
184 | if (IS_ERR(tlv320aic23_mclk)) { | ||
185 | printk(KERN_ERR "Could not get mclk clock\n"); | ||
186 | return -ENODEV; | ||
187 | } | ||
188 | |||
189 | if (clk_get_usecount(tlv320aic23_mclk) > 0) { | ||
190 | /* MCLK is already in use */ | ||
191 | printk(KERN_WARNING | ||
192 | "MCLK in use at %d Hz. We change it to %d Hz\n", | ||
193 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Configure 12 MHz output on MCLK. | ||
198 | */ | ||
199 | curRate = (uint) clk_get_rate(tlv320aic23_mclk); | ||
200 | if (curRate != CODEC_CLOCK) { | ||
201 | if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) { | ||
202 | printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n"); | ||
203 | err = -ECANCELED; | ||
204 | goto err1; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n", | ||
209 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK, | ||
210 | clk_get_usecount(tlv320aic23_mclk)); | ||
211 | |||
212 | return 0; | ||
213 | err1: | ||
214 | clk_put(tlv320aic23_mclk); | ||
215 | platform_device_del(osk_snd_device); | ||
216 | platform_device_put(osk_snd_device); | ||
217 | |||
218 | return err; | ||
219 | |||
220 | } | ||
221 | |||
222 | static void __exit osk_soc_exit(void) | ||
223 | { | ||
224 | platform_device_unregister(osk_snd_device); | ||
225 | } | ||
226 | |||
227 | module_init(osk_soc_init); | ||
228 | module_exit(osk_soc_exit); | ||
229 | |||
230 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
231 | MODULE_DESCRIPTION("ALSA SoC OSK 5912"); | ||
232 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 1a8373de7f3a..2718eaf7895f 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
@@ -281,8 +281,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) | |||
281 | { | 281 | { |
282 | int i, err; | 282 | int i, err; |
283 | 283 | ||
284 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); | 284 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
285 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); | 285 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
286 | 286 | ||
287 | /* Add corgi specific controls */ | 287 | /* Add corgi specific controls */ |
288 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { | 288 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { |
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index d9c3f7b28be2..e6ff6929ab4b 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * Copyright 2005 Wolfson Microelectronics PLC. | 9 | * Copyright 2005 Wolfson Microelectronics PLC. |
10 | * Copyright 2005 Openedhand Ltd. | 10 | * Copyright 2005 Openedhand Ltd. |
11 | * | 11 | * |
12 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 12 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
13 | * Richard Purdie <richard@openedhand.com> | 13 | * Richard Purdie <richard@openedhand.com> |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify it | 15 | * This program is free software; you can redistribute it and/or modify it |
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index f84f7d8db09a..4d9930c52789 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
@@ -242,8 +242,8 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) | |||
242 | { | 242 | { |
243 | int i, err; | 243 | int i, err; |
244 | 244 | ||
245 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); | 245 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
246 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); | 246 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
247 | snd_soc_dapm_enable_pin(codec, "MICIN"); | 247 | snd_soc_dapm_enable_pin(codec, "MICIN"); |
248 | 248 | ||
249 | /* Add poodle specific controls */ | 249 | /* Add poodle specific controls */ |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 2fb58298513b..e758034db5c3 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | 6 | * lrg@slimlogic.co.uk |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
@@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init); | |||
405 | module_exit(pxa2xx_i2s_exit); | 405 | module_exit(pxa2xx_i2s_exit); |
406 | 406 | ||
407 | /* Module information */ | 407 | /* Module information */ |
408 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | 408 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); |
409 | MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); | 409 | MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); |
410 | MODULE_LICENSE("GPL"); | 410 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 9a70b00fc30e..d307b6757e95 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
@@ -281,13 +281,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
281 | int i, err; | 281 | int i, err; |
282 | 282 | ||
283 | /* NC codec pins */ | 283 | /* NC codec pins */ |
284 | snd_soc_dapm_disable_pin(codec, "RINPUT1"); | 284 | snd_soc_dapm_nc_pin(codec, "RINPUT1"); |
285 | snd_soc_dapm_disable_pin(codec, "LINPUT2"); | 285 | snd_soc_dapm_nc_pin(codec, "LINPUT2"); |
286 | snd_soc_dapm_disable_pin(codec, "RINPUT2"); | 286 | snd_soc_dapm_nc_pin(codec, "RINPUT2"); |
287 | snd_soc_dapm_disable_pin(codec, "LINPUT3"); | 287 | snd_soc_dapm_nc_pin(codec, "LINPUT3"); |
288 | snd_soc_dapm_disable_pin(codec, "RINPUT3"); | 288 | snd_soc_dapm_nc_pin(codec, "RINPUT3"); |
289 | snd_soc_dapm_disable_pin(codec, "OUT3"); | 289 | snd_soc_dapm_nc_pin(codec, "OUT3"); |
290 | snd_soc_dapm_disable_pin(codec, "MONO1"); | 290 | snd_soc_dapm_nc_pin(codec, "MONO1"); |
291 | 291 | ||
292 | /* Add spitz specific controls */ | 292 | /* Add spitz specific controls */ |
293 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { | 293 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 2baaa750f123..afefe41b8c46 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
@@ -190,8 +190,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) | |||
190 | { | 190 | { |
191 | int i, err; | 191 | int i, err; |
192 | 192 | ||
193 | snd_soc_dapm_disable_pin(codec, "OUT3"); | 193 | snd_soc_dapm_nc_pin(codec, "OUT3"); |
194 | snd_soc_dapm_disable_pin(codec, "MONOOUT"); | 194 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); |
195 | 195 | ||
196 | /* add tosa specific controls */ | 196 | /* add tosa specific controls */ |
197 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { | 197 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 73a50e93a9a2..87ddfefcc2fb 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -511,21 +511,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
511 | DBG("Entered %s\n", __func__); | 511 | DBG("Entered %s\n", __func__); |
512 | 512 | ||
513 | /* set up NC codec pins */ | 513 | /* set up NC codec pins */ |
514 | snd_soc_dapm_disable_pin(codec, "LOUT2"); | 514 | snd_soc_dapm_nc_pin(codec, "LOUT2"); |
515 | snd_soc_dapm_disable_pin(codec, "ROUT2"); | 515 | snd_soc_dapm_nc_pin(codec, "ROUT2"); |
516 | snd_soc_dapm_disable_pin(codec, "OUT3"); | 516 | snd_soc_dapm_nc_pin(codec, "OUT3"); |
517 | snd_soc_dapm_disable_pin(codec, "OUT4"); | 517 | snd_soc_dapm_nc_pin(codec, "OUT4"); |
518 | snd_soc_dapm_disable_pin(codec, "LINE1"); | 518 | snd_soc_dapm_nc_pin(codec, "LINE1"); |
519 | snd_soc_dapm_disable_pin(codec, "LINE2"); | 519 | snd_soc_dapm_nc_pin(codec, "LINE2"); |
520 | |||
521 | |||
522 | /* set endpoints to default mode */ | ||
523 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | ||
524 | 520 | ||
525 | /* Add neo1973 specific widgets */ | 521 | /* Add neo1973 specific widgets */ |
526 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, | 522 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
527 | ARRAY_SIZE(wm8753_dapm_widgets)); | 523 | ARRAY_SIZE(wm8753_dapm_widgets)); |
528 | 524 | ||
525 | /* set endpoints to default mode */ | ||
526 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | ||
527 | |||
529 | /* add neo1973 specific controls */ | 528 | /* add neo1973 specific controls */ |
530 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { | 529 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { |
531 | err = snd_ctl_add(codec->card, | 530 | err = snd_ctl_add(codec->card, |
@@ -603,6 +602,8 @@ static int lm4857_i2c_probe(struct i2c_client *client, | |||
603 | { | 602 | { |
604 | DBG("Entered %s\n", __func__); | 603 | DBG("Entered %s\n", __func__); |
605 | 604 | ||
605 | i2c = client; | ||
606 | |||
606 | lm4857_write_regs(); | 607 | lm4857_write_regs(); |
607 | return 0; | 608 | return 0; |
608 | } | 609 | } |
@@ -611,6 +612,8 @@ static int lm4857_i2c_remove(struct i2c_client *client) | |||
611 | { | 612 | { |
612 | DBG("Entered %s\n", __func__); | 613 | DBG("Entered %s\n", __func__); |
613 | 614 | ||
615 | i2c = NULL; | ||
616 | |||
614 | return 0; | 617 | return 0; |
615 | } | 618 | } |
616 | 619 | ||
@@ -650,7 +653,7 @@ static void lm4857_shutdown(struct i2c_client *dev) | |||
650 | } | 653 | } |
651 | 654 | ||
652 | static const struct i2c_device_id lm4857_i2c_id[] = { | 655 | static const struct i2c_device_id lm4857_i2c_id[] = { |
653 | { "neo1973_lm4857", 0 } | 656 | { "neo1973_lm4857", 0 }, |
654 | { } | 657 | { } |
655 | }; | 658 | }; |
656 | 659 | ||
@@ -668,48 +671,6 @@ static struct i2c_driver lm4857_i2c_driver = { | |||
668 | }; | 671 | }; |
669 | 672 | ||
670 | static struct platform_device *neo1973_snd_device; | 673 | static struct platform_device *neo1973_snd_device; |
671 | static struct i2c_client *lm4857_client; | ||
672 | |||
673 | static int __init neo1973_add_lm4857_device(struct platform_device *pdev, | ||
674 | int i2c_bus, | ||
675 | unsigned short i2c_address) | ||
676 | { | ||
677 | struct i2c_board_info info; | ||
678 | struct i2c_adapter *adapter; | ||
679 | struct i2c_client *client; | ||
680 | int ret; | ||
681 | |||
682 | ret = i2c_add_driver(&lm4857_i2c_driver); | ||
683 | if (ret != 0) { | ||
684 | dev_err(&pdev->dev, "can't add lm4857 driver\n"); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
689 | info.addr = i2c_address; | ||
690 | strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE); | ||
691 | |||
692 | adapter = i2c_get_adapter(i2c_bus); | ||
693 | if (!adapter) { | ||
694 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus); | ||
695 | goto err_driver; | ||
696 | } | ||
697 | |||
698 | client = i2c_new_device(adapter, &info); | ||
699 | i2c_put_adapter(adapter); | ||
700 | if (!client) { | ||
701 | dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n", | ||
702 | (unsigned int)info.addr); | ||
703 | goto err_driver; | ||
704 | } | ||
705 | |||
706 | lm4857_client = client; | ||
707 | return 0; | ||
708 | |||
709 | err_driver: | ||
710 | i2c_del_driver(&lm4857_i2c_driver); | ||
711 | return -ENODEV; | ||
712 | } | ||
713 | 674 | ||
714 | static int __init neo1973_init(void) | 675 | static int __init neo1973_init(void) |
715 | { | 676 | { |
@@ -736,8 +697,8 @@ static int __init neo1973_init(void) | |||
736 | return ret; | 697 | return ret; |
737 | } | 698 | } |
738 | 699 | ||
739 | ret = neo1973_add_lm4857_device(neo1973_snd_device, | 700 | ret = i2c_add_driver(&lm4857_i2c_driver); |
740 | neo1973_wm8753_setup, 0x7C); | 701 | |
741 | if (ret != 0) | 702 | if (ret != 0) |
742 | platform_device_unregister(neo1973_snd_device); | 703 | platform_device_unregister(neo1973_snd_device); |
743 | 704 | ||
@@ -748,7 +709,6 @@ static void __exit neo1973_exit(void) | |||
748 | { | 709 | { |
749 | DBG("Entered %s\n", __func__); | 710 | DBG("Entered %s\n", __func__); |
750 | 711 | ||
751 | i2c_unregister_device(lm4857_client); | ||
752 | i2c_del_driver(&lm4857_i2c_driver); | 712 | i2c_del_driver(&lm4857_i2c_driver); |
753 | platform_device_unregister(neo1973_snd_device); | 713 | platform_device_unregister(neo1973_snd_device); |
754 | } | 714 | } |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ad381138fc2e..462e635dfc74 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -4,8 +4,7 @@ | |||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Author: Liam Girdwood | 7 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
9 | * with code, comments and ideas from :- | 8 | * with code, comments and ideas from :- |
10 | * Richard Purdie <richard@openedhand.com> | 9 | * Richard Purdie <richard@openedhand.com> |
11 | * | 10 | * |
@@ -1886,7 +1885,7 @@ module_init(snd_soc_init); | |||
1886 | module_exit(snd_soc_exit); | 1885 | module_exit(snd_soc_exit); |
1887 | 1886 | ||
1888 | /* Module information */ | 1887 | /* Module information */ |
1889 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | 1888 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); |
1890 | MODULE_DESCRIPTION("ALSA SoC Core"); | 1889 | MODULE_DESCRIPTION("ALSA SoC Core"); |
1891 | MODULE_LICENSE("GPL"); | 1890 | MODULE_LICENSE("GPL"); |
1892 | MODULE_ALIAS("platform:soc-audio"); | 1891 | MODULE_ALIAS("platform:soc-audio"); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9ca9c08610fa..efbd0b37810a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management | 2 | * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
@@ -1484,6 +1483,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) | |||
1484 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | 1483 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); |
1485 | 1484 | ||
1486 | /** | 1485 | /** |
1486 | * snd_soc_dapm_nc_pin - permanently disable pin. | ||
1487 | * @codec: SoC codec | ||
1488 | * @pin: pin name | ||
1489 | * | ||
1490 | * Marks the specified pin as being not connected, disabling it along | ||
1491 | * any parent or child widgets. At present this is identical to | ||
1492 | * snd_soc_dapm_disable_pin() but in future it will be extended to do | ||
1493 | * additional things such as disabling controls which only affect | ||
1494 | * paths through the pin. | ||
1495 | * | ||
1496 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
1497 | * do any widget power switching. | ||
1498 | */ | ||
1499 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin) | ||
1500 | { | ||
1501 | return snd_soc_dapm_set_pin(codec, pin, 0); | ||
1502 | } | ||
1503 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); | ||
1504 | |||
1505 | /** | ||
1487 | * snd_soc_dapm_get_pin_status - get audio pin status | 1506 | * snd_soc_dapm_get_pin_status - get audio pin status |
1488 | * @codec: audio codec | 1507 | * @codec: audio codec |
1489 | * @pin: audio signal pin endpoint (or start point) | 1508 | * @pin: audio signal pin endpoint (or start point) |
@@ -1521,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev) | |||
1521 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 1540 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
1522 | 1541 | ||
1523 | /* Module information */ | 1542 | /* Module information */ |
1524 | MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); | 1543 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); |
1525 | MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); | 1544 | MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); |
1526 | MODULE_LICENSE("GPL"); | 1545 | MODULE_LICENSE("GPL"); |