From d6d55f0b9d900673548515614b56ab55aa2c51f8 Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Thu, 29 May 2014 17:26:50 +0200 Subject: perf/x86/amd: AMD support for bp_len > HW_BREAKPOINT_LEN_8 Implement hardware breakpoint address mask for AMD Family 16h and above processors. CPUID feature bit indicates hardware support for DRn_ADDR_MASK MSRs. These masks further qualify DRn/DR7 hardware breakpoint addresses to allow matching of larger addresses ranges. Valuable advice and pseudo code from Oleg Nesterov Signed-off-by: Jacob Shin Signed-off-by: Suravee Suthikulpanit Acked-by: Jiri Olsa Reviewed-by: Oleg Nesterov Cc: Arnaldo Carvalho de Melo Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: xiakaixu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 0bb1335..53966d6 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -174,6 +174,7 @@ #define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */ #define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ #define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ +#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ #define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */ /* @@ -383,6 +384,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) #define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU) #define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT) +#define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT) #if __GNUC__ >= 4 extern void warn_pre_alternatives(void); diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 61fd18b..12cb66f 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -114,5 +114,10 @@ static inline void debug_stack_usage_inc(void) { } static inline void debug_stack_usage_dec(void) { } #endif /* X86_64 */ +#ifdef CONFIG_CPU_SUP_AMD +extern void set_dr_addr_mask(unsigned long mask, int dr); +#else +static inline void set_dr_addr_mask(unsigned long mask, int dr) { } +#endif #endif /* _ASM_X86_DEBUGREG_H */ diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h index ef1c4d2..6c98be8 100644 --- a/arch/x86/include/asm/hw_breakpoint.h +++ b/arch/x86/include/asm/hw_breakpoint.h @@ -12,6 +12,7 @@ */ struct arch_hw_breakpoint { unsigned long address; + unsigned long mask; u8 len; u8 type; }; diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index 8f02f69..b1fb4fa 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -212,6 +212,10 @@ /* Fam 16h MSRs */ #define MSR_F16H_L2I_PERF_CTL 0xc0010230 #define MSR_F16H_L2I_PERF_CTR 0xc0010231 +#define MSR_F16H_DR1_ADDR_MASK 0xc0011019 +#define MSR_F16H_DR2_ADDR_MASK 0xc001101a +#define MSR_F16H_DR3_ADDR_MASK 0xc001101b +#define MSR_F16H_DR0_ADDR_MASK 0xc0011027 /* Fam 15h MSRs */ #define MSR_F15H_PERF_CTL 0xc0010200 diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 813d29d..abe4ec7 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -870,3 +870,22 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) return false; } + +void set_dr_addr_mask(unsigned long mask, int dr) +{ + if (!cpu_has_bpext) + return; + + switch (dr) { + case 0: + wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0); + break; + case 1: + case 2: + case 3: + wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0); + break; + default: + break; + } +} diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 3d5fb50..b5cb0c5 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp) *dr7 |= encode_dr7(i, info->len, info->type); set_debugreg(*dr7, 7); + if (info->mask) + set_dr_addr_mask(info->mask, i); return 0; } @@ -161,6 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) *dr7 &= ~__encode_dr7(i, info->len, info->type); set_debugreg(*dr7, 7); + if (info->mask) + set_dr_addr_mask(0, i); } static int get_hbp_len(u8 hbp_len) @@ -277,6 +281,8 @@ static int arch_build_bp_info(struct perf_event *bp) } /* Len */ + info->mask = 0; + switch (bp->attr.bp_len) { case HW_BREAKPOINT_LEN_1: info->len = X86_BREAKPOINT_LEN_1; @@ -293,11 +299,17 @@ static int arch_build_bp_info(struct perf_event *bp) break; #endif default: - return -EINVAL; + if (!is_power_of_2(bp->attr.bp_len)) + return -EINVAL; + if (!cpu_has_bpext) + return -EOPNOTSUPP; + info->mask = bp->attr.bp_len - 1; + info->len = X86_BREAKPOINT_LEN_1; } return 0; } + /* * Validate the arch-specific HW Breakpoint register settings */ @@ -312,11 +324,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) if (ret) return ret; - ret = -EINVAL; - switch (info->len) { case X86_BREAKPOINT_LEN_1: align = 0; + if (info->mask) + align = info->mask; break; case X86_BREAKPOINT_LEN_2: align = 1; @@ -330,7 +342,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) break; #endif default: - return ret; + WARN_ON_ONCE(1); } /* -- cgit v0.10.2 From 3741eb9f8c3be3ec59583881c1f49980dad844e0 Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Thu, 29 May 2014 17:26:51 +0200 Subject: perf tools: allow user to specify hardware breakpoint bp_len Currently bp_len is given a default value of 4. Allow user to override it: $ perf stat -e mem:0x1000/8 ^ bp_len If no value is given, it will default to 4 as it did before. Signed-off-by: Jacob Shin Signed-off-by: Suravee Suthikulpanit Acked-by: Jiri Olsa Reviewed-by: Oleg Nesterov Cc: Arnaldo Carvalho de Melo Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: xiakaixu Signed-off-by: Frederic Weisbecker diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index af9a54e..81a20f2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -33,12 +33,15 @@ OPTIONS - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a hexadecimal event descriptor. - - a hardware breakpoint event in the form of '\mem:addr[:access]' + - a hardware breakpoint event in the form of '\mem:addr[/len][:access]' where addr is the address in memory you want to break in. Access is the memory access type (read, write, execute) it can - be passed as follows: '\mem:addr[:[r][w][x]]'. + be passed as follows: '\mem:addr[:[r][w][x]]'. len is the range, + number of bytes from specified addr, which the breakpoint will cover. If you want to profile read-write accesses in 0x1000, just set 'mem:0x1000:rw'. + If you want to profile write accesses in [0x1000~1008), just set + 'mem:0x1000/8:w'. --filter=:: Event filter. diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c659a3c..efa1ff4 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -526,7 +526,7 @@ do { \ } int parse_events_add_breakpoint(struct list_head *list, int *idx, - void *ptr, char *type) + void *ptr, char *type, u64 len) { struct perf_event_attr attr; @@ -536,14 +536,15 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, if (parse_breakpoint_type(type, &attr)) return -EINVAL; - /* - * We should find a nice way to override the access length - * Provide some defaults for now - */ - if (attr.bp_type == HW_BREAKPOINT_X) - attr.bp_len = sizeof(long); - else - attr.bp_len = HW_BREAKPOINT_LEN_4; + /* Provide some defaults if len is not specified */ + if (!len) { + if (attr.bp_type == HW_BREAKPOINT_X) + len = sizeof(long); + else + len = HW_BREAKPOINT_LEN_4; + } + + attr.bp_len = len; attr.type = PERF_TYPE_BREAKPOINT; attr.sample_period = 1; @@ -1364,7 +1365,7 @@ void print_events(const char *event_glob, bool name_only) printf("\n"); printf(" %-50s [%s]\n", - "mem:[:access]", + "mem:[/len][:access]", event_type_descriptors[PERF_TYPE_BREAKPOINT]); printf("\n"); } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index db2cf78..a19fbeb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -104,7 +104,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx, int parse_events_add_cache(struct list_head *list, int *idx, char *type, char *op_result1, char *op_result2); int parse_events_add_breakpoint(struct list_head *list, int *idx, - void *ptr, char *type); + void *ptr, char *type, u64 len); int parse_events_add_pmu(struct list_head *list, int *idx, char *pmu , struct list_head *head_config); enum perf_pmu_event_symbol_type diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 906630b..94eacb6 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -159,6 +159,7 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE { {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } : { return ':'; } +"/" { return '/'; } {num_dec} { return value(yyscanner, 10); } {num_hex} { return value(yyscanner, 16); } /* diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 93c4c9f..72def07 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -326,6 +326,28 @@ PE_NAME_CACHE_TYPE } event_legacy_mem: +PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc +{ + struct parse_events_evlist *data = _data; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_add_breakpoint(list, &data->idx, + (void *) $2, $6, $4)); + $$ = list; +} +| +PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc +{ + struct parse_events_evlist *data = _data; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_add_breakpoint(list, &data->idx, + (void *) $2, NULL, $4)); + $$ = list; +} +| PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc { struct parse_events_evlist *data = _data; @@ -333,7 +355,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc ALLOC_LIST(list); ABORT_ON(parse_events_add_breakpoint(list, &data->idx, - (void *) $2, $4)); + (void *) $2, $4, 0)); $$ = list; } | @@ -344,7 +366,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc ALLOC_LIST(list); ABORT_ON(parse_events_add_breakpoint(list, &data->idx, - (void *) $2, NULL)); + (void *) $2, NULL, 0)); $$ = list; } -- cgit v0.10.2 From ec32398c231a019d39017afee490728ab3b60b92 Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Thu, 29 May 2014 17:26:52 +0200 Subject: perf tools: add hardware breakpoint bp_len test cases Signed-off-by: Jacob Shin Signed-off-by: Suravee Suthikulpanit Acked-by: Jiri Olsa Reviewed-by: Oleg Nesterov Cc: Arnaldo Carvalho de Melo Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: xiakaixu Signed-off-by: Frederic Weisbecker diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7f2f51f..4169f46 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1145,6 +1145,49 @@ static int test__pinned_group(struct perf_evlist *evlist) return 0; } +static int test__checkevent_breakpoint_len(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == + evsel->attr.bp_type); + TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_1 == + evsel->attr.bp_len); + + return 0; +} + +static int test__checkevent_breakpoint_len_w(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); + TEST_ASSERT_VAL("wrong bp_type", HW_BREAKPOINT_W == + evsel->attr.bp_type); + TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_2 == + evsel->attr.bp_len); + + return 0; +} + +static int +test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_breakpoint_rw(evlist); +} + static int count_tracepoints(void) { char events_path[PATH_MAX]; @@ -1420,6 +1463,21 @@ static struct evlist_test test__events[] = { .check = test__pinned_group, .id = 41, }, + { + .name = "mem:0/1", + .check = test__checkevent_breakpoint_len, + .id = 42, + }, + { + .name = "mem:0/2:w", + .check = test__checkevent_breakpoint_len_w, + .id = 43, + }, + { + .name = "mem:0/4:rw:u", + .check = test__checkevent_breakpoint_len_rw_modifier, + .id = 44 + }, #if defined(__s390x__) { .name = "kvm-s390:kvm_s390_create_vm", -- cgit v0.10.2 From 36748b9518a2437beffe861b47dff6d12b736b3f Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Thu, 29 May 2014 17:26:53 +0200 Subject: perf/x86: Remove get_hbp_len and replace with bp_len Clean up the logic for determining the breakpoint length Signed-off-by: Jacob Shin Signed-off-by: Suravee Suthikulpanit Acked-by: Jiri Olsa Reviewed-by: Oleg Nesterov Cc: Arnaldo Carvalho de Melo Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: xiakaixu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index b5cb0c5..7114ba2 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -167,29 +167,6 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) set_dr_addr_mask(0, i); } -static int get_hbp_len(u8 hbp_len) -{ - unsigned int len_in_bytes = 0; - - switch (hbp_len) { - case X86_BREAKPOINT_LEN_1: - len_in_bytes = 1; - break; - case X86_BREAKPOINT_LEN_2: - len_in_bytes = 2; - break; - case X86_BREAKPOINT_LEN_4: - len_in_bytes = 4; - break; -#ifdef CONFIG_X86_64 - case X86_BREAKPOINT_LEN_8: - len_in_bytes = 8; - break; -#endif - } - return len_in_bytes; -} - /* * Check for virtual address in kernel space. */ @@ -200,7 +177,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp) struct arch_hw_breakpoint *info = counter_arch_bp(bp); va = info->address; - len = get_hbp_len(info->len); + len = bp->attr.bp_len; return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); } -- cgit v0.10.2 From 108cc2e7d212c7d52694fb400423da807e1e5fe4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Apr 2013 12:42:50 +0300 Subject: SFI: fix compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/sfi/sfi_core.c:164:26: warning: no previous prototype for ‘sfi_map_table’ [-Wmissing-prototypes] drivers/sfi/sfi_core.c:192:6: warning: no previous prototype for ‘sfi_unmap_table’ [-Wmissing-prototypes] Signed-off-by: Andy Shevchenko Signed-off-by: Len Brown diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index 1e824fb..296db7a 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -161,7 +161,7 @@ static int sfi_verify_table(struct sfi_table_header *table) * Check for common case that we can re-use mapping to SYST, * which requires syst_pa, syst_va to be initialized. */ -struct sfi_table_header *sfi_map_table(u64 pa) +static struct sfi_table_header *sfi_map_table(u64 pa) { struct sfi_table_header *th; u32 length; @@ -189,7 +189,7 @@ struct sfi_table_header *sfi_map_table(u64 pa) * Undoes effect of sfi_map_table() by unmapping table * if it did not completely fit on same page as SYST. */ -void sfi_unmap_table(struct sfi_table_header *th) +static void sfi_unmap_table(struct sfi_table_header *th) { if (!TABLE_ON_PAGE(syst_va, th, th->len)) sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ? -- cgit v0.10.2 From 5cb2f03c67265922c66e20270d4fd669a661da82 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Dec 2014 21:19:51 +0800 Subject: regulator: rk808: Fix sparse non static symbol warnings Fixes the following sparse warnings: drivers/regulator/rk808-regulator.c:100:5: warning: symbol 'rk808_set_suspend_voltage' was not declared. Should it be static? drivers/regulator/rk808-regulator.c:115:5: warning: symbol 'rk808_set_suspend_enable' was not declared. Should it be static? drivers/regulator/rk808-regulator.c:126:5: warning: symbol 'rk808_set_suspend_disable' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 8d1dc48..33042eb 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -97,7 +97,7 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) RK808_RAMP_RATE_MASK, ramp_value); } -int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) +static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) { unsigned int reg; int sel = regulator_map_voltage_linear_range(rdev, uv, uv); @@ -112,7 +112,7 @@ int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) sel); } -int rk808_set_suspend_enable(struct regulator_dev *rdev) +static int rk808_set_suspend_enable(struct regulator_dev *rdev) { unsigned int reg; @@ -123,7 +123,7 @@ int rk808_set_suspend_enable(struct regulator_dev *rdev) 0); } -int rk808_set_suspend_disable(struct regulator_dev *rdev) +static int rk808_set_suspend_disable(struct regulator_dev *rdev) { unsigned int reg; -- cgit v0.10.2 From 5424d43e4daddf71aaa60d6565c8816af9150adf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2014 17:40:53 +0000 Subject: spi: Move queue data structure initialisation to main master init Since most devices now do use the standard queue and in order to avoid initialisation ordering issues being introduced by further refactorings to improve performance move the initialisation of the queue and the lock for it to the main master allocation. Signed-off-by: Mark Brown diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index da7e622..b81ccdb 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -989,9 +989,6 @@ static int spi_init_queue(struct spi_master *master) { struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; - INIT_LIST_HEAD(&master->queue); - spin_lock_init(&master->queue_lock); - master->running = false; master->busy = false; @@ -1595,6 +1592,8 @@ int spi_register_master(struct spi_master *master) dynamic = 1; } + INIT_LIST_HEAD(&master->queue); + spin_lock_init(&master->queue_lock); spin_lock_init(&master->bus_lock_spinlock); mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; -- cgit v0.10.2 From 983aee5d7090cf12b624f18533777caa09d067b1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2014 19:46:56 +0000 Subject: spi: Check to see if the device is processing a message before we idle cur_msg is updated under the queue lock and holds the message we are currently processing. Since currently we only ever do removals in the pump kthread it doesn't matter in what order we do things but we want to be able to push things out from the submitting thread so pull the check to see if we're currently handling a message before we check to see if the queue is idle. Signed-off-by: Mark Brown diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b81ccdb..0bc752d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -891,8 +891,16 @@ static void spi_pump_messages(struct kthread_work *work) bool was_busy = false; int ret; - /* Lock queue and check for queue work */ + /* Lock queue */ spin_lock_irqsave(&master->queue_lock, flags); + + /* Make sure we are not already running a message */ + if (master->cur_msg) { + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + + /* Check if the queue is idle */ if (list_empty(&master->queue) || !master->running) { if (!master->busy) { spin_unlock_irqrestore(&master->queue_lock, flags); @@ -916,11 +924,6 @@ static void spi_pump_messages(struct kthread_work *work) return; } - /* Make sure we are not already running a message */ - if (master->cur_msg) { - spin_unlock_irqrestore(&master->queue_lock, flags); - return; - } /* Extract head of queue */ master->cur_msg = list_first_entry(&master->queue, struct spi_message, queue); -- cgit v0.10.2 From 0461a4149836c792d186027c8c859637a4cfb11a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2014 21:38:05 +0000 Subject: spi: Pump transfers inside calling context for spi_sync() If we are using the standard SPI message pump (which all drivers should be transitioning over to) then special case the message enqueue and instead of starting the worker thread to push messages to the hardware do so in the context of the caller if the controller is idle. This avoids a context switch in the common case where the controller has a single user in a single thread, for short PIO transfers there may be no need to context switch away from the calling context to complete the transfer. The code is a bit more complex than is desirable in part due to the need to handle drivers not using the standard queue and in part due to handling the various combinations of bus locking and asynchronous submission in interrupt context. It is still suboptimal since it will still wake the message pump for each transfer in order to schedule idling of the hardware and if multiple contexts are using the controller simultaneously a caller may end up pumping a message for some random other thread rather than for itself, and if the thread ends up deferring due to another context idling the hardware then it will just busy wait. It can, however, have the benefit of aggregating power up and down of the hardware when a caller performs a series of transfers back to back without any need for the use of spi_async(). Signed-off-by: Mark Brown diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 0bc752d..e1bf257 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -882,6 +882,9 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); * needs processing and if so call out to the driver to initialize hardware * and transfer each message. * + * Note that it is called both from the kthread itself and also from + * inside spi_sync(); the queue extraction handling at the top of the + * function should deal with this safely. */ static void spi_pump_messages(struct kthread_work *work) { @@ -900,6 +903,13 @@ static void spi_pump_messages(struct kthread_work *work) return; } + /* If another context is idling the device then defer */ + if (master->idling) { + queue_kthread_work(&master->kworker, &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + /* Check if the queue is idle */ if (list_empty(&master->queue) || !master->running) { if (!master->busy) { @@ -907,7 +917,9 @@ static void spi_pump_messages(struct kthread_work *work) return; } master->busy = false; + master->idling = true; spin_unlock_irqrestore(&master->queue_lock, flags); + kfree(master->dummy_rx); master->dummy_rx = NULL; kfree(master->dummy_tx); @@ -921,6 +933,10 @@ static void spi_pump_messages(struct kthread_work *work) pm_runtime_put_autosuspend(master->dev.parent); } trace_spi_master_idle(master); + + spin_lock_irqsave(&master->queue_lock, flags); + master->idling = false; + spin_unlock_irqrestore(&master->queue_lock, flags); return; } @@ -1161,12 +1177,9 @@ static int spi_destroy_queue(struct spi_master *master) return 0; } -/** - * spi_queued_transfer - transfer function for queued transfers - * @spi: spi device which is requesting transfer - * @msg: spi message which is to handled is queued to driver queue - */ -static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) +static int __spi_queued_transfer(struct spi_device *spi, + struct spi_message *msg, + bool need_pump) { struct spi_master *master = spi->master; unsigned long flags; @@ -1181,13 +1194,23 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) msg->status = -EINPROGRESS; list_add_tail(&msg->queue, &master->queue); - if (!master->busy) + if (!master->busy && need_pump) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); return 0; } +/** + * spi_queued_transfer - transfer function for queued transfers + * @spi: spi device which is requesting transfer + * @msg: spi message which is to handled is queued to driver queue + */ +static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) +{ + return __spi_queued_transfer(spi, msg, true); +} + static int spi_master_initialize_queue(struct spi_master *master) { int ret; @@ -2102,19 +2125,46 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, DECLARE_COMPLETION_ONSTACK(done); int status; struct spi_master *master = spi->master; + unsigned long flags; + + status = __spi_validate(spi, message); + if (status != 0) + return status; message->complete = spi_complete; message->context = &done; + message->spi = spi; if (!bus_locked) mutex_lock(&master->bus_lock_mutex); - status = spi_async_locked(spi, message); + /* If we're not using the legacy transfer method then we will + * try to transfer in the calling context so special case. + * This code would be less tricky if we could remove the + * support for driver implemented message queues. + */ + if (master->transfer == spi_queued_transfer) { + spin_lock_irqsave(&master->bus_lock_spinlock, flags); + + trace_spi_message_submit(message); + + status = __spi_queued_transfer(spi, message, false); + + spin_unlock_irqrestore(&master->bus_lock_spinlock, flags); + } else { + status = spi_async_locked(spi, message); + } if (!bus_locked) mutex_unlock(&master->bus_lock_mutex); if (status == 0) { + /* Push out the messages in the calling context if we + * can. + */ + if (master->transfer == spi_queued_transfer) + spi_pump_messages(&master->pump_messages); + wait_for_completion(&done); status = message->status; } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index a6ef2a8..4e6db75 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -260,6 +260,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @pump_messages: work struct for scheduling work to the message pump * @queue_lock: spinlock to syncronise access to message queue * @queue: message queue + * @idling: the device is entering idle state * @cur_msg: the currently in-flight message * @cur_msg_prepared: spi_prepare_message was called for the currently * in-flight message @@ -425,6 +426,7 @@ struct spi_master { spinlock_t queue_lock; struct list_head queue; struct spi_message *cur_msg; + bool idling; bool busy; bool running; bool rt; -- cgit v0.10.2 From fc9e0f71f2d7ea43fa3ba0bea68586d1462cb5a7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2014 13:46:33 +0000 Subject: spi: Only idle the message pump in the worker kthread In order to avoid the situation where the kthread is waiting for another context to make the hardware idle let the message pump know if it's being called from the worker thread context and if it isn't then defer to the worker thread instead of idling the hardware immediately. This will ensure that if this situation happens we block rather than busy waiting. Signed-off-by: Mark Brown diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e1bf257..3ac188f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -875,8 +875,9 @@ void spi_finalize_current_transfer(struct spi_master *master) EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); /** - * spi_pump_messages - kthread work function which processes spi message queue - * @work: pointer to kthread work struct contained in the master struct + * __spi_pump_messages - function which processes spi message queue + * @master: master to process queue for + * @in_kthread: true if we are in the context of the message pump thread * * This function checks if there is any spi message in the queue that * needs processing and if so call out to the driver to initialize hardware @@ -886,10 +887,8 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); * inside spi_sync(); the queue extraction handling at the top of the * function should deal with this safely. */ -static void spi_pump_messages(struct kthread_work *work) +static void __spi_pump_messages(struct spi_master *master, bool in_kthread) { - struct spi_master *master = - container_of(work, struct spi_master, pump_messages); unsigned long flags; bool was_busy = false; int ret; @@ -916,6 +915,15 @@ static void spi_pump_messages(struct kthread_work *work) spin_unlock_irqrestore(&master->queue_lock, flags); return; } + + /* Only do teardown in the thread */ + if (!in_kthread) { + queue_kthread_work(&master->kworker, + &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + master->busy = false; master->idling = true; spin_unlock_irqrestore(&master->queue_lock, flags); @@ -1004,6 +1012,18 @@ static void spi_pump_messages(struct kthread_work *work) } } +/** + * spi_pump_messages - kthread work function which processes spi message queue + * @work: pointer to kthread work struct contained in the master struct + */ +static void spi_pump_messages(struct kthread_work *work) +{ + struct spi_master *master = + container_of(work, struct spi_master, pump_messages); + + __spi_pump_messages(master, true); +} + static int spi_init_queue(struct spi_master *master) { struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; @@ -2163,7 +2183,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, * can. */ if (master->transfer == spi_queued_transfer) - spi_pump_messages(&master->pump_messages); + __spi_pump_messages(master, false); wait_for_completion(&done); status = message->status; -- cgit v0.10.2 From 7f6d62a2adc6c3a8eb7bbdceea2630634eb2d535 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2014 22:18:03 +0000 Subject: spi/falcon: Remove hardware prepare and unprepare functions They are completely empty and therefore serve no function. Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index f73b300..973ded3 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -353,16 +353,6 @@ static int falcon_sflash_setup(struct spi_device *spi) return 0; } -static int falcon_sflash_prepare_xfer(struct spi_master *master) -{ - return 0; -} - -static int falcon_sflash_unprepare_xfer(struct spi_master *master) -{ - return 0; -} - static int falcon_sflash_xfer_one(struct spi_master *master, struct spi_message *m) { @@ -420,9 +410,7 @@ static int falcon_sflash_probe(struct platform_device *pdev) master->mode_bits = SPI_MODE_3; master->flags = SPI_MASTER_HALF_DUPLEX; master->setup = falcon_sflash_setup; - master->prepare_transfer_hardware = falcon_sflash_prepare_xfer; master->transfer_one_message = falcon_sflash_xfer_one; - master->unprepare_transfer_hardware = falcon_sflash_unprepare_xfer; master->dev.of_node = pdev->dev.of_node; ret = devm_spi_register_master(&pdev->dev, master); -- cgit v0.10.2 From 5ede19c58a1ec274b28e03a76b855c3c55ab6f11 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 8 Dec 2014 11:23:11 +0100 Subject: ASoC: wm8750: Make VREF a VMID instead of OUTPUT widget Commit 04489eeb02a4 ("ALSA: wm8750: add missing VREF output") added the previously missing VREF widget. And while adding the widget as OUTPUT widget silences the error of the missing widget it should have rather been a VMID widget. The VREF widget is only used internally as a source for the VREF input of the Out3 Mux. Selecting that input means that the path should be kept powered up at the VREF/VMID voltage, but that there is no actual audio signal. Using a VMID widget will do this, whereas using a OUTPUT widget will simply cause the path to completely power down. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 67653a2..d9e2626 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -323,7 +323,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("ROUT2"), SND_SOC_DAPM_OUTPUT("MONO1"), SND_SOC_DAPM_OUTPUT("OUT3"), - SND_SOC_DAPM_OUTPUT("VREF"), + SND_SOC_DAPM_VMID("VREF"), SND_SOC_DAPM_INPUT("LINPUT1"), SND_SOC_DAPM_INPUT("LINPUT2"), -- cgit v0.10.2 From f93d1be217d89f258f0108a8cd64b98cb8fa9e73 Mon Sep 17 00:00:00 2001 From: "Wang, Yalin" Date: Mon, 15 Dec 2014 16:05:50 +0800 Subject: regmap: Move spinlock_flags into the union This patch move struct regmap.spinlock_flags into the union of spinlock, so that we can shrink struct regmap size. Signed-off-by: Yalin Wang Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 0da5865..8e94584 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -51,9 +51,11 @@ struct regmap_async { struct regmap { union { struct mutex mutex; - spinlock_t spinlock; + struct { + spinlock_t spinlock; + unsigned long spinlock_flags; + }; }; - unsigned long spinlock_flags; regmap_lock lock; regmap_unlock unlock; void *lock_arg; /* This is passed to lock/unlock functions */ -- cgit v0.10.2 From d91525eb8ee6a622ce476955fe1a2530ade87c83 Mon Sep 17 00:00:00 2001 From: "Chen, Gong" Date: Wed, 10 Dec 2014 13:53:26 -0800 Subject: ACPI, EINJ: Enhance error injection tolerance level Some BIOSes utilize PCI MMCFG space read/write opertion to trigger specific errors. EINJ will report errors as below when hitting such cases: APEI: Can not request [mem 0x83f990a0-0x83f990a3] for APEI EINJ Trigger registers It is because on x86 platform ACPI based PCI MMCFG logic has reserved all MMCFG spaces so that EINJ can't reserve it again. We already trust the ACPI/APEI code when using the EINJ interface so it is not a big leap to also trust it to access the right MMCFG addresses. Skip address checking to allow the access. Signed-off-by: Chen, Gong Signed-off-by: Tony Luck diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 326198a..676e5e0 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -610,6 +610,32 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) return 0; } +#ifdef CONFIG_ACPI_APEI +extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size, + void *data), void *data); + +static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size, + void *data), void *data) +{ + struct pci_mmcfg_region *cfg; + int rc; + + if (list_empty(&pci_mmcfg_list)) + return 0; + + list_for_each_entry(cfg, &pci_mmcfg_list, list) { + rc = func(cfg->res.start, resource_size(&cfg->res), data); + if (rc) + return rc; + } + + return 0; +} +#define set_apei_filter() (arch_apei_filter_addr = pci_mmcfg_for_each_region) +#else +#define set_apei_filter() +#endif + static void __init __pci_mmcfg_init(int early) { pci_mmcfg_reject_broken(early); @@ -644,6 +670,8 @@ void __init pci_mmcfg_early_init(void) else acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); __pci_mmcfg_init(1); + + set_apei_filter(); } } diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 2cd7bdd..a85ac07 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -449,7 +449,7 @@ int apei_resources_sub(struct apei_resources *resources1, } EXPORT_SYMBOL_GPL(apei_resources_sub); -static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) +static int apei_get_res_callback(__u64 start, __u64 size, void *data) { struct apei_resources *resources = data; return apei_res_add(&resources->iomem, start, size); @@ -457,7 +457,15 @@ static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) static int apei_get_nvs_resources(struct apei_resources *resources) { - return acpi_nvs_for_each_region(apei_get_nvs_callback, resources); + return acpi_nvs_for_each_region(apei_get_res_callback, resources); +} + +int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size, + void *data), void *data); +static int apei_get_arch_resources(struct apei_resources *resources) + +{ + return arch_apei_filter_addr(apei_get_res_callback, resources); } /* @@ -470,7 +478,7 @@ int apei_resources_request(struct apei_resources *resources, { struct apei_res *res, *res_bak = NULL; struct resource *r; - struct apei_resources nvs_resources; + struct apei_resources nvs_resources, arch_res; int rc; rc = apei_resources_sub(resources, &apei_resources_all); @@ -485,10 +493,20 @@ int apei_resources_request(struct apei_resources *resources, apei_resources_init(&nvs_resources); rc = apei_get_nvs_resources(&nvs_resources); if (rc) - goto res_fini; + goto nvs_res_fini; rc = apei_resources_sub(resources, &nvs_resources); if (rc) - goto res_fini; + goto nvs_res_fini; + + if (arch_apei_filter_addr) { + apei_resources_init(&arch_res); + rc = apei_get_arch_resources(&arch_res); + if (rc) + goto arch_res_fini; + rc = apei_resources_sub(resources, &arch_res); + if (rc) + goto arch_res_fini; + } rc = -EINVAL; list_for_each_entry(res, &resources->iomem, list) { @@ -536,7 +554,9 @@ err_unmap_iomem: break; release_mem_region(res->start, res->end - res->start); } -res_fini: +arch_res_fini: + apei_resources_fini(&arch_res); +nvs_res_fini: apei_resources_fini(&nvs_resources); return rc; } -- cgit v0.10.2 From e529fea919872c6568bbda7873c64ac5d807ee83 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 17 Dec 2014 00:23:51 +0100 Subject: HID: logitech-hidpp: separate HID++ from WTP processing Previously wtp_raw_event would be called through hidpp_raw_hidpp_event (for the touchpad report) and hidpp_raw_event (for the mouse report). This patch removes one calling surface, making a clearer distinction between "generic HID++ processing" (matching internal reports) and device-specific event processing. Suggested-by: Benjamin Tissoires Signed-off-by: Peter Wu Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 2f420c0..6a5fe97 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -924,7 +924,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, /* * If the mutex is locked then we have a pending answer from a - * previoulsly sent command + * previously sent command. */ if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { /* @@ -955,9 +955,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, return 1; } - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) - return wtp_raw_event(hidpp->hid_dev, data, size); - return 0; } @@ -965,7 +962,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); + int ret = 0; + /* Generic HID++ processing. */ switch (data[0]) { case REPORT_ID_HIDPP_LONG: if (size != HIDPP_REPORT_LONG_LENGTH) { @@ -973,16 +972,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, size); return 1; } - return hidpp_raw_hidpp_event(hidpp, data, size); + ret = hidpp_raw_hidpp_event(hidpp, data, size); + break; case REPORT_ID_HIDPP_SHORT: if (size != HIDPP_REPORT_SHORT_LENGTH) { hid_err(hdev, "received hid++ report of bad size (%d)", size); return 1; } - return hidpp_raw_hidpp_event(hidpp, data, size); + ret = hidpp_raw_hidpp_event(hidpp, data, size); + break; } + /* If no report is available for further processing, skip calling + * raw_event of subclasses. */ + if (ret != 0) + return ret; + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) return wtp_raw_event(hdev, data, size); -- cgit v0.10.2 From e3cb0acd23258cf5e1a7ea270c98805eff01dcc5 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Tue, 16 Dec 2014 21:26:45 +0000 Subject: HID: lenovo: Add sensitivity control to compact keyboards The trackpoint sensitivity can also be controlled, expose this via sysfs. Signed-off-by: Jamie Lentin Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 4c55f4d..0f35a76 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd { struct lenovo_drvdata_cptkbd { bool fn_lock; + int sensitivity; }; #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) @@ -145,6 +146,7 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev) struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); + ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); if (ret) hid_err(hdev, "Fn-lock setting failed: %d\n", ret); } @@ -179,13 +181,50 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, return count; } +static ssize_t attr_sensitivity_show_cptkbd(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + cptkbd_data->sensitivity); +} + +static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + int value; + + if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) + return -EINVAL; + + cptkbd_data->sensitivity = value; + lenovo_features_set_cptkbd(hdev); + + return count; +} + + static struct device_attribute dev_attr_fn_lock_cptkbd = __ATTR(fn_lock, S_IWUSR | S_IRUGO, attr_fn_lock_show_cptkbd, attr_fn_lock_store_cptkbd); +static struct device_attribute dev_attr_sensitivity_cptkbd = + __ATTR(sensitivity, S_IWUSR | S_IRUGO, + attr_sensitivity_show_cptkbd, + attr_sensitivity_store_cptkbd); + + static struct attribute *lenovo_attributes_cptkbd[] = { &dev_attr_fn_lock_cptkbd.attr, + &dev_attr_sensitivity_cptkbd.attr, NULL }; @@ -594,8 +633,9 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) if (ret) hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); - /* Turn Fn-Lock on by default */ + /* Set keyboard settings to known state */ cptkbd_data->fn_lock = true; + cptkbd_data->sensitivity = 0x05; lenovo_features_set_cptkbd(hdev); ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); -- cgit v0.10.2 From 94eefa27132358434735060c6bbdf61c669bb0ab Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Tue, 16 Dec 2014 21:26:46 +0000 Subject: HID: lenovo: Use native middle-button mode for compact keyboards By default the middle button is in a compatibility mode, and generates standard wheel events when dragging with the middle trackpoint button. Unfortunately this is buggy: * The middle button comes up before starting wheel events, causing a middle click on whatever the mouse cursor was sitting on * The USB keyboard always generates the "native" horizontal wheel event, regardless of mode. Instead, enable the "native" mode the Windows driver uses, and add support for the custom events this generates. This fixes the USB keyboard wheel events, and the middle-click up event comes after the wheel events. Signed-off-by: Jamie Lentin Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 0f35a76..c4c3f09 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -92,6 +92,38 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, case 0x00fa: /* Fn-Esc: Fn-lock toggle */ map_key_clear(KEY_FN_ESC); return 1; + case 0x00fb: /* Middle mouse button (in native mode) */ + map_key_clear(BTN_MIDDLE); + return 1; + } + } + + /* Compatibility middle/wheel mappings should be ignored */ + if (usage->hid == HID_GD_WHEEL) + return -1; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON && + (usage->hid & HID_USAGE) == 0x003) + return -1; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER && + (usage->hid & HID_USAGE) == 0x238) + return -1; + + /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */ + if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 || + (usage->hid & HID_USAGE_PAGE) == 0xffa10000) { + field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE; + field->logical_minimum = -127; + field->logical_maximum = 127; + + switch (usage->hid & HID_USAGE) { + case 0x0000: + hid_map_usage(hi, usage, bit, max, EV_REL, 0x06); + return 1; + case 0x0001: + hid_map_usage(hi, usage, bit, max, EV_REL, 0x08); + return 1; + default: + return -1; } } @@ -633,6 +665,11 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) if (ret) hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); + /* Switch middle button to native mode */ + ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01); + if (ret) + hid_warn(hdev, "Failed to switch middle button: %d\n", ret); + /* Set keyboard settings to known state */ cptkbd_data->fn_lock = true; cptkbd_data->sensitivity = 0x05; -- cgit v0.10.2 From bf159447537ed234afb569f91f5fd8c54ffa4c36 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 16 Dec 2014 17:06:01 -0500 Subject: HID: logitech-hidpp: bail out if wtp_connect fails If wtp_connect() fails, that means most of the time that the device has been disconnected. Subsequent attempts to contact the device will fail too, so it's simpler to bail out earlier. Signed-off-by: Benjamin Tissoires Reviewed-by: Peter Wu Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 6a5fe97..e1f3aca 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -862,24 +862,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id) return 0; }; -static void wtp_connect(struct hid_device *hdev, bool connected) +static int wtp_connect(struct hid_device *hdev, bool connected) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct wtp_data *wd = hidpp->private_data; int ret; if (!connected) - return; + return 0; if (!wd->x_size) { ret = wtp_get_config(hidpp); if (ret) { hid_err(hdev, "Can not get wtp config: %d\n", ret); - return; + return ret; } } - hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, + return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, true, true); } @@ -1063,8 +1063,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) struct input_dev *input; char *name, *devm_name; - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) - wtp_connect(hdev, connected); + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { + ret = wtp_connect(hdev, connected); + if (ret) + return; + } if (!connected || hidpp->delayed_input) return; -- cgit v0.10.2 From e39f2d5956999c05c85814787a113ffadbcd4b26 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Fri, 12 Dec 2014 10:17:26 -0800 Subject: HID: rmi: Scan the report descriptor to determine if the device is suitable for the hid-rmi driver On composite HID devices there may be multiple HID devices on separate interfaces, but hid-rmi should only bind to the touchpad. The previous version simply checked that the interface protocol was set to mouse. Unfortuately, it is not always the case that the touchpad has the mouse interface protocol set. This patch takes a different approach and scans the report descriptor looking for the Generic Desktop Pointer usage and the Vendor Specific Top Level Collection needed by the hid-rmi driver to interface with the device. Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d0ac1..81665b4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -698,6 +698,7 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) static void hid_scan_collection(struct hid_parser *parser, unsigned type) { struct hid_device *hid = parser->device; + int i; if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && type == HID_COLLECTION_PHYSICAL) @@ -707,6 +708,14 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; + + if ((parser->global.usage_page << 16) == HID_UP_GENDESK) + for (i = 0; i < parser->local.usage_index; i++) + if (parser->local.usage[i] == HID_GD_POINTER) + parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER; + + if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR) + parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC; } static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) @@ -792,11 +801,14 @@ static int hid_scan_report(struct hid_device *hid) hid->group = HID_GROUP_WACOM; break; case USB_VENDOR_ID_SYNAPTICS: - if ((hid->group == HID_GROUP_GENERIC) && - (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE)) - /* hid-rmi should only bind to the mouse interface of - * composite USB devices */ - hid->group = HID_GROUP_RMI; + if (hid->group == HID_GROUP_GENERIC) + if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC) + && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER)) + /* + * hid-rmi should take care of them, + * not hid-generic + */ + hid->group = HID_GROUP_RMI; break; } diff --git a/include/linux/hid.h b/include/linux/hid.h index 06c4607..efc7787 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -574,7 +574,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data) #define HID_GLOBAL_STACK_SIZE 4 #define HID_COLLECTION_STACK_SIZE 4 -#define HID_SCAN_FLAG_MT_WIN_8 0x00000001 +#define HID_SCAN_FLAG_MT_WIN_8 BIT(0) +#define HID_SCAN_FLAG_VENDOR_SPECIFIC BIT(1) +#define HID_SCAN_FLAG_GD_POINTER BIT(2) struct hid_parser { struct hid_global global; -- cgit v0.10.2 From b1ac9487c824a212f3b5bb80df5ac578243b0e21 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 11 Dec 2014 17:39:59 -0500 Subject: HID: logitech-hidpp: prefix the name with "Logitech" Current names are reported as "K750", "M705", and it can be misleading for the users when they look at their input device list. Prefixing the names with "Logitech " makes things better. Signed-off-by: Benjamin Tissoires Reviewed-by: Peter Wu Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index e1f3aca..7efbd8b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -282,6 +282,33 @@ static inline bool hidpp_report_is_connect_event(struct hidpp_report *report) (report->rap.sub_id == 0x41); } +/** + * hidpp_prefix_name() prefixes the current given name with "Logitech ". + */ +static void hidpp_prefix_name(char **name, int name_length) +{ +#define PREFIX_LENGTH 9 /* "Logitech " */ + + int new_length; + char *new_name; + + if (name_length > PREFIX_LENGTH && + strncmp(*name, "Logitech ", PREFIX_LENGTH) == 0) + /* The prefix has is already in the name */ + return; + + new_length = PREFIX_LENGTH + name_length; + new_name = kzalloc(new_length, GFP_KERNEL); + if (!new_name) + return; + + snprintf(new_name, new_length, "Logitech %s", *name); + + kfree(*name); + + *name = new_name; +} + /* -------------------------------------------------------------------------- */ /* HIDP++ 1.0 commands */ /* -------------------------------------------------------------------------- */ @@ -321,6 +348,10 @@ static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev) return NULL; memcpy(name, &response.rap.params[2], len); + + /* include the terminating '\0' */ + hidpp_prefix_name(&name, len + 1); + return name; } @@ -498,6 +529,9 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp) index += ret; } + /* include the terminating '\0' */ + hidpp_prefix_name(&name, __name_length + 1); + return name; } -- cgit v0.10.2 From f677bb150c2f7b96ebcd377cd722e9d2649e9400 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Tue, 16 Dec 2014 01:50:14 +0100 Subject: HID: logitech-hidpp: detect HID++ 2.0 errors too Devices speaking HID++ 2.0 report a different error code (0xff). Detect these errors too to avoid 5 second delays when the device reports an error. Caught by... well, a bug in the QEMU emulation of this receiver. Renamed fap to rap for HID++ 1.0 errors because it is more logical, it has no functional difference. Signed-off-by: Peter Wu Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 7efbd8b..cf57955 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -105,6 +105,7 @@ struct hidpp_device { }; +/* HID++ 1.0 error codes */ #define HIDPP_ERROR 0x8f #define HIDPP_ERROR_SUCCESS 0x00 #define HIDPP_ERROR_INVALID_SUBID 0x01 @@ -119,6 +120,8 @@ struct hidpp_device { #define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c +/* HID++ 2.0 error codes */ +#define HIDPP20_ERROR 0xff static void hidpp_connect_event(struct hidpp_device *hidpp_dev); @@ -192,9 +195,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, } if (response->report_id == REPORT_ID_HIDPP_SHORT && - response->fap.feature_index == HIDPP_ERROR) { + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); + goto exit; + } + + if (response->report_id == REPORT_ID_HIDPP_LONG && + response->fap.feature_index == HIDPP20_ERROR) { ret = response->fap.params[1]; - dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret); + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); goto exit; } @@ -271,7 +281,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question, static inline bool hidpp_match_error(struct hidpp_report *question, struct hidpp_report *answer) { - return (answer->fap.feature_index == HIDPP_ERROR) && + return ((answer->rap.sub_id == HIDPP_ERROR) || + (answer->fap.feature_index == HIDPP20_ERROR)) && (answer->fap.funcindex_clientid == question->fap.feature_index) && (answer->fap.params[0] == question->fap.funcindex_clientid); } -- cgit v0.10.2 From e7ddf4b7b3c5fe64902c4fb9edac92532c87cd75 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Fri, 19 Dec 2014 23:13:51 +0530 Subject: cpufreq: Add SFI based cpufreq driver support This adds the SFI based cpu freq driver for some of the Intel's Silvermont based Atom architectures like Z34xx and Z35xx. Signed-off-by: Rudramuni, Vishwesh M Signed-off-by: Srinidhi Kasagar Acked-by: Viresh Kumar Signed-off-by: Len Brown diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index e21331ce..4f6dae6 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -318,6 +318,7 @@ #define MSR_IA32_PERF_STATUS 0x00000198 #define MSR_IA32_PERF_CTL 0x00000199 +#define INTEL_PERF_CTL_MASK 0xffff #define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 #define MSR_AMD_PERF_STATUS 0xc0010063 #define MSR_AMD_PERF_CTL 0xc0010062 diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 89ae88f..c59bdcb 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB By enabling this option the acpi_cpufreq driver provides the old entry in addition to the new boost ones, for compatibility reasons. +config X86_SFI_CPUFREQ + tristate "SFI Performance-States driver" + depends on X86_INTEL_MID && SFI + help + This adds a CPUFreq driver for some Silvermont based Intel Atom + architectures like Z34xx and Z35xx which enumerate processor + performance states through SFI. + + If in doubt, say N. + config ELAN_CPUFREQ tristate "AMD Elan SC400 and SC410" depends on MELAN diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 40c53dc..2e50f55 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o +obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o ################################################################################## # ARM SoC drivers diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c new file mode 100644 index 0000000..ffa3389 --- /dev/null +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -0,0 +1,136 @@ +/* + * SFI Performance States Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Author: Vishwesh M Rudramuni + * Author: Srinidhi Kasagar + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cpufreq_frequency_table *freq_table; +static struct sfi_freq_table_entry *sfi_cpufreq_array; +static int num_freq_table_entries; + +static int sfi_parse_freq(struct sfi_table_header *table) +{ + struct sfi_table_simple *sb; + struct sfi_freq_table_entry *pentry; + int totallen; + + sb = (struct sfi_table_simple *)table; + num_freq_table_entries = SFI_GET_NUM_ENTRIES(sb, + struct sfi_freq_table_entry); + if (num_freq_table_entries <= 1) { + pr_err("No p-states discovered\n"); + return -ENODEV; + } + + pentry = (struct sfi_freq_table_entry *)sb->pentry; + totallen = num_freq_table_entries * sizeof(*pentry); + + sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL); + if (!sfi_cpufreq_array) + return -ENOMEM; + + memcpy(sfi_cpufreq_array, pentry, totallen); + + return 0; +} + +static int sfi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) +{ + unsigned int next_perf_state = 0; /* Index into perf table */ + u32 lo, hi; + + next_perf_state = policy->freq_table[index].driver_data; + + rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi); + lo = (lo & ~INTEL_PERF_CTL_MASK) | + ((u32) sfi_cpufreq_array[next_perf_state].ctrl_val & + INTEL_PERF_CTL_MASK); + wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi); + + return 0; +} + +static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + policy->shared_type = CPUFREQ_SHARED_TYPE_HW; + policy->cpuinfo.transition_latency = 100000; /* 100us */ + + return cpufreq_table_validate_and_show(policy, freq_table); +} + +static struct cpufreq_driver sfi_cpufreq_driver = { + .flags = CPUFREQ_CONST_LOOPS, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = sfi_cpufreq_target, + .init = sfi_cpufreq_cpu_init, + .name = "sfi-cpufreq", + .attr = cpufreq_generic_attr, +}; + +static int __init sfi_cpufreq_init(void) +{ + int ret, i; + + /* parse the freq table from SFI */ + ret = sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, sfi_parse_freq); + if (ret) + return ret; + + freq_table = kzalloc(sizeof(*freq_table) * + (num_freq_table_entries + 1), GFP_KERNEL); + if (!freq_table) { + ret = -ENOMEM; + goto err_free_array; + } + + for (i = 0; i < num_freq_table_entries; i++) { + freq_table[i].driver_data = i; + freq_table[i].frequency = sfi_cpufreq_array[i].freq_mhz * 1000; + } + freq_table[i].frequency = CPUFREQ_TABLE_END; + + ret = cpufreq_register_driver(&sfi_cpufreq_driver); + if (ret) + goto err_free_tbl; + + return ret; + +err_free_tbl: + kfree(freq_table); +err_free_array: + kfree(sfi_cpufreq_array); + return ret; +} +late_initcall(sfi_cpufreq_init); + +static void __exit sfi_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&sfi_cpufreq_driver); + kfree(freq_table); + kfree(sfi_cpufreq_array); +} +module_exit(sfi_cpufreq_exit); + +MODULE_AUTHOR("Vishwesh M Rudramuni "); +MODULE_DESCRIPTION("SFI Performance-States Driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 8c2b117fdf004ebcb81129307996218a7d471cda Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Dec 2014 09:04:55 +0800 Subject: EDAC, mce_amd_inj: Fix sparse non static symbol warning Fixes the following sparse warnings: drivers/edac/mce_amd_inj.c:204:3: warning: symbol 'dfs_fls' was not declared. Should it be static? Signed-off-by: Wei Yongjun Link: http://lkml.kernel.org/r/1418087095-14174-1-git-send-email-weiyj_lk@163.com Signed-off-by: Borislav Petkov diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 0bd91a8..f7681b5 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -197,7 +197,7 @@ static int inj_bank_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n"); -struct dfs_node { +static struct dfs_node { char *name; struct dentry *d; const struct file_operations *fops; -- cgit v0.10.2 From d64cb71bede87dbca60d586a7bb4cef87fbe2731 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Wed, 17 Dec 2014 10:31:08 -0800 Subject: Input: add regulator haptic driver This change adds support for haptic driver controlled by voltage of a regulator. Userspace can control the device via Force Feedback interface from input framework. Signed-off-by: Jaewon Kim Signed-off-by: Hyunhee Kim Acked-by: Kyungmin Park Tested-by: Chanwoo Choi Reviewed-by: Chanwoo Choi Reviewed-by: Pankaj Dubey Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.txt b/Documentation/devicetree/bindings/input/regulator-haptic.txt new file mode 100644 index 0000000..3ed1c7e --- /dev/null +++ b/Documentation/devicetree/bindings/input/regulator-haptic.txt @@ -0,0 +1,21 @@ +* Regulator Haptic Device Tree Bindings + +Required Properties: + - compatible : Should be "regulator-haptic" + - haptic-supply : Power supply to the haptic motor. + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt + + - max-microvolt : The maximum voltage value supplied to the haptic motor. + [The unit of the voltage is a micro] + + - min-microvolt : The minimum voltage value supplied to the haptic motor. + [The unit of the voltage is a micro] + +Example: + + haptics { + compatible = "regulator-haptic"; + haptic-supply = <&motor_regulator>; + max-microvolt = <2700000>; + min-microvolt = <1100000>; + }; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 23297ab..1da0a20 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -394,6 +394,18 @@ config INPUT_CM109 To compile this driver as a module, choose M here: the module will be called cm109. +config INPUT_REGULATOR_HAPTIC + tristate "Regulator haptics support" + depends on REGULATOR + select INPUT_FF_MEMLESS + help + This option enables device driver support for the haptic controlled + by a regulator. This driver supports ff-memless interface + from input framework. + + To compile this driver as a module, choose M here: the + module will be called regulator-haptic. + config INPUT_RETU_PWRBUTTON tristate "Retu Power button Driver" depends on MFD_RETU diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 19c7603..1f135af 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o +obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c new file mode 100644 index 0000000..9426221 --- /dev/null +++ b/drivers/input/misc/regulator-haptic.c @@ -0,0 +1,279 @@ +/* + * Regulator haptic driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Jaewon Kim + * Author: Hyunhee Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MAGNITUDE_SHIFT 16 + +struct regulator_haptic { + struct device *dev; + struct input_dev *input_dev; + struct regulator *regulator; + + struct work_struct work; + struct mutex mutex; + + bool active; + bool suspended; + + unsigned int max_volt; + unsigned int min_volt; + unsigned int magnitude; +}; + +static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on) +{ + int error; + + if (haptic->active != on) { + + error = on ? regulator_enable(haptic->regulator) : + regulator_disable(haptic->regulator); + if (error) { + dev_err(haptic->dev, + "failed to switch regulator %s: %d\n", + on ? "on" : "off", error); + return error; + } + + haptic->active = on; + } + + return 0; +} + +static int regulator_haptic_set_voltage(struct regulator_haptic *haptic, + unsigned int magnitude) +{ + u64 volt_mag_multi; + unsigned int intensity; + int error; + + volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude; + intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT); + + error = regulator_set_voltage(haptic->regulator, + intensity + haptic->min_volt, + haptic->max_volt); + if (error) { + dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n", + intensity + haptic->min_volt, error); + return error; + } + + return 0; +} + +static void regulator_haptic_work(struct work_struct *work) +{ + struct regulator_haptic *haptic = container_of(work, + struct regulator_haptic, work); + unsigned int magnitude; + int error; + + mutex_lock(&haptic->mutex); + + if (haptic->suspended) + goto out; + + magnitude = ACCESS_ONCE(haptic->magnitude); + + error = regulator_haptic_set_voltage(haptic, magnitude); + if (error) + goto out; + + regulator_haptic_toggle(haptic, magnitude != 0); + +out: + mutex_unlock(&haptic->mutex); +} + +static int regulator_haptic_play_effect(struct input_dev *input, void *data, + struct ff_effect *effect) +{ + struct regulator_haptic *haptic = input_get_drvdata(input); + + haptic->magnitude = effect->u.rumble.strong_magnitude; + if (!haptic->magnitude) + haptic->magnitude = effect->u.rumble.weak_magnitude; + + schedule_work(&haptic->work); + + return 0; +} + +static void regulator_haptic_close(struct input_dev *input) +{ + struct regulator_haptic *haptic = input_get_drvdata(input); + + cancel_work_sync(&haptic->work); + regulator_haptic_set_voltage(haptic, 0); + regulator_haptic_toggle(haptic, false); +} + +static int __maybe_unused +regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) +{ + struct device_node *node; + int error; + + node = dev->of_node; + if(!node) { + dev_err(dev, "Missing dveice tree data\n"); + return -EINVAL; + } + + error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt); + if (error) { + dev_err(dev, "cannot parse max-microvolt\n"); + return error; + } + + error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt); + if (error) { + dev_err(dev, "cannot parse min-microvolt\n"); + return error; + } + + return 0; +} + +static int regulator_haptic_probe(struct platform_device *pdev) +{ + const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev); + struct regulator_haptic *haptic; + struct input_dev *input_dev; + int error; + + haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); + if (!haptic) + return -ENOMEM; + + platform_set_drvdata(pdev, haptic); + haptic->dev = &pdev->dev; + mutex_init(&haptic->mutex); + INIT_WORK(&haptic->work, regulator_haptic_work); + + if (pdata) { + haptic->max_volt = pdata->max_volt; + haptic->min_volt = pdata->min_volt; + } else if (IS_ENABLED(CONFIG_OF)) { + error = regulator_haptic_parse_dt(&pdev->dev, haptic); + if (error) + return error; + } else { + dev_err(&pdev->dev, "Missing platform data\n"); + return -EINVAL; + } + + haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic"); + if (IS_ERR(haptic->regulator)) { + dev_err(&pdev->dev, "failed to get regulator\n"); + return PTR_ERR(haptic->regulator); + } + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + haptic->input_dev = input_dev; + haptic->input_dev->name = "regulator-haptic"; + haptic->input_dev->dev.parent = &pdev->dev; + haptic->input_dev->close = regulator_haptic_close; + input_set_drvdata(haptic->input_dev, haptic); + input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); + + error = input_ff_create_memless(input_dev, NULL, + regulator_haptic_play_effect); + if (error) { + dev_err(&pdev->dev, "failed to create force-feedback\n"); + return error; + } + + error = input_register_device(haptic->input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + return 0; +} + +static int __maybe_unused regulator_haptic_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct regulator_haptic *haptic = platform_get_drvdata(pdev); + int error; + + error = mutex_lock_interruptible(&haptic->mutex); + if (error) + return error; + + regulator_haptic_set_voltage(haptic, 0); + regulator_haptic_toggle(haptic, false); + + haptic->suspended = true; + + mutex_unlock(&haptic->mutex); + + return 0; +} + +static int __maybe_unused regulator_haptic_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct regulator_haptic *haptic = platform_get_drvdata(pdev); + unsigned int magnitude; + + mutex_lock(&haptic->mutex); + + haptic->suspended = false; + + magnitude = ACCESS_ONCE(haptic->magnitude); + if (magnitude) { + regulator_haptic_set_voltage(haptic, magnitude); + regulator_haptic_toggle(haptic, true); + } + + mutex_unlock(&haptic->mutex); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, + regulator_haptic_suspend, regulator_haptic_resume); + +static struct of_device_id regulator_haptic_dt_match[] = { + { .compatible = "regulator-haptic" }, + { /* sentinel */ }, +}; + +static struct platform_driver regulator_haptic_driver = { + .probe = regulator_haptic_probe, + .driver = { + .name = "regulator-haptic", + .of_match_table = regulator_haptic_dt_match, + .pm = ®ulator_haptic_pm_ops, + }, +}; +module_platform_driver(regulator_haptic_driver); + +MODULE_AUTHOR("Jaewon Kim "); +MODULE_AUTHOR("Hyunhee Kim "); +MODULE_DESCRIPTION("Regulator haptic driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/regulator-haptic.h b/include/linux/platform_data/regulator-haptic.h new file mode 100644 index 0000000..5658e58 --- /dev/null +++ b/include/linux/platform_data/regulator-haptic.h @@ -0,0 +1,29 @@ +/* + * Regulator Haptic Platform Data + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Jaewon Kim + * Author: Hyunhee Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _REGULATOR_HAPTIC_H +#define _REGULATOR_HAPTIC_H + +/* + * struct regulator_haptic_data - Platform device data + * + * @max_volt: maximum voltage value supplied to the haptic motor. + * + * @min_volt: minimum voltage value supplied to the haptic motor. + * + */ +struct regulator_haptic_data { + unsigned int max_volt; + unsigned int min_volt; +}; + +#endif /* _REGULATOR_HAPTIC_H */ -- cgit v0.10.2 From af6a5af8e8cc1566fc06636de02347825808650e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 18 Dec 2014 09:24:50 -0800 Subject: Input: add new sun4i-lradc-keys driver Allwinnner sunxi SoCs have a low resolution adc (called lradc) which is specifically designed to have various (tablet) keys (ie home, back, search, etc). attached to it using a resistor network. This adds a driver for this. There are 2 channels, currently this driver only supports chan0 since there are no boards known to use chan1. This has been tested on an olimex a10s-olinuxino-micro, a13-olinuxino, and a20-olinuxino-micro. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt new file mode 100644 index 0000000..b9c32f6 --- /dev/null +++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt @@ -0,0 +1,62 @@ +Allwinner sun4i low res adc attached tablet keys +------------------------------------------------ + +Required properties: + - compatible: "allwinner,sun4i-a10-lradc-keys" + - reg: mmio address range of the chip + - interrupts: interrupt to which the chip is connected + - vref-supply: powersupply for the lradc reference voltage + +Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys": + +Required subnode-properties: + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + - channel: Channel this key is attached to, mut be 0 or 1. + - voltage: Voltage in µV at lradc input when this key is pressed. + +Example: + +#include + + lradc: lradc@01c22800 { + compatible = "allwinner,sun4i-a10-lradc-keys"; + reg = <0x01c22800 0x100>; + interrupts = <31>; + vref-supply = <®_vcc3v0>; + + button@191 { + label = "Volume Up"; + linux,code = ; + channel = <0>; + voltage = <191274>; + }; + + button@392 { + label = "Volume Down"; + linux,code = ; + channel = <0>; + voltage = <392644>; + }; + + button@601 { + label = "Menu"; + linux,code = ; + channel = <0>; + voltage = <601151>; + }; + + button@795 { + label = "Enter"; + linux,code = ; + channel = <0>; + voltage = <795090>; + }; + + button@987 { + label = "Home"; + linux,code = ; + channel = <0>; + voltage = <987387>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index f73bb41..21b834b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8806,6 +8806,13 @@ F: arch/m68k/sun3*/ F: arch/m68k/include/asm/sun3* F: drivers/net/ethernet/i825xx/sun3* +SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt +F: drivers/input/keyboard/sun4i-lradc-keys.c + SUNDANCE NETWORK DRIVER M: Denis Kirjanov L: netdev@vger.kernel.org diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a5d9b3f..a89ba7c 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -568,6 +568,16 @@ config KEYBOARD_STMPE To compile this driver as a module, choose M here: the module will be called stmpe-keypad. +config KEYBOARD_SUN4I_LRADC + tristate "Allwinner sun4i low res adc attached tablet keys support" + depends on ARCH_SUNXI + help + This selects support for the Allwinner low res adc attached tablet + keys found on Allwinner sunxi SoCs. + + To compile this driver as a module, choose M here: the + module will be called sun4i-lradc-keys. + config KEYBOARD_DAVINCI tristate "TI DaVinci Key Scan" depends on ARCH_DAVINCI_DM365 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index febafa5..4707678 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o +obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c new file mode 100644 index 0000000..cc8f7dd --- /dev/null +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -0,0 +1,286 @@ +/* + * Allwinner sun4i low res adc attached tablet keys driver + * + * Copyright (C) 2014 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Allwinnner sunxi SoCs have a lradc which is specifically designed to have + * various (tablet) keys (ie home, back, search, etc). attached to it using + * a resistor network. This driver is for the keys on such boards. + * + * There are 2 channels, currently this driver only supports channel 0 since + * there are no boards known to use channel 1. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LRADC_CTRL 0x00 +#define LRADC_INTC 0x04 +#define LRADC_INTS 0x08 +#define LRADC_DATA0 0x0c +#define LRADC_DATA1 0x10 + +/* LRADC_CTRL bits */ +#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */ +#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */ +#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */ +#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */ +#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */ +#define HOLD_EN(x) ((x) << 6) +#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */ +#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */ +#define ENABLE(x) ((x) << 0) + +/* LRADC_INTC and LRADC_INTS bits */ +#define CHAN1_KEYUP_IRQ BIT(12) +#define CHAN1_ALRDY_HOLD_IRQ BIT(11) +#define CHAN1_HOLD_IRQ BIT(10) +#define CHAN1_KEYDOWN_IRQ BIT(9) +#define CHAN1_DATA_IRQ BIT(8) +#define CHAN0_KEYUP_IRQ BIT(4) +#define CHAN0_ALRDY_HOLD_IRQ BIT(3) +#define CHAN0_HOLD_IRQ BIT(2) +#define CHAN0_KEYDOWN_IRQ BIT(1) +#define CHAN0_DATA_IRQ BIT(0) + +struct sun4i_lradc_keymap { + u32 voltage; + u32 keycode; +}; + +struct sun4i_lradc_data { + struct device *dev; + struct input_dev *input; + void __iomem *base; + struct regulator *vref_supply; + struct sun4i_lradc_keymap *chan0_map; + u32 chan0_map_count; + u32 chan0_keycode; + u32 vref; +}; + +static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id) +{ + struct sun4i_lradc_data *lradc = dev_id; + u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff; + + ints = readl(lradc->base + LRADC_INTS); + + /* + * lradc supports only one keypress at a time, release does not give + * any info as to which key was released, so we cache the keycode. + */ + + if (ints & CHAN0_KEYUP_IRQ) { + input_report_key(lradc->input, lradc->chan0_keycode, 0); + lradc->chan0_keycode = 0; + } + + if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) { + val = readl(lradc->base + LRADC_DATA0) & 0x3f; + voltage = val * lradc->vref / 63; + + for (i = 0; i < lradc->chan0_map_count; i++) { + diff = abs(lradc->chan0_map[i].voltage - voltage); + if (diff < closest) { + closest = diff; + keycode = lradc->chan0_map[i].keycode; + } + } + + lradc->chan0_keycode = keycode; + input_report_key(lradc->input, lradc->chan0_keycode, 1); + } + + input_sync(lradc->input); + + writel(ints, lradc->base + LRADC_INTS); + + return IRQ_HANDLED; +} + +static int sun4i_lradc_open(struct input_dev *dev) +{ + struct sun4i_lradc_data *lradc = input_get_drvdata(dev); + int error; + + error = regulator_enable(lradc->vref_supply); + if (error) + return error; + + /* lradc Vref internally is divided by 2/3 */ + lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3; + + /* + * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to + * stabilize on press, wait (1 + 1) * 4 ms for key release + */ + writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | + SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL); + + writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC); + + return 0; +} + +static void sun4i_lradc_close(struct input_dev *dev) +{ + struct sun4i_lradc_data *lradc = input_get_drvdata(dev); + + /* Disable lradc, leave other settings unchanged */ + writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | + SAMPLE_RATE(2), lradc->base + LRADC_CTRL); + writel(0, lradc->base + LRADC_INTC); + + regulator_disable(lradc->vref_supply); +} + +static int sun4i_lradc_load_dt_keymap(struct device *dev, + struct sun4i_lradc_data *lradc) +{ + struct device_node *np, *pp; + int i; + int error; + + np = dev->of_node; + if (!np) + return -EINVAL; + + lradc->chan0_map_count = of_get_child_count(np); + if (lradc->chan0_map_count == 0) { + dev_err(dev, "keymap is missing in device tree\n"); + return -EINVAL; + } + + lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count, + sizeof(struct sun4i_lradc_keymap), + GFP_KERNEL); + if (!lradc->chan0_map) + return -ENOMEM; + + i = 0; + for_each_child_of_node(np, pp) { + struct sun4i_lradc_keymap *map = &lradc->chan0_map[i]; + u32 channel; + + error = of_property_read_u32(pp, "channel", &channel); + if (error || channel != 0) { + dev_err(dev, "%s: Inval channel prop\n", pp->name); + return -EINVAL; + } + + error = of_property_read_u32(pp, "voltage", &map->voltage); + if (error) { + dev_err(dev, "%s: Inval voltage prop\n", pp->name); + return -EINVAL; + } + + error = of_property_read_u32(pp, "linux,code", &map->keycode); + if (error) { + dev_err(dev, "%s: Inval linux,code prop\n", pp->name); + return -EINVAL; + } + + i++; + } + + return 0; +} + +static int sun4i_lradc_probe(struct platform_device *pdev) +{ + struct sun4i_lradc_data *lradc; + struct device *dev = &pdev->dev; + int i; + int error; + + lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL); + if (!lradc) + return -ENOMEM; + + error = sun4i_lradc_load_dt_keymap(dev, lradc); + if (error) + return error; + + lradc->vref_supply = devm_regulator_get(dev, "vref"); + if (IS_ERR(lradc->vref_supply)) + return PTR_ERR(lradc->vref_supply); + + lradc->dev = dev; + lradc->input = devm_input_allocate_device(dev); + if (!lradc->input) + return -ENOMEM; + + lradc->input->name = pdev->name; + lradc->input->phys = "sun4i_lradc/input0"; + lradc->input->open = sun4i_lradc_open; + lradc->input->close = sun4i_lradc_close; + lradc->input->id.bustype = BUS_HOST; + lradc->input->id.vendor = 0x0001; + lradc->input->id.product = 0x0001; + lradc->input->id.version = 0x0100; + + __set_bit(EV_KEY, lradc->input->evbit); + for (i = 0; i < lradc->chan0_map_count; i++) + __set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit); + + input_set_drvdata(lradc->input, lradc); + + lradc->base = devm_ioremap_resource(dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0)); + if (IS_ERR(lradc->base)) + return PTR_ERR(lradc->base); + + error = devm_request_irq(dev, platform_get_irq(pdev, 0), + sun4i_lradc_irq, 0, + "sun4i-a10-lradc-keys", lradc); + if (error) + return error; + + error = input_register_device(lradc->input); + if (error) + return error; + + platform_set_drvdata(pdev, lradc); + return 0; +} + +static const struct of_device_id sun4i_lradc_of_match[] = { + { .compatible = "allwinner,sun4i-a10-lradc-keys", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match); + +static struct platform_driver sun4i_lradc_driver = { + .driver = { + .name = "sun4i-a10-lradc-keys", + .of_match_table = of_match_ptr(sun4i_lradc_of_match), + }, + .probe = sun4i_lradc_probe, +}; + +module_platform_driver(sun4i_lradc_driver); + +MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a380acb88611e1ee90dcb3da39e05991cadc6682 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:26 +0100 Subject: ASoC: wm8750: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index d9e2626..eb0a164 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -686,18 +686,6 @@ static struct snd_soc_dai_driver wm8750_dai = { .ops = &wm8750_dai_ops, }; -static int wm8750_suspend(struct snd_soc_codec *codec) -{ - wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8750_resume(struct snd_soc_codec *codec) -{ - wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8750_probe(struct snd_soc_codec *codec) { int ret; @@ -708,9 +696,6 @@ static int wm8750_probe(struct snd_soc_codec *codec) return ret; } - /* charge output caps */ - wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* set the update bits */ snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100); @@ -724,18 +709,10 @@ static int wm8750_probe(struct snd_soc_codec *codec) return ret; } -static int wm8750_remove(struct snd_soc_codec *codec) -{ - wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { .probe = wm8750_probe, - .remove = wm8750_remove, - .suspend = wm8750_suspend, - .resume = wm8750_resume, .set_bias_level = wm8750_set_bias_level, + .suspend_bias_off = true, .controls = wm8750_snd_controls, .num_controls = ARRAY_SIZE(wm8750_snd_controls), -- cgit v0.10.2 From eca80394abc50abae9847b264b0a3120336f590a Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 21 Dec 2014 22:40:43 +0800 Subject: ASoC: Intel: fix platform_no_drv_owner.cocci warnings sound/soc/intel/cht_bsw_rt5672.c:273:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index 9b8b561..a406c610 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -270,7 +270,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { - .owner = THIS_MODULE, .name = "cht-bsw-rt5672", .pm = &snd_soc_pm_ops, }, -- cgit v0.10.2 From 602129c8d1da0b2d43f2afae2ff7f1f2919f6eaa Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 21 Dec 2014 22:34:50 +0800 Subject: ASoC: Intel: fix platform_no_drv_owner.cocci warnings sound/soc/intel/bytcr_dpcm_rt5640.c:218:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Subhransu S. Prusty Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c index f5d0fc1..9277f2b 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c @@ -215,7 +215,6 @@ static int snd_byt_mc_probe(struct platform_device *pdev) static struct platform_driver snd_byt_mc_driver = { .driver = { - .owner = THIS_MODULE, .name = "bytt100_rt5640", .pm = &snd_soc_pm_ops, }, -- cgit v0.10.2 From 676ebf68873f97c0e2a386ce979529573e0a8931 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:45 +0100 Subject: ASoC: intel: sst: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index 3abc29e..f1180ff 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -366,7 +366,6 @@ MODULE_DEVICE_TABLE(acpi, sst_acpi_ids); static struct platform_driver sst_acpi_driver = { .driver = { .name = "intel_sst_acpi", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(sst_acpi_ids), .pm = &intel_sst_pm, }, -- cgit v0.10.2 From 97d62a3096355168db71bdcbc618cbf2c3b7c2a0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:46 +0100 Subject: ASoC: omap: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 3f9ac7d..ccfb41c 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -393,7 +393,6 @@ static int omap_hdmi_audio_remove(struct platform_device *pdev) static struct platform_driver hdmi_audio_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, }, .probe = omap_hdmi_audio_probe, .remove = omap_hdmi_audio_remove, -- cgit v0.10.2 From 7e0fc116c41f0ca93c4d3de6d26c223c92182857 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:47 +0100 Subject: ASoC: pxa: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d7d5fb2..a6d680a 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -352,7 +352,6 @@ static int spitz_remove(struct platform_device *pdev) static struct platform_driver spitz_driver = { .driver = { .name = "spitz-audio", - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, }, .probe = spitz_probe, -- cgit v0.10.2 From 03da09a02de2ffd15df89b9ddef17dd7af195f32 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:48 +0100 Subject: ASoC: samsung: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c index 1e2b61c..8bf2e2c 100644 --- a/sound/soc/samsung/arndale_rt5631.c +++ b/sound/soc/samsung/arndale_rt5631.c @@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); static struct platform_driver arndale_audio_driver = { .driver = { .name = "arndale-audio", - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), }, -- cgit v0.10.2 From e951ceef65f76d6c611a4afa65dfc9420a3123f4 Mon Sep 17 00:00:00 2001 From: Beomho Seo Date: Fri, 19 Dec 2014 18:04:46 +0900 Subject: regulator: max14577: Use regulator_nodes/of_match in the descriptor This patch is add regulator_nodes/ofmatch in the regulator descriptor for using information from DT instead of specific codes. That will be used regulation_of_get_init_data function for get regulator property on device tree. Using that make driver simpler. Signed-off-by: Beomho Seo Signed-off-by: Mark Brown diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c index bf9a44c..b3678d2 100644 --- a/drivers/regulator/max14577.c +++ b/drivers/regulator/max14577.c @@ -103,6 +103,8 @@ static struct regulator_ops max14577_charger_ops = { static const struct regulator_desc max14577_supported_regulators[] = { [MAX14577_SAFEOUT] = { .name = "SAFEOUT", + .of_match = of_match_ptr("SAFEOUT"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_SAFEOUT, .ops = &max14577_safeout_ops, .type = REGULATOR_VOLTAGE, @@ -114,6 +116,8 @@ static const struct regulator_desc max14577_supported_regulators[] = { }, [MAX14577_CHARGER] = { .name = "CHARGER", + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_CHARGER, .ops = &max14577_charger_ops, .type = REGULATOR_CURRENT, @@ -137,6 +141,8 @@ static struct regulator_ops max77836_ldo_ops = { static const struct regulator_desc max77836_supported_regulators[] = { [MAX14577_SAFEOUT] = { .name = "SAFEOUT", + .of_match = of_match_ptr("SAFEOUT"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_SAFEOUT, .ops = &max14577_safeout_ops, .type = REGULATOR_VOLTAGE, @@ -148,6 +154,8 @@ static const struct regulator_desc max77836_supported_regulators[] = { }, [MAX14577_CHARGER] = { .name = "CHARGER", + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_CHARGER, .ops = &max14577_charger_ops, .type = REGULATOR_CURRENT, @@ -157,6 +165,8 @@ static const struct regulator_desc max77836_supported_regulators[] = { }, [MAX77836_LDO1] = { .name = "LDO1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), .id = MAX77836_LDO1, .ops = &max77836_ldo_ops, .type = REGULATOR_VOLTAGE, @@ -171,6 +181,8 @@ static const struct regulator_desc max77836_supported_regulators[] = { }, [MAX77836_LDO2] = { .name = "LDO2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), .id = MAX77836_LDO2, .ops = &max77836_ldo_ops, .type = REGULATOR_VOLTAGE, @@ -198,43 +210,6 @@ static struct of_regulator_match max77836_regulator_matches[] = { { .name = "LDO2", }, }; -static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, - enum maxim_device_type dev_type) -{ - int ret; - struct device_node *np; - struct of_regulator_match *regulator_matches; - unsigned int regulator_matches_size; - - np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); - if (!np) { - dev_err(&pdev->dev, "Failed to get child OF node for regulators\n"); - return -EINVAL; - } - - switch (dev_type) { - case MAXIM_DEVICE_TYPE_MAX77836: - regulator_matches = max77836_regulator_matches; - regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches); - break; - case MAXIM_DEVICE_TYPE_MAX14577: - default: - regulator_matches = max14577_regulator_matches; - regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches); - } - - ret = of_regulator_match(&pdev->dev, np, regulator_matches, - regulator_matches_size); - if (ret < 0) - dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); - else - ret = 0; - - of_node_put(np); - - return ret; -} - static inline struct regulator_init_data *match_init_data(int index, enum maxim_device_type dev_type) { @@ -261,11 +236,6 @@ static inline struct device_node *match_of_node(int index, } } #else /* CONFIG_OF */ -static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, - enum maxim_device_type dev_type) -{ - return 0; -} static inline struct regulator_init_data *match_init_data(int index, enum maxim_device_type dev_type) { @@ -308,16 +278,12 @@ static int max14577_regulator_probe(struct platform_device *pdev) { struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev); - int i, ret; + int i, ret = 0; struct regulator_config config = {}; const struct regulator_desc *supported_regulators; unsigned int supported_regulators_size; enum maxim_device_type dev_type = max14577->dev_type; - ret = max14577_regulator_dt_parse_pdata(pdev, dev_type); - if (ret) - return ret; - switch (dev_type) { case MAXIM_DEVICE_TYPE_MAX77836: supported_regulators = max77836_supported_regulators; @@ -329,7 +295,7 @@ static int max14577_regulator_probe(struct platform_device *pdev) supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators); } - config.dev = &pdev->dev; + config.dev = max14577->dev; config.driver_data = max14577; for (i = 0; i < supported_regulators_size; i++) { -- cgit v0.10.2 From 34084a4367037b5bb3de71dfa7cdcd8e998d153a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2014 11:53:47 +0100 Subject: ASoC: intel: Remove superfluous backslash in Kconfig The line continuation in Kconfig should be a '\' instead of '\\'. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index e989ecf..f06fcf1 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -46,7 +46,7 @@ config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\ + depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \ I2C_DESIGNWARE_PLATFORM select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 @@ -76,7 +76,7 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\ + depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM select SND_SOC_INTEL_HASWELL select SND_COMPRESS_OFFLOAD -- cgit v0.10.2 From 768c0564439bce179e3f0f2ffafe8dcab6a08f40 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 21 Dec 2014 11:05:43 +0100 Subject: ASoC: dapm: Don't mark MICBIAS widgets as auto non-connected The connected flag of a widget only affects widgets that are either a source or a sink. The MICBIAS widget is a simple pass-through widget though and hence its behavior is the same regardless of whether the connected flag is set or not. Hence there is not much point in trying to automatically mark MICBIAS widgets as non-connected, so just remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c5136bb..b8eba93 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3880,7 +3880,6 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card) switch (w->id) { case snd_soc_dapm_input: case snd_soc_dapm_output: - case snd_soc_dapm_micbias: dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n", w->name); if (!snd_soc_dapm_widget_in_card_paths(card, w)) { -- cgit v0.10.2 From 86d7500326ea71ea72aeaf0da78671eef28be2af Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 21 Dec 2014 11:05:44 +0100 Subject: ASoC: dapm: Simplify fully route card handling For legacy reasons the ASoC framework assumes that a CODEC INPUT or OUTPUT widget that is not explicitly connected to a external source or sink is potentially connected to a source or a sink and hence the framework treats the widget itself as source (for INPUT) or sink (for OUTPUT). For this reason a INPUT or OUTPUT widget that is really not connected needs to be explicitly marked as so. Setting the card's fully_routed flag will cause the ASoC core, once that all widgets and routes have been registered, to go through the list of all widgets and mark all INPUT and OUTPUT that are not externally connected as non-connected. This essentially negates the default behaviour of treating INPUT or OUTPUT widgets without external routes as sources or sinks. This patch takes a different approach while getting the same result. Instead of first marking INPUT and OUTPUT widgets as sinks/sources and then later marking them as non-connected, just never mark them as a sink or a source if the fully_routed flag is set on a card. This requires a lot less code and also results in a slightly faster card initialization since there is no need to iterate over all widgets and check whether the INPUT and OUTPUT widgets are connected or not. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 89823cf..ecffecc 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -431,7 +431,6 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); -void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card); unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); /* Mostly internal - should not normally be used */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 985052b..89aa671 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1626,9 +1626,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } - if (card->fully_routed) - snd_soc_dapm_auto_nc_pins(card); - snd_soc_dapm_new_widgets(card); ret = snd_card_register(card->snd_card); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b8eba93..ea49684 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2279,6 +2279,9 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) switch (w->id) { case snd_soc_dapm_input: + /* On a fully routed card a input is never a source */ + if (w->dapm->card->fully_routed) + break; w->is_source = 1; list_for_each_entry(p, &w->sources, list_sink) { if (p->source->id == snd_soc_dapm_micbias || @@ -2291,6 +2294,9 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) } break; case snd_soc_dapm_output: + /* On a fully routed card a output is never a sink */ + if (w->dapm->card->fully_routed) + break; w->is_sink = 1; list_for_each_entry(p, &w->sinks, list_source) { if (p->sink->id == snd_soc_dapm_spk || @@ -3085,16 +3091,24 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, switch (w->id) { case snd_soc_dapm_mic: - case snd_soc_dapm_input: w->is_source = 1; w->power_check = dapm_generic_check_power; break; + case snd_soc_dapm_input: + if (!dapm->card->fully_routed) + w->is_source = 1; + w->power_check = dapm_generic_check_power; + break; case snd_soc_dapm_spk: case snd_soc_dapm_hp: - case snd_soc_dapm_output: w->is_sink = 1; w->power_check = dapm_generic_check_power; break; + case snd_soc_dapm_output: + if (!dapm->card->fully_routed) + w->is_sink = 1; + w->power_check = dapm_generic_check_power; + break; case snd_soc_dapm_vmid: case snd_soc_dapm_siggen: w->is_source = 1; @@ -3809,92 +3823,6 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); /** - * dapm_is_external_path() - Checks if a path is a external path - * @card: The card the path belongs to - * @path: The path to check - * - * Returns true if the path is either between two different DAPM contexts or - * between two external pins of the same DAPM context. Otherwise returns - * false. - */ -static bool dapm_is_external_path(struct snd_soc_card *card, - struct snd_soc_dapm_path *path) -{ - dev_dbg(card->dev, - "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", - path->source->name, path->source->id, path->source->dapm, - path->sink->name, path->sink->id, path->sink->dapm); - - /* Connection between two different DAPM contexts */ - if (path->source->dapm != path->sink->dapm) - return true; - - /* Loopback connection from external pin to external pin */ - if (path->sink->id == snd_soc_dapm_input) { - switch (path->source->id) { - case snd_soc_dapm_output: - case snd_soc_dapm_micbias: - return true; - default: - break; - } - } - - return false; -} - -static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, - struct snd_soc_dapm_widget *w) -{ - struct snd_soc_dapm_path *p; - - list_for_each_entry(p, &w->sources, list_sink) { - if (dapm_is_external_path(card, p)) - return true; - } - - list_for_each_entry(p, &w->sinks, list_source) { - if (dapm_is_external_path(card, p)) - return true; - } - - return false; -} - -/** - * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins - * @card: The card whose pins should be processed - * - * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card - * which are unused. Pins are used if they are connected externally to a - * component, whether that be to some other device, or a loop-back connection to - * the component itself. - */ -void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card) -{ - struct snd_soc_dapm_widget *w; - - dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm); - - list_for_each_entry(w, &card->widgets, list) { - switch (w->id) { - case snd_soc_dapm_input: - case snd_soc_dapm_output: - dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n", - w->name); - if (!snd_soc_dapm_widget_in_card_paths(card, w)) { - dev_dbg(card->dev, - "... Not in map; disabling\n"); - snd_soc_dapm_nc_pin(w->dapm, w->name); - } - break; - default: - break; - } - } -} - -/** * snd_soc_dapm_free - free dapm resources * @dapm: DAPM context * -- cgit v0.10.2 From 2f43de605e700f5aa5cad15e19f8ffe54b1d4c86 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Fri, 19 Dec 2014 14:45:41 -0800 Subject: HID: rmi: Support non rmi devices by passing events to hid-input Allowing hid-rmi to bind to non rmi devices allows us to support composite USB devices which contain several HID devices one of which is a HID touchpad. Since all of the devices have the same VID and PID we can add the device to the hid_have_special_driver list and have hid-rmi handle all of the devices. Then hid-rmi's probe can look for the rmi specific HID report IDs and decide if it should handle the device as a rmi device or simply report that the events needs additional processing. Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index b51200f..018f80f 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -33,6 +33,9 @@ #define RMI_READ_DATA_PENDING BIT(1) #define RMI_STARTED BIT(2) +/* device flags */ +#define RMI_DEVICE BIT(0) + enum rmi_mode_type { RMI_MODE_OFF = 0, RMI_MODE_ATTN_REPORTS = 1, @@ -118,6 +121,8 @@ struct rmi_data { struct work_struct reset_work; struct hid_device *hdev; + + unsigned long device_flags; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -452,9 +457,23 @@ static int rmi_raw_event(struct hid_device *hdev, return rmi_read_data_event(hdev, data, size); case RMI_ATTN_REPORT_ID: return rmi_input_event(hdev, data, size); - case RMI_MOUSE_REPORT_ID: + default: + return 1; + } + + return 0; +} + +static int rmi_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + + if ((data->device_flags & RMI_DEVICE) && + (field->application == HID_GD_POINTER || + field->application == HID_GD_MOUSE)) { rmi_schedule_reset(hdev); - break; + return 1; } return 0; @@ -856,6 +875,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) if (ret) return; + if (!(data->device_flags & RMI_DEVICE)) + return; + /* Allow incoming hid reports */ hid_device_io_start(hdev); @@ -914,8 +936,33 @@ static int rmi_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* we want to make HID ignore the advertised HID collection */ - return -1; + struct rmi_data *data = hid_get_drvdata(hdev); + + /* + * we want to make HID ignore the advertised HID collection + * for RMI deivces + */ + if (data->device_flags & RMI_DEVICE) + return -1; + + return 0; +} + +static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type, + unsigned id, struct hid_report **report) +{ + int i; + + *report = hdev->report_enum[type].report_id_hash[id]; + if (*report) { + for (i = 0; i < (*report)->maxfield; i++) { + unsigned app = (*report)->field[i]->application; + if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR) + return 1; + } + } + + return 0; } static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -925,6 +972,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) size_t alloc_size; struct hid_report *input_report; struct hid_report *output_report; + struct hid_report *feature_report; data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); if (!data) @@ -943,27 +991,35 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - input_report = hdev->report_enum[HID_INPUT_REPORT] - .report_id_hash[RMI_ATTN_REPORT_ID]; - if (!input_report) { - hid_err(hdev, "device does not have expected input report\n"); - ret = -ENODEV; - return ret; + /* + * Check for the RMI specific report ids. If they are misisng + * simply return and let the events be processed by hid-input + */ + if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT, + RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) { + hid_dbg(hdev, "device does not have set mode feature report\n"); + goto start; + } + + if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT, + RMI_ATTN_REPORT_ID, &input_report)) { + hid_dbg(hdev, "device does not have attention input report\n"); + goto start; } data->input_report_size = (input_report->size >> 3) + 1 /* report id */; - output_report = hdev->report_enum[HID_OUTPUT_REPORT] - .report_id_hash[RMI_WRITE_REPORT_ID]; - if (!output_report) { - hid_err(hdev, "device does not have expected output report\n"); - ret = -ENODEV; - return ret; + if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, + RMI_WRITE_REPORT_ID, &output_report)) { + hid_dbg(hdev, + "device does not have rmi write output report\n"); + goto start; } data->output_report_size = (output_report->size >> 3) + 1 /* report id */; + data->device_flags |= RMI_DEVICE; alloc_size = data->output_report_size + data->input_report_size; data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); @@ -978,13 +1034,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) mutex_init(&data->page_mutex); +start: ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); return ret; } - if (!test_bit(RMI_STARTED, &data->flags)) + if ((data->device_flags & RMI_DEVICE) && + !test_bit(RMI_STARTED, &data->flags)) /* * The device maybe in the bootloader if rmi_input_configured * failed to find F11 in the PDT. Print an error, but don't @@ -1017,6 +1075,7 @@ static struct hid_driver rmi_driver = { .id_table = rmi_id, .probe = rmi_probe, .remove = rmi_remove, + .event = rmi_event, .raw_event = rmi_raw_event, .input_mapping = rmi_input_mapping, .input_configured = rmi_input_configured, -- cgit v0.10.2 From a5a41645d0096f4c9ffd7154270b43daebcb4386 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 18 Dec 2014 11:32:52 +0800 Subject: ASoC: rt5670: set platform data by dmi This patch set specific data according to dmi data. Signed-off-by: Jin, Yao Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 8a0833d..cd47ef1 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -2549,6 +2550,17 @@ static struct acpi_device_id rt5670_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); #endif +static const struct dmi_system_id dmi_platform_intel_braswell[] = { + { + .ident = "Intel Braswell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), + }, + }, + {} +}; + static int rt5670_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2568,6 +2580,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (pdata) rt5670->pdata = *pdata; + if (dmi_check_system(dmi_platform_intel_braswell)) { + rt5670->pdata.dmic_en = true; + rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.jd_mode = 1; + } + rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); if (IS_ERR(rt5670->regmap)) { ret = PTR_ERR(rt5670->regmap); -- cgit v0.10.2 From fc38a8a66e1bda87da13e8eb549dd87ddd86f3b8 Mon Sep 17 00:00:00 2001 From: Huang Bo Date: Wed, 26 Nov 2014 18:21:03 +0800 Subject: HID: add BETOP game controller force feedback support Adds force feedback support for BETOP USB game controllers. These devices are mass produced in China. Signed-off-by: Huang Bo Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 230b6f8..c33d98e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -146,6 +146,16 @@ config HID_BELKIN ---help--- Support for Belkin Flip KVM and Wireless keyboard. +config HID_BETOP_FF + tristate "Betop Production Inc. force feedback support" + depends on USB_HID + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to enable force feedback support for devices by + BETOP Production Ltd. + Currently the following devices are known to be supported: + - BETOP 2185 PC & BFM MODE + config HID_CHERRY tristate "Cherry Cymotion keyboard" if EXPERT depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index debd15b..3a27d14 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o +obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d0ac1..9b1442a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1757,6 +1757,10 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7460f34..ac20ba0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -189,6 +189,11 @@ #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 +#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2 +#define USB_VENDOR_ID_BETOP_2185PC 0x11c0 +#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380 +#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc + #define USB_VENDOR_ID_BTC 0x046e #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 -- cgit v0.10.2 From be33465e58ab3a3300c5182844d45c67e73b15e0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 12 Dec 2014 09:25:00 +0000 Subject: ASoC: dwc: Remove unnecessary debug messages and tests The devm_XXX allocation functions print a message on failure, so additional messages are not required. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index b93168d..f81e747 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -345,26 +345,17 @@ static int dw_i2s_probe(struct platform_device *pdev) } dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); - if (!dw_i2s_dai) { - dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); + if (!dw_i2s_dai) return -ENOMEM; - } dw_i2s_dai->ops = &dw_i2s_dai_ops; dw_i2s_dai->suspend = dw_i2s_suspend; dw_i2s_dai->resume = dw_i2s_resume; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no i2s resource defined\n"); - return -ENODEV; - } - dev->i2s_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dev->i2s_base)) { - dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); + if (IS_ERR(dev->i2s_base)) return PTR_ERR(dev->i2s_base); - } cap = pdata->cap; dev->capability = cap; -- cgit v0.10.2 From afa8603c6253204bf96c88739f711e89c2b00cd5 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 19 Dec 2014 16:18:07 +0000 Subject: ASoC: dwc: Reorder code in preparation for DT support Move code that configures the DAI and DMA into a separate function. This reduces the size of the dw_i2s_probe function and will make it easier to add support for device tree to the driver. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index f81e747..23a7c13 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -324,13 +324,47 @@ static int dw_i2s_resume(struct snd_soc_dai *dai) #define dw_i2s_resume NULL #endif +static void dw_configure_dai_by_pd(struct dw_i2s_dev *dev, + struct snd_soc_dai_driver *dw_i2s_dai, + struct resource *res, + const struct i2s_platform_data *pdata) +{ + /* Set DMA slaves info */ + + dev->play_dma_data.data = pdata->play_dma_data; + dev->capture_dma_data.data = pdata->capture_dma_data; + dev->play_dma_data.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.addr = res->start + I2S_RXDMA; + dev->play_dma_data.max_burst = 16; + dev->capture_dma_data.max_burst = 16; + dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + dev->play_dma_data.filter = pdata->filter; + dev->capture_dma_data.filter = pdata->filter; + + if (pdata->cap & DWC_I2S_PLAY) { + dev_dbg(dev->dev, " designware: play supported\n"); + dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->playback.channels_max = pdata->channel; + dw_i2s_dai->playback.formats = pdata->snd_fmts; + dw_i2s_dai->playback.rates = pdata->snd_rates; + } + + if (pdata->cap & DWC_I2S_RECORD) { + dev_dbg(dev->dev, "designware: record supported\n"); + dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->capture.channels_max = pdata->channel; + dw_i2s_dai->capture.formats = pdata->snd_fmts; + dw_i2s_dai->capture.rates = pdata->snd_rates; + } +} + static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; struct dw_i2s_dev *dev; struct resource *res; int ret; - unsigned int cap; struct snd_soc_dai_driver *dw_i2s_dai; if (!pdata) { @@ -357,23 +391,11 @@ static int dw_i2s_probe(struct platform_device *pdev) if (IS_ERR(dev->i2s_base)) return PTR_ERR(dev->i2s_base); - cap = pdata->cap; - dev->capability = cap; - dev->i2s_clk_cfg = pdata->i2s_clk_cfg; - - /* Set DMA slaves info */ - - dev->play_dma_data.data = pdata->play_dma_data; - dev->capture_dma_data.data = pdata->capture_dma_data; - dev->play_dma_data.addr = res->start + I2S_TXDMA; - dev->capture_dma_data.addr = res->start + I2S_RXDMA; - dev->play_dma_data.max_burst = 16; - dev->capture_dma_data.max_burst = 16; - dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - dev->play_dma_data.filter = pdata->filter; - dev->capture_dma_data.filter = pdata->filter; + dev->dev = &pdev->dev; + dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); + dev->capability = pdata->cap; + dev->i2s_clk_cfg = pdata->i2s_clk_cfg; dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); @@ -382,23 +404,6 @@ static int dw_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_clk_put; - if (cap & DWC_I2S_PLAY) { - dev_dbg(&pdev->dev, " designware: play supported\n"); - dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->playback.channels_max = pdata->channel; - dw_i2s_dai->playback.formats = pdata->snd_fmts; - dw_i2s_dai->playback.rates = pdata->snd_rates; - } - - if (cap & DWC_I2S_RECORD) { - dev_dbg(&pdev->dev, "designware: record supported\n"); - dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->capture.channels_max = pdata->channel; - dw_i2s_dai->capture.formats = pdata->snd_fmts; - dw_i2s_dai->capture.rates = pdata->snd_rates; - } - - dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, dw_i2s_dai, 1); -- cgit v0.10.2 From 52cd7785f3cdd2724f4efb5b21dbc75d6f9ccef4 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 22 Dec 2014 14:58:13 +0100 Subject: HID: betop: add drivers/hid/hid-betopff.c Commit fc38a8a66e ("HID: add BETOP game controller force feedback support") is missing the actual addition of drivers/hid/hid-betopff.c due to my mistake (I forgot to add the file after fixing conflicts). Fixes: fc38a8a66e1b ("HID: add BETOP game controller force feedback support") Reported-by: kbuild test robot Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c new file mode 100644 index 0000000..69cfc8d --- /dev/null +++ b/drivers/hid/hid-betopff.c @@ -0,0 +1,160 @@ +/* + * Force feedback support for Betop based devices + * + * The devices are distributed under various names and the same USB device ID + * can be used in both adapters and actual game controllers. + * + * 0x11c2:0x2208 "BTP2185 BFM mode Joystick" + * - tested with BTP2185 BFM Mode. + * + * 0x11C0:0x5506 "BTP2185 PC mode Joystick" + * - tested with BTP2185 PC Mode. + * + * 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad" + * - tested with BTP2185 PC Mode with another version. + * + * 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick" + * - tested with BTP2171s. + * Copyright (c) 2014 Huang Bo + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + + +#include +#include +#include +#include + +#include "hid-ids.h" + +struct betopff_device { + struct hid_report *report; +}; + +static int hid_betopff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct betopff_device *betopff = data; + __u16 left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + + betopff->report->field[2]->value[0] = left / 256; + betopff->report->field[3]->value[0] = right / 256; + + hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT); + + return 0; +} + +static int betopff_init(struct hid_device *hid) +{ + struct betopff_device *betopff; + struct hid_report *report; + struct hid_input *hidinput = + list_first_entry(&hid->inputs, struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int field_count = 0; + int error; + int i, j; + + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; + } + + report = list_first_entry(report_list, struct hid_report, list); + /* + * Actually there are 4 fields for 4 Bytes as below: + * ----------------------------------------- + * Byte0 Byte1 Byte2 Byte3 + * 0x00 0x00 left_motor right_motor + * ----------------------------------------- + * Do init them with default value. + */ + for (i = 0; i < report->maxfield; i++) { + for (j = 0; j < report->field[i]->report_count; j++) { + report->field[i]->value[j] = 0x00; + field_count++; + } + } + + if (field_count < 4) { + hid_err(hid, "not enough fields in the report: %d\n", + field_count); + return -ENODEV; + } + + betopff = kzalloc(sizeof(*betopff), GFP_KERNEL); + if (!betopff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, betopff, hid_betopff_play); + if (error) { + kfree(betopff); + return error; + } + + betopff->report = report; + hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT); + + hid_info(hid, "Force feedback for betop devices by huangbo \n"); + + return 0; +} + +static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + if (id->driver_data) + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err; + } + + betopff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id betop_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, + { } +}; +MODULE_DEVICE_TABLE(hid, betop_devices); + +static struct hid_driver betop_driver = { + .name = "betop", + .id_table = betop_devices, + .probe = betop_probe, +}; +module_hid_driver(betop_driver); + +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From c5f4546593e9911800f0926c1090959b58bc5c93 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Tue, 16 Dec 2014 11:58:18 -0600 Subject: livepatch: kernel: add TAINT_LIVEPATCH This adds a new taint flag to indicate when the kernel or a kernel module has been live patched. This will provide a clean indication in bug reports that live patching was used. Additionally, if the crash occurs in a live patched function, the live patch module will appear beside the patched function in the backtrace. Signed-off-by: Seth Jennings Acked-by: Josh Poimboeuf Reviewed-by: Miroslav Benes Reviewed-by: Petr Mladek Reviewed-by: Masami Hiramatsu Signed-off-by: Jiri Kosina diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index beefb9f..f3ac05c 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -270,6 +270,8 @@ characters, each representing a particular tainted value. 15: 'L' if a soft lockup has previously occurred on the system. + 16: 'K' if the kernel has been live patched. + The primary reason for the 'Tainted: ' string is to tell kernel debuggers if this is a clean kernel or if anything unusual has occurred. Tainting is permanent: even if an offending module is diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 75511ef..83ab256 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -843,6 +843,7 @@ can be ORed together: 8192 - An unsigned module has been loaded in a kernel supporting module signature. 16384 - A soft lockup has previously occurred on the system. +32768 - The kernel has been live patched. ============================================================== diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 5449d2f..d03e3de 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -471,6 +471,7 @@ extern enum system_states { #define TAINT_OOT_MODULE 12 #define TAINT_UNSIGNED_MODULE 13 #define TAINT_SOFTLOCKUP 14 +#define TAINT_LIVEPATCH 15 extern const char hex_asc[]; #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] diff --git a/kernel/panic.c b/kernel/panic.c index 4d8d6f9..8136ad7 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -226,6 +226,7 @@ static const struct tnt tnts[] = { { TAINT_OOT_MODULE, 'O', ' ' }, { TAINT_UNSIGNED_MODULE, 'E', ' ' }, { TAINT_SOFTLOCKUP, 'L', ' ' }, + { TAINT_LIVEPATCH, 'K', ' ' }, }; /** @@ -246,6 +247,7 @@ static const struct tnt tnts[] = { * 'O' - Out-of-tree module has been loaded. * 'E' - Unsigned module has been loaded. * 'L' - A soft lockup has previously occurred. + * 'K' - Kernel has been live patched. * * The string is overwritten by the next call to print_tainted(). */ -- cgit v0.10.2 From b700e7f03df5d92f85fa5247fe1f557528d3363d Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Tue, 16 Dec 2014 11:58:19 -0600 Subject: livepatch: kernel: add support for live patching This commit introduces code for the live patching core. It implements an ftrace-based mechanism and kernel interface for doing live patching of kernel and kernel module functions. It represents the greatest common functionality set between kpatch and kgraft and can accept patches built using either method. This first version does not implement any consistency mechanism that ensures that old and new code do not run together. In practice, ~90% of CVEs are safe to apply in this way, since they simply add a conditional check. However, any function change that can not execute safely with the old version of the function can _not_ be safely applied in this version. [ jkosina@suse.cz: due to the number of contributions that got folded into this original patch from Seth Jennings, add SUSE's copyright as well, as discussed via e-mail ] Signed-off-by: Seth Jennings Signed-off-by: Josh Poimboeuf Reviewed-by: Miroslav Benes Reviewed-by: Petr Mladek Reviewed-by: Masami Hiramatsu Signed-off-by: Miroslav Benes Signed-off-by: Petr Mladek Signed-off-by: Jiri Kosina diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch new file mode 100644 index 0000000..5bf42a8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-livepatch @@ -0,0 +1,44 @@ +What: /sys/kernel/livepatch +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + Interface for kernel live patching + + The /sys/kernel/livepatch directory contains subdirectories for + each loaded live patch module. + +What: /sys/kernel/livepatch/ +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + The patch directory contains subdirectories for each kernel + object (vmlinux or a module) in which it patched functions. + +What: /sys/kernel/livepatch//enabled +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + A writable attribute that indicates whether the patched + code is currently applied. Writing 0 will disable the patch + while writing 1 will re-enable the patch. + +What: /sys/kernel/livepatch// +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + The object directory contains subdirectories for each function + that is patched within the object. + +What: /sys/kernel/livepatch/// +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + The function directory contains attributes regarding the + properties and state of the patched function. + + There are currently no such attributes. diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8..df6a078 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5784,6 +5784,19 @@ F: Documentation/misc-devices/lis3lv02d F: drivers/misc/lis3lv02d/ F: drivers/platform/x86/hp_accel.c +LIVE PATCHING +M: Josh Poimboeuf +M: Seth Jennings +M: Jiri Kosina +M: Vojtech Pavlik +S: Maintained +F: kernel/livepatch/ +F: include/linux/livepatch.h +F: arch/x86/include/asm/livepatch.h +F: arch/x86/kernel/livepatch.c +F: Documentation/ABI/testing/sysfs-kernel-livepatch +L: live-patching@vger.kernel.org + LLC (802.2) M: Arnaldo Carvalho de Melo S: Maintained diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ba397bd..460b31b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -17,6 +17,7 @@ config X86_64 depends on 64BIT select X86_DEV_DMA_OPS select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_HAVE_LIVE_PATCHING ### Arch settings config X86 @@ -2008,6 +2009,8 @@ config CMDLINE_OVERRIDE This is used to work around broken boot loaders. This should be set to 'N' under normal conditions. +source "kernel/livepatch/Kconfig" + endmenu config ARCH_ENABLE_MEMORY_HOTPLUG diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h new file mode 100644 index 0000000..d529db1 --- /dev/null +++ b/arch/x86/include/asm/livepatch.h @@ -0,0 +1,37 @@ +/* + * livepatch.h - x86-specific Kernel Live Patching Core + * + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2014 SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _ASM_X86_LIVEPATCH_H +#define _ASM_X86_LIVEPATCH_H + +#include + +#ifdef CONFIG_LIVE_PATCHING +#ifndef CC_USING_FENTRY +#error Your compiler must support -mfentry for live patching to work +#endif +extern int klp_write_module_reloc(struct module *mod, unsigned long type, + unsigned long loc, unsigned long value); + +#else +#error Live patching support is disabled; check CONFIG_LIVE_PATCHING +#endif + +#endif /* _ASM_X86_LIVEPATCH_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 5d4502c..316b34e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-y += apic/ obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o +obj-$(CONFIG_LIVE_PATCHING) += livepatch.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o obj-$(CONFIG_X86_TSC) += trace_clock.o diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c new file mode 100644 index 0000000..ff3c3101d --- /dev/null +++ b/arch/x86/kernel/livepatch.c @@ -0,0 +1,90 @@ +/* + * livepatch.c - x86-specific Kernel Live Patching Core + * + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2014 SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +/** + * klp_write_module_reloc() - write a relocation in a module + * @mod: module in which the section to be modified is found + * @type: ELF relocation type (see asm/elf.h) + * @loc: address that the relocation should be written to + * @value: relocation value (sym address + addend) + * + * This function writes a relocation to the specified location for + * a particular module. + */ +int klp_write_module_reloc(struct module *mod, unsigned long type, + unsigned long loc, unsigned long value) +{ + int ret, numpages, size = 4; + bool readonly; + unsigned long val; + unsigned long core = (unsigned long)mod->module_core; + unsigned long core_ro_size = mod->core_ro_size; + unsigned long core_size = mod->core_size; + + switch (type) { + case R_X86_64_NONE: + return 0; + case R_X86_64_64: + val = value; + size = 8; + break; + case R_X86_64_32: + val = (u32)value; + break; + case R_X86_64_32S: + val = (s32)value; + break; + case R_X86_64_PC32: + val = (u32)(value - loc); + break; + default: + /* unsupported relocation type */ + return -EINVAL; + } + + if (loc < core || loc >= core + core_size) + /* loc does not point to any symbol inside the module */ + return -EINVAL; + + if (loc < core + core_ro_size) + readonly = true; + else + readonly = false; + + /* determine if the relocation spans a page boundary */ + numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2; + + if (readonly) + set_memory_rw(loc & PAGE_MASK, numpages); + + ret = probe_kernel_write((void *)loc, &val, size); + + if (readonly) + set_memory_ro(loc & PAGE_MASK, numpages); + + return ret; +} diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h new file mode 100644 index 0000000..950bc61 --- /dev/null +++ b/include/linux/livepatch.h @@ -0,0 +1,133 @@ +/* + * livepatch.h - Kernel Live Patching Core + * + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2014 SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _LINUX_LIVEPATCH_H_ +#define _LINUX_LIVEPATCH_H_ + +#include +#include + +#if IS_ENABLED(CONFIG_LIVE_PATCHING) + +#include + +enum klp_state { + KLP_DISABLED, + KLP_ENABLED +}; + +/** + * struct klp_func - function structure for live patching + * @old_name: name of the function to be patched + * @new_func: pointer to the patched function code + * @old_addr: a hint conveying at what address the old function + * can be found (optional, vmlinux patches only) + * @kobj: kobject for sysfs resources + * @fops: ftrace operations structure + * @state: tracks function-level patch application state + */ +struct klp_func { + /* external */ + const char *old_name; + void *new_func; + /* + * The old_addr field is optional and can be used to resolve + * duplicate symbol names in the vmlinux object. If this + * information is not present, the symbol is located by name + * with kallsyms. If the name is not unique and old_addr is + * not provided, the patch application fails as there is no + * way to resolve the ambiguity. + */ + unsigned long old_addr; + + /* internal */ + struct kobject kobj; + struct ftrace_ops *fops; + enum klp_state state; +}; + +/** + * struct klp_reloc - relocation structure for live patching + * @loc: address where the relocation will be written + * @val: address of the referenced symbol (optional, + * vmlinux patches only) + * @type: ELF relocation type + * @name: name of the referenced symbol (for lookup/verification) + * @addend: offset from the referenced symbol + * @external: symbol is either exported or within the live patch module itself + */ +struct klp_reloc { + unsigned long loc; + unsigned long val; + unsigned long type; + const char *name; + int addend; + int external; +}; + +/** + * struct klp_object - kernel object structure for live patching + * @name: module name (or NULL for vmlinux) + * @relocs: relocation entries to be applied at load time + * @funcs: function entries for functions to be patched in the object + * @kobj: kobject for sysfs resources + * @mod: kernel module associated with the patched object + * (NULL for vmlinux) + * @state: tracks object-level patch application state + */ +struct klp_object { + /* external */ + const char *name; + struct klp_reloc *relocs; + struct klp_func *funcs; + + /* internal */ + struct kobject *kobj; + struct module *mod; + enum klp_state state; +}; + +/** + * struct klp_patch - patch structure for live patching + * @mod: reference to the live patch module + * @objs: object entries for kernel objects to be patched + * @list: list node for global list of registered patches + * @kobj: kobject for sysfs resources + * @state: tracks patch-level application state + */ +struct klp_patch { + /* external */ + struct module *mod; + struct klp_object *objs; + + /* internal */ + struct list_head list; + struct kobject kobj; + enum klp_state state; +}; + +extern int klp_register_patch(struct klp_patch *); +extern int klp_unregister_patch(struct klp_patch *); +extern int klp_enable_patch(struct klp_patch *); +extern int klp_disable_patch(struct klp_patch *); + +#endif /* CONFIG_LIVE_PATCHING */ + +#endif /* _LINUX_LIVEPATCH_H_ */ diff --git a/kernel/Makefile b/kernel/Makefile index a59481a..616994f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -26,6 +26,7 @@ obj-y += power/ obj-y += printk/ obj-y += irq/ obj-y += rcu/ +obj-y += livepatch/ obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o obj-$(CONFIG_FREEZER) += freezer.o diff --git a/kernel/livepatch/Kconfig b/kernel/livepatch/Kconfig new file mode 100644 index 0000000..96da00f --- /dev/null +++ b/kernel/livepatch/Kconfig @@ -0,0 +1,18 @@ +config ARCH_HAVE_LIVE_PATCHING + boolean + help + Arch supports kernel live patching + +config LIVE_PATCHING + boolean "Kernel Live Patching" + depends on DYNAMIC_FTRACE_WITH_REGS + depends on MODULES + depends on SYSFS + depends on KALLSYMS_ALL + depends on ARCH_HAVE_LIVE_PATCHING + help + Say Y here if you want to support kernel live patching. + This option has no runtime impact until a kernel "patch" + module uses the interface provided by this option to register + a patch, causing calls to patched functions to be redirected + to new function code contained in the patch module. diff --git a/kernel/livepatch/Makefile b/kernel/livepatch/Makefile new file mode 100644 index 0000000..7c1f008 --- /dev/null +++ b/kernel/livepatch/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_LIVE_PATCHING) += livepatch.o + +livepatch-objs := core.o diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c new file mode 100644 index 0000000..f99fe18 --- /dev/null +++ b/kernel/livepatch/core.c @@ -0,0 +1,930 @@ +/* + * core.c - Kernel Live Patching Core + * + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2014 SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The klp_mutex protects the klp_patches list and state transitions of any + * structure reachable from the patches list. References to any structure must + * be obtained under mutex protection. + */ + +static DEFINE_MUTEX(klp_mutex); +static LIST_HEAD(klp_patches); + +static struct kobject *klp_root_kobj; + +static bool klp_is_module(struct klp_object *obj) +{ + return obj->name; +} + +static bool klp_is_object_loaded(struct klp_object *obj) +{ + return !obj->name || obj->mod; +} + +/* sets obj->mod if object is not vmlinux and module is found */ +static void klp_find_object_module(struct klp_object *obj) +{ + if (!klp_is_module(obj)) + return; + + mutex_lock(&module_mutex); + /* + * We don't need to take a reference on the module here because we have + * the klp_mutex, which is also taken by the module notifier. This + * prevents any module from unloading until we release the klp_mutex. + */ + obj->mod = find_module(obj->name); + mutex_unlock(&module_mutex); +} + +/* klp_mutex must be held by caller */ +static bool klp_is_patch_registered(struct klp_patch *patch) +{ + struct klp_patch *mypatch; + + list_for_each_entry(mypatch, &klp_patches, list) + if (mypatch == patch) + return true; + + return false; +} + +static bool klp_initialized(void) +{ + return klp_root_kobj; +} + +struct klp_find_arg { + const char *objname; + const char *name; + unsigned long addr; + /* + * If count == 0, the symbol was not found. If count == 1, a unique + * match was found and addr is set. If count > 1, there is + * unresolvable ambiguity among "count" number of symbols with the same + * name in the same object. + */ + unsigned long count; +}; + +static int klp_find_callback(void *data, const char *name, + struct module *mod, unsigned long addr) +{ + struct klp_find_arg *args = data; + + if ((mod && !args->objname) || (!mod && args->objname)) + return 0; + + if (strcmp(args->name, name)) + return 0; + + if (args->objname && strcmp(args->objname, mod->name)) + return 0; + + /* + * args->addr might be overwritten if another match is found + * but klp_find_object_symbol() handles this and only returns the + * addr if count == 1. + */ + args->addr = addr; + args->count++; + + return 0; +} + +static int klp_find_object_symbol(const char *objname, const char *name, + unsigned long *addr) +{ + struct klp_find_arg args = { + .objname = objname, + .name = name, + .addr = 0, + .count = 0 + }; + + kallsyms_on_each_symbol(klp_find_callback, &args); + + if (args.count == 0) + pr_err("symbol '%s' not found in symbol table\n", name); + else if (args.count > 1) + pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n", + args.count, name, objname); + else { + *addr = args.addr; + return 0; + } + + *addr = 0; + return -EINVAL; +} + +struct klp_verify_args { + const char *name; + const unsigned long addr; +}; + +static int klp_verify_callback(void *data, const char *name, + struct module *mod, unsigned long addr) +{ + struct klp_verify_args *args = data; + + if (!mod && + !strcmp(args->name, name) && + args->addr == addr) + return 1; + + return 0; +} + +static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr) +{ + struct klp_verify_args args = { + .name = name, + .addr = addr, + }; + + if (kallsyms_on_each_symbol(klp_verify_callback, &args)) + return 0; + + pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?", + name, addr); + return -EINVAL; +} + +static int klp_find_verify_func_addr(struct klp_object *obj, + struct klp_func *func) +{ + int ret; + +#if defined(CONFIG_RANDOMIZE_BASE) + /* KASLR is enabled, disregard old_addr from user */ + func->old_addr = 0; +#endif + + if (!func->old_addr || klp_is_module(obj)) + ret = klp_find_object_symbol(obj->name, func->old_name, + &func->old_addr); + else + ret = klp_verify_vmlinux_symbol(func->old_name, + func->old_addr); + + return ret; +} + +/* + * external symbols are located outside the parent object (where the parent + * object is either vmlinux or the kmod being patched). + */ +static int klp_find_external_symbol(struct module *pmod, const char *name, + unsigned long *addr) +{ + const struct kernel_symbol *sym; + + /* first, check if it's an exported symbol */ + preempt_disable(); + sym = find_symbol(name, NULL, NULL, true, true); + preempt_enable(); + if (sym) { + *addr = sym->value; + return 0; + } + + /* otherwise check if it's in another .o within the patch module */ + return klp_find_object_symbol(pmod->name, name, addr); +} + +static int klp_write_object_relocations(struct module *pmod, + struct klp_object *obj) +{ + int ret; + struct klp_reloc *reloc; + + if (WARN_ON(!klp_is_object_loaded(obj))) + return -EINVAL; + + if (WARN_ON(!obj->relocs)) + return -EINVAL; + + for (reloc = obj->relocs; reloc->name; reloc++) { + if (!klp_is_module(obj)) { + ret = klp_verify_vmlinux_symbol(reloc->name, + reloc->val); + if (ret) + return ret; + } else { + /* module, reloc->val needs to be discovered */ + if (reloc->external) + ret = klp_find_external_symbol(pmod, + reloc->name, + &reloc->val); + else + ret = klp_find_object_symbol(obj->mod->name, + reloc->name, + &reloc->val); + if (ret) + return ret; + } + ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc, + reloc->val + reloc->addend); + if (ret) { + pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n", + reloc->name, reloc->val, ret); + return ret; + } + } + + return 0; +} + +static void notrace klp_ftrace_handler(unsigned long ip, + unsigned long parent_ip, + struct ftrace_ops *ops, + struct pt_regs *regs) +{ + struct klp_func *func = ops->private; + + regs->ip = (unsigned long)func->new_func; +} + +static int klp_disable_func(struct klp_func *func) +{ + int ret; + + if (WARN_ON(func->state != KLP_ENABLED)) + return -EINVAL; + + if (WARN_ON(!func->old_addr)) + return -EINVAL; + + ret = unregister_ftrace_function(func->fops); + if (ret) { + pr_err("failed to unregister ftrace handler for function '%s' (%d)\n", + func->old_name, ret); + return ret; + } + + ret = ftrace_set_filter_ip(func->fops, func->old_addr, 1, 0); + if (ret) + pr_warn("function unregister succeeded but failed to clear the filter\n"); + + func->state = KLP_DISABLED; + + return 0; +} + +static int klp_enable_func(struct klp_func *func) +{ + int ret; + + if (WARN_ON(!func->old_addr)) + return -EINVAL; + + if (WARN_ON(func->state != KLP_DISABLED)) + return -EINVAL; + + ret = ftrace_set_filter_ip(func->fops, func->old_addr, 0, 0); + if (ret) { + pr_err("failed to set ftrace filter for function '%s' (%d)\n", + func->old_name, ret); + return ret; + } + + ret = register_ftrace_function(func->fops); + if (ret) { + pr_err("failed to register ftrace handler for function '%s' (%d)\n", + func->old_name, ret); + ftrace_set_filter_ip(func->fops, func->old_addr, 1, 0); + } else { + func->state = KLP_ENABLED; + } + + return ret; +} + +static int klp_disable_object(struct klp_object *obj) +{ + struct klp_func *func; + int ret; + + for (func = obj->funcs; func->old_name; func++) { + if (func->state != KLP_ENABLED) + continue; + + ret = klp_disable_func(func); + if (ret) + return ret; + } + + obj->state = KLP_DISABLED; + + return 0; +} + +static int klp_enable_object(struct klp_object *obj) +{ + struct klp_func *func; + int ret; + + if (WARN_ON(obj->state != KLP_DISABLED)) + return -EINVAL; + + if (WARN_ON(!klp_is_object_loaded(obj))) + return -EINVAL; + + for (func = obj->funcs; func->old_name; func++) { + ret = klp_enable_func(func); + if (ret) + goto unregister; + } + obj->state = KLP_ENABLED; + + return 0; + +unregister: + WARN_ON(klp_disable_object(obj)); + return ret; +} + +static int __klp_disable_patch(struct klp_patch *patch) +{ + struct klp_object *obj; + int ret; + + pr_notice("disabling patch '%s'\n", patch->mod->name); + + for (obj = patch->objs; obj->funcs; obj++) { + if (obj->state != KLP_ENABLED) + continue; + + ret = klp_disable_object(obj); + if (ret) + return ret; + } + + patch->state = KLP_DISABLED; + + return 0; +} + +/** + * klp_disable_patch() - disables a registered patch + * @patch: The registered, enabled patch to be disabled + * + * Unregisters the patched functions from ftrace. + * + * Return: 0 on success, otherwise error + */ +int klp_disable_patch(struct klp_patch *patch) +{ + int ret; + + mutex_lock(&klp_mutex); + + if (!klp_is_patch_registered(patch)) { + ret = -EINVAL; + goto err; + } + + if (patch->state == KLP_DISABLED) { + ret = -EINVAL; + goto err; + } + + ret = __klp_disable_patch(patch); + +err: + mutex_unlock(&klp_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(klp_disable_patch); + +static int __klp_enable_patch(struct klp_patch *patch) +{ + struct klp_object *obj; + int ret; + + if (WARN_ON(patch->state != KLP_DISABLED)) + return -EINVAL; + + pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n"); + add_taint(TAINT_LIVEPATCH, LOCKDEP_STILL_OK); + + pr_notice("enabling patch '%s'\n", patch->mod->name); + + for (obj = patch->objs; obj->funcs; obj++) { + klp_find_object_module(obj); + + if (!klp_is_object_loaded(obj)) + continue; + + ret = klp_enable_object(obj); + if (ret) + goto unregister; + } + + patch->state = KLP_ENABLED; + + return 0; + +unregister: + WARN_ON(__klp_disable_patch(patch)); + return ret; +} + +/** + * klp_enable_patch() - enables a registered patch + * @patch: The registered, disabled patch to be enabled + * + * Performs the needed symbol lookups and code relocations, + * then registers the patched functions with ftrace. + * + * Return: 0 on success, otherwise error + */ +int klp_enable_patch(struct klp_patch *patch) +{ + int ret; + + mutex_lock(&klp_mutex); + + if (!klp_is_patch_registered(patch)) { + ret = -EINVAL; + goto err; + } + + ret = __klp_enable_patch(patch); + +err: + mutex_unlock(&klp_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(klp_enable_patch); + +/* + * Sysfs Interface + * + * /sys/kernel/livepatch + * /sys/kernel/livepatch/ + * /sys/kernel/livepatch//enabled + * /sys/kernel/livepatch// + * /sys/kernel/livepatch/// + */ + +static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct klp_patch *patch; + int ret; + unsigned long val; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return -EINVAL; + + if (val != KLP_DISABLED && val != KLP_ENABLED) + return -EINVAL; + + patch = container_of(kobj, struct klp_patch, kobj); + + mutex_lock(&klp_mutex); + + if (val == patch->state) { + /* already in requested state */ + ret = -EINVAL; + goto err; + } + + if (val == KLP_ENABLED) { + ret = __klp_enable_patch(patch); + if (ret) + goto err; + } else { + ret = __klp_disable_patch(patch); + if (ret) + goto err; + } + + mutex_unlock(&klp_mutex); + + return count; + +err: + mutex_unlock(&klp_mutex); + return ret; +} + +static ssize_t enabled_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct klp_patch *patch; + + patch = container_of(kobj, struct klp_patch, kobj); + return snprintf(buf, PAGE_SIZE-1, "%d\n", patch->state); +} + +static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled); +static struct attribute *klp_patch_attrs[] = { + &enabled_kobj_attr.attr, + NULL +}; + +static void klp_kobj_release_patch(struct kobject *kobj) +{ + /* + * Once we have a consistency model we'll need to module_put() the + * patch module here. See klp_register_patch() for more details. + */ +} + +static struct kobj_type klp_ktype_patch = { + .release = klp_kobj_release_patch, + .sysfs_ops = &kobj_sysfs_ops, + .default_attrs = klp_patch_attrs, +}; + +static void klp_kobj_release_func(struct kobject *kobj) +{ + struct klp_func *func; + + func = container_of(kobj, struct klp_func, kobj); + kfree(func->fops); +} + +static struct kobj_type klp_ktype_func = { + .release = klp_kobj_release_func, + .sysfs_ops = &kobj_sysfs_ops, +}; + +/* + * Free all functions' kobjects in the array up to some limit. When limit is + * NULL, all kobjects are freed. + */ +static void klp_free_funcs_limited(struct klp_object *obj, + struct klp_func *limit) +{ + struct klp_func *func; + + for (func = obj->funcs; func->old_name && func != limit; func++) + kobject_put(&func->kobj); +} + +/* Clean up when a patched object is unloaded */ +static void klp_free_object_loaded(struct klp_object *obj) +{ + struct klp_func *func; + + obj->mod = NULL; + + for (func = obj->funcs; func->old_name; func++) + func->old_addr = 0; +} + +/* + * Free all objects' kobjects in the array up to some limit. When limit is + * NULL, all kobjects are freed. + */ +static void klp_free_objects_limited(struct klp_patch *patch, + struct klp_object *limit) +{ + struct klp_object *obj; + + for (obj = patch->objs; obj->funcs && obj != limit; obj++) { + klp_free_funcs_limited(obj, NULL); + kobject_put(obj->kobj); + } +} + +static void klp_free_patch(struct klp_patch *patch) +{ + klp_free_objects_limited(patch, NULL); + if (!list_empty(&patch->list)) + list_del(&patch->list); + kobject_put(&patch->kobj); +} + +static int klp_init_func(struct klp_object *obj, struct klp_func *func) +{ + struct ftrace_ops *ops; + int ret; + + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + + ops->private = func; + ops->func = klp_ftrace_handler; + ops->flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_DYNAMIC; + func->fops = ops; + func->state = KLP_DISABLED; + + ret = kobject_init_and_add(&func->kobj, &klp_ktype_func, + obj->kobj, func->old_name); + if (ret) { + kfree(func->fops); + return ret; + } + + return 0; +} + +/* parts of the initialization that is done only when the object is loaded */ +static int klp_init_object_loaded(struct klp_patch *patch, + struct klp_object *obj) +{ + struct klp_func *func; + int ret; + + if (obj->relocs) { + ret = klp_write_object_relocations(patch->mod, obj); + if (ret) + return ret; + } + + for (func = obj->funcs; func->old_name; func++) { + ret = klp_find_verify_func_addr(obj, func); + if (ret) + return ret; + } + + return 0; +} + +static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) +{ + struct klp_func *func; + int ret; + const char *name; + + if (!obj->funcs) + return -EINVAL; + + obj->state = KLP_DISABLED; + + klp_find_object_module(obj); + + name = klp_is_module(obj) ? obj->name : "vmlinux"; + obj->kobj = kobject_create_and_add(name, &patch->kobj); + if (!obj->kobj) + return -ENOMEM; + + for (func = obj->funcs; func->old_name; func++) { + ret = klp_init_func(obj, func); + if (ret) + goto free; + } + + if (klp_is_object_loaded(obj)) { + ret = klp_init_object_loaded(patch, obj); + if (ret) + goto free; + } + + return 0; + +free: + klp_free_funcs_limited(obj, func); + kobject_put(obj->kobj); + return ret; +} + +static int klp_init_patch(struct klp_patch *patch) +{ + struct klp_object *obj; + int ret; + + if (!patch->objs) + return -EINVAL; + + mutex_lock(&klp_mutex); + + patch->state = KLP_DISABLED; + + ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch, + klp_root_kobj, patch->mod->name); + if (ret) + goto unlock; + + for (obj = patch->objs; obj->funcs; obj++) { + ret = klp_init_object(patch, obj); + if (ret) + goto free; + } + + list_add(&patch->list, &klp_patches); + + mutex_unlock(&klp_mutex); + + return 0; + +free: + klp_free_objects_limited(patch, obj); + kobject_put(&patch->kobj); +unlock: + mutex_unlock(&klp_mutex); + return ret; +} + +/** + * klp_unregister_patch() - unregisters a patch + * @patch: Disabled patch to be unregistered + * + * Frees the data structures and removes the sysfs interface. + * + * Return: 0 on success, otherwise error + */ +int klp_unregister_patch(struct klp_patch *patch) +{ + int ret = 0; + + mutex_lock(&klp_mutex); + + if (!klp_is_patch_registered(patch)) { + ret = -EINVAL; + goto out; + } + + if (patch->state == KLP_ENABLED) { + ret = -EBUSY; + goto out; + } + + klp_free_patch(patch); + +out: + mutex_unlock(&klp_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(klp_unregister_patch); + +/** + * klp_register_patch() - registers a patch + * @patch: Patch to be registered + * + * Initializes the data structure associated with the patch and + * creates the sysfs interface. + * + * Return: 0 on success, otherwise error + */ +int klp_register_patch(struct klp_patch *patch) +{ + int ret; + + if (!klp_initialized()) + return -ENODEV; + + if (!patch || !patch->mod) + return -EINVAL; + + /* + * A reference is taken on the patch module to prevent it from being + * unloaded. Right now, we don't allow patch modules to unload since + * there is currently no method to determine if a thread is still + * running in the patched code contained in the patch module once + * the ftrace registration is successful. + */ + if (!try_module_get(patch->mod)) + return -ENODEV; + + ret = klp_init_patch(patch); + if (ret) + module_put(patch->mod); + + return ret; +} +EXPORT_SYMBOL_GPL(klp_register_patch); + +static void klp_module_notify_coming(struct klp_patch *patch, + struct klp_object *obj) +{ + struct module *pmod = patch->mod; + struct module *mod = obj->mod; + int ret; + + ret = klp_init_object_loaded(patch, obj); + if (ret) + goto err; + + if (patch->state == KLP_DISABLED) + return; + + pr_notice("applying patch '%s' to loading module '%s'\n", + pmod->name, mod->name); + + ret = klp_enable_object(obj); + if (!ret) + return; + +err: + pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", + pmod->name, mod->name, ret); +} + +static void klp_module_notify_going(struct klp_patch *patch, + struct klp_object *obj) +{ + struct module *pmod = patch->mod; + struct module *mod = obj->mod; + int ret; + + if (patch->state == KLP_DISABLED) + goto disabled; + + pr_notice("reverting patch '%s' on unloading module '%s'\n", + pmod->name, mod->name); + + ret = klp_disable_object(obj); + if (ret) + pr_warn("failed to revert patch '%s' on module '%s' (%d)\n", + pmod->name, mod->name, ret); + +disabled: + klp_free_object_loaded(obj); +} + +static int klp_module_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct module *mod = data; + struct klp_patch *patch; + struct klp_object *obj; + + if (action != MODULE_STATE_COMING && action != MODULE_STATE_GOING) + return 0; + + mutex_lock(&klp_mutex); + + list_for_each_entry(patch, &klp_patches, list) { + for (obj = patch->objs; obj->funcs; obj++) { + if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) + continue; + + if (action == MODULE_STATE_COMING) { + obj->mod = mod; + klp_module_notify_coming(patch, obj); + } else /* MODULE_STATE_GOING */ + klp_module_notify_going(patch, obj); + + break; + } + } + + mutex_unlock(&klp_mutex); + + return 0; +} + +static struct notifier_block klp_module_nb = { + .notifier_call = klp_module_notify, + .priority = INT_MIN+1, /* called late but before ftrace notifier */ +}; + +static int klp_init(void) +{ + int ret; + + ret = register_module_notifier(&klp_module_nb); + if (ret) + return ret; + + klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj); + if (!klp_root_kobj) { + ret = -ENOMEM; + goto unregister; + } + + return 0; + +unregister: + unregister_module_notifier(&klp_module_nb); + return ret; +} + +module_init(klp_init); -- cgit v0.10.2 From 13d1cf7e702596e0cd8ec62afa6bd49c431f2d0c Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Tue, 16 Dec 2014 11:58:20 -0600 Subject: livepatch: samples: add sample live patching module Add a sample live patching module. Signed-off-by: Seth Jennings Reviewed-by: Miroslav Benes Reviewed-by: Petr Mladek Reviewed-by: Masami Hiramatsu Signed-off-by: Jiri Kosina diff --git a/MAINTAINERS b/MAINTAINERS index df6a078..afe93ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5795,6 +5795,7 @@ F: include/linux/livepatch.h F: arch/x86/include/asm/livepatch.h F: arch/x86/kernel/livepatch.c F: Documentation/ABI/testing/sysfs-kernel-livepatch +F: samples/livepatch/ L: live-patching@vger.kernel.org LLC (802.2) diff --git a/samples/Kconfig b/samples/Kconfig index 6181c2c..0aed20d 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -63,4 +63,11 @@ config SAMPLE_RPMSG_CLIENT to communicate with an AMP-configured remote processor over the rpmsg bus. +config SAMPLE_LIVE_PATCHING + tristate "Build live patching sample -- loadable modules only" + depends on LIVE_PATCHING && m + help + Builds a sample live patch that replaces the procfs handler + for /proc/cmdline to print "this has been live patched". + endif # SAMPLES diff --git a/samples/Makefile b/samples/Makefile index 1a60c62..f00257b 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -1,4 +1,4 @@ # Makefile for Linux samples code -obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ \ +obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ diff --git a/samples/livepatch/Makefile b/samples/livepatch/Makefile new file mode 100644 index 0000000..7f1cdc1 --- /dev/null +++ b/samples/livepatch/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SAMPLE_LIVE_PATCHING) += livepatch-sample.o diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c new file mode 100644 index 0000000..21f159d --- /dev/null +++ b/samples/livepatch/livepatch-sample.c @@ -0,0 +1,87 @@ +/* + * livepatch-sample.c - Kernel Live Patching Sample Module + * + * Copyright (C) 2014 Seth Jennings + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +/* + * This (dumb) live patch overrides the function that prints the + * kernel boot cmdline when /proc/cmdline is read. + * + * Example: + * $ cat /proc/cmdline + * + * $ insmod livepatch-sample.ko + * $ cat /proc/cmdline + * this has been live patched + * $ echo 0 > /sys/kernel/livepatch/klp_sample/enabled + * + */ + +#include +static int livepatch_cmdline_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%s\n", "this has been live patched"); + return 0; +} + +static struct klp_func funcs[] = { + { + .old_name = "cmdline_proc_show", + .new_func = livepatch_cmdline_proc_show, + }, { } +}; + +static struct klp_object objs[] = { + { + /* name being NULL means vmlinux */ + .funcs = funcs, + }, { } +}; + +static struct klp_patch patch = { + .mod = THIS_MODULE, + .objs = objs, +}; + +static int livepatch_init(void) +{ + int ret; + + ret = klp_register_patch(&patch); + if (ret) + return ret; + ret = klp_enable_patch(&patch); + if (ret) { + WARN_ON(klp_unregister_patch(&patch)); + return ret; + } + return 0; +} + +static void livepatch_exit(void) +{ + WARN_ON(klp_disable_patch(&patch)); + WARN_ON(klp_unregister_patch(&patch)); +} + +module_init(livepatch_init); +module_exit(livepatch_exit); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From b5bfc51707f1b56b0b733980bb4fcc0562bf02d8 Mon Sep 17 00:00:00 2001 From: Li Bin Date: Fri, 19 Dec 2014 14:11:17 +0800 Subject: livepatch: move x86 specific ftrace handler code to arch/x86 The execution flow redirection related implemention in the livepatch ftrace handler is depended on the specific architecture. This patch introduces klp_arch_set_pc(like kgdb_arch_set_pc) interface to change the pt_regs. Signed-off-by: Li Bin Acked-by: Josh Poimboeuf Signed-off-by: Jiri Kosina diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h index d529db1..b5608d7 100644 --- a/arch/x86/include/asm/livepatch.h +++ b/arch/x86/include/asm/livepatch.h @@ -22,6 +22,7 @@ #define _ASM_X86_LIVEPATCH_H #include +#include #ifdef CONFIG_LIVE_PATCHING #ifndef CC_USING_FENTRY @@ -30,6 +31,10 @@ extern int klp_write_module_reloc(struct module *mod, unsigned long type, unsigned long loc, unsigned long value); +static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) +{ + regs->ip = ip; +} #else #error Live patching support is disabled; check CONFIG_LIVE_PATCHING #endif diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index f99fe18..07a2db9 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -272,7 +272,7 @@ static void notrace klp_ftrace_handler(unsigned long ip, { struct klp_func *func = ops->private; - regs->ip = (unsigned long)func->new_func; + klp_arch_set_pc(regs, (unsigned long)func->new_func); } static int klp_disable_func(struct klp_func *func) -- cgit v0.10.2 From 2c658e212ce7e40ace56d9441c8c5634d4d420e3 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 18 Dec 2014 16:12:08 +0200 Subject: spi: Remove FSF mailing addresses Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 326f479..f45e085 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 98aab45..419a782 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index c205309..e73e2b05 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, */ #include diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index dc7d2c2..5ef6638 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index ee4f91c..9a95862 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 41b5dc4..688956ff 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -12,11 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index b3707ba..5e99106 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index aee4e75..2b76492 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 41c5765..ba72347 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 79399ae..d890d30 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -16,11 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include #include diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index daf1ada..3c08444 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -28,10 +28,6 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 3bc3cba..4df8942 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -14,11 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c index e8a26f2..e51fcf9 100644 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ b/drivers/spi/spi-pxa2xx-pxadma.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 05c623c..7a9a605 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 2071f78..46ce470 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -15,11 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 37b1983..9231c34 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 237f2e7..5a56acf 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index fc29233..20e800e 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -16,11 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 1cfc906..5025011 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -14,11 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index be692ad..93dfcee 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 66a70e9..c76cc75 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 6941e04..6f97e5a 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/include/linux/spi/at86rf230.h b/include/linux/spi/at86rf230.h index b2b1afb..cd519a1 100644 --- a/include/linux/spi/at86rf230.h +++ b/include/linux/spi/at86rf230.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * * Written by: * Dmitry Eremin-Solenikov */ diff --git a/include/linux/spi/l4f00242t03.h b/include/linux/spi/l4f00242t03.h index bc8677c..e69e9b5 100644 --- a/include/linux/spi/l4f00242t03.h +++ b/include/linux/spi/l4f00242t03.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _INCLUDE_LINUX_SPI_L4F00242T03_H_ diff --git a/include/linux/spi/lms283gf05.h b/include/linux/spi/lms283gf05.h index 555d254..fdd1d1d 100644 --- a/include/linux/spi/lms283gf05.h +++ b/include/linux/spi/lms283gf05.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _INCLUDE_LINUX_SPI_LMS283GF05_H_ diff --git a/include/linux/spi/mxs-spi.h b/include/linux/spi/mxs-spi.h index 4835486..381d368 100644 --- a/include/linux/spi/mxs-spi.h +++ b/include/linux/spi/mxs-spi.h @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __LINUX_SPI_MXS_SPI_H__ diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index d5a3165..5eb56e3 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __linux_pxa2xx_spi_h #define __linux_pxa2xx_spi_h diff --git a/include/linux/spi/rspi.h b/include/linux/spi/rspi.h index e546b2c..a693188 100644 --- a/include/linux/spi/rspi.h +++ b/include/linux/spi/rspi.h @@ -11,11 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef __LINUX_SPI_RENESAS_SPI_H__ diff --git a/include/linux/spi/sh_hspi.h b/include/linux/spi/sh_hspi.h index a1121f8..aa0d440 100644 --- a/include/linux/spi/sh_hspi.h +++ b/include/linux/spi/sh_hspi.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH_HSPI_H #define SH_HSPI_H diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index a6ef2a8..6e2664a 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __LINUX_SPI_H diff --git a/include/linux/spi/tle62x0.h b/include/linux/spi/tle62x0.h index 60b5918..414c6fd 100644 --- a/include/linux/spi/tle62x0.h +++ b/include/linux/spi/tle62x0.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ struct tle62x0_pdata { diff --git a/include/linux/spi/tsc2005.h b/include/linux/spi/tsc2005.h index 8f721e4..563b3b1 100644 --- a/include/linux/spi/tsc2005.h +++ b/include/linux/spi/tsc2005.h @@ -12,11 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _LINUX_SPI_TSC2005_H -- cgit v0.10.2 From 2914e72681cdb3f310b0a0d570e9ac17b8c37d0c Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Wed, 26 Nov 2014 19:42:24 -0300 Subject: [media] media: s3c-camif: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Cc: Sylwester Nawrocki Acked-by: Sylwester Nawrocki Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index aa40c82..54479d6 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -536,24 +536,12 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&camif->slock, flags); } -static void camif_lock(struct vb2_queue *vq) -{ - struct camif_vp *vp = vb2_get_drv_priv(vq); - mutex_lock(&vp->camif->lock); -} - -static void camif_unlock(struct vb2_queue *vq) -{ - struct camif_vp *vp = vb2_get_drv_priv(vq); - mutex_unlock(&vp->camif->lock); -} - static const struct vb2_ops s3c_camif_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = camif_unlock, - .wait_finish = camif_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -1161,6 +1149,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) q->buf_struct_size = sizeof(struct camif_buffer); q->drv_priv = vp; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &vp->camif->lock; ret = vb2_queue_init(q); if (ret) -- cgit v0.10.2 From 3d0aed38342b42bc532cc16cf4bf57a863f32df3 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Wed, 26 Nov 2014 19:42:25 -0300 Subject: [media] media: ti-vpe: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Cc: Kukjin Kim Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index d628d1a..968fb63 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1913,30 +1913,19 @@ static void vpe_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); } -static void vpe_wait_prepare(struct vb2_queue *q) -{ - struct vpe_ctx *ctx = vb2_get_drv_priv(q); - vpe_unlock(ctx); -} - -static void vpe_wait_finish(struct vb2_queue *q) -{ - struct vpe_ctx *ctx = vb2_get_drv_priv(q); - vpe_lock(ctx); -} - static struct vb2_ops vpe_qops = { .queue_setup = vpe_queue_setup, .buf_prepare = vpe_buf_prepare, .buf_queue = vpe_buf_queue, - .wait_prepare = vpe_wait_prepare, - .wait_finish = vpe_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { struct vpe_ctx *ctx = priv; + struct vpe_dev *dev = ctx->dev; int ret; memset(src_vq, 0, sizeof(*src_vq)); @@ -1947,6 +1936,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &vpe_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &dev->dev_mutex; ret = vb2_queue_init(src_vq); if (ret) @@ -1960,6 +1950,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &vpe_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &dev->dev_mutex; return vb2_queue_init(dst_vq); } -- cgit v0.10.2 From 0637f054cef5b734b0b1dc5de7ee21aad6e0f441 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Wed, 26 Nov 2014 19:42:26 -0300 Subject: [media] media: exynos-gsc: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Cc: Kukjin Kim Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 0abdb17..fa572aa 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -466,18 +466,6 @@ static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq) writel(cfg, dev->regs + GSC_IRQ); } -static inline void gsc_lock(struct vb2_queue *vq) -{ - struct gsc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_lock(&ctx->gsc_dev->lock); -} - -static inline void gsc_unlock(struct vb2_queue *vq) -{ - struct gsc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_unlock(&ctx->gsc_dev->lock); -} - static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx) { unsigned long flags; diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 74e1de6..d5cffef 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -267,8 +267,8 @@ static struct vb2_ops gsc_m2m_qops = { .queue_setup = gsc_m2m_queue_setup, .buf_prepare = gsc_m2m_buf_prepare, .buf_queue = gsc_m2m_buf_queue, - .wait_prepare = gsc_unlock, - .wait_finish = gsc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .stop_streaming = gsc_m2m_stop_streaming, .start_streaming = gsc_m2m_start_streaming, }; @@ -590,6 +590,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->gsc_dev->lock; ret = vb2_queue_init(src_vq); if (ret) @@ -603,6 +604,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->gsc_dev->lock; return vb2_queue_init(dst_vq); } -- cgit v0.10.2 From 8776ff659d8f9e86850fbe432610461ab09a94a0 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Wed, 26 Nov 2014 19:42:28 -0300 Subject: [media] media: sh_veu: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index aaa1f6f..a901b62 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -242,20 +242,6 @@ static void sh_veu_job_abort(void *priv) veu->aborting = true; } -static void sh_veu_lock(void *priv) -{ - struct sh_veu_dev *veu = priv; - - mutex_lock(&veu->fop_lock); -} - -static void sh_veu_unlock(void *priv) -{ - struct sh_veu_dev *veu = priv; - - mutex_unlock(&veu->fop_lock); -} - static void sh_veu_process(struct sh_veu_dev *veu, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf) @@ -950,36 +936,28 @@ static void sh_veu_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(veu->m2m_ctx, vb); } -static void sh_veu_wait_prepare(struct vb2_queue *q) -{ - sh_veu_unlock(vb2_get_drv_priv(q)); -} - -static void sh_veu_wait_finish(struct vb2_queue *q) -{ - sh_veu_lock(vb2_get_drv_priv(q)); -} - static const struct vb2_ops sh_veu_qops = { .queue_setup = sh_veu_queue_setup, .buf_prepare = sh_veu_buf_prepare, .buf_queue = sh_veu_buf_queue, - .wait_prepare = sh_veu_wait_prepare, - .wait_finish = sh_veu_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { + struct sh_veu_dev *veu = priv; int ret; memset(src_vq, 0, sizeof(*src_vq)); src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->io_modes = VB2_MMAP | VB2_USERPTR; - src_vq->drv_priv = priv; + src_vq->drv_priv = veu; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &sh_veu_qops; src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->lock = &veu->fop_lock; ret = vb2_queue_init(src_vq); if (ret < 0) @@ -988,10 +966,11 @@ static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq, memset(dst_vq, 0, sizeof(*dst_vq)); dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; - dst_vq->drv_priv = priv; + dst_vq->drv_priv = veu; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &sh_veu_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->lock = &veu->fop_lock; return vb2_queue_init(dst_vq); } -- cgit v0.10.2 From c747404dbf2dcc0d8cb5d2e8aee5810b6ebba496 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Wed, 26 Nov 2014 19:42:30 -0300 Subject: [media] media: s5p-tv: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Cc: Kyungmin Park Cc: Tomasz Stanislawski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index b4d2696..72d4f2e 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -926,22 +926,6 @@ static void buf_queue(struct vb2_buffer *vb) mxr_dbg(mdev, "queuing buffer\n"); } -static void wait_lock(struct vb2_queue *vq) -{ - struct mxr_layer *layer = vb2_get_drv_priv(vq); - - mxr_dbg(layer->mdev, "%s\n", __func__); - mutex_lock(&layer->mutex); -} - -static void wait_unlock(struct vb2_queue *vq) -{ - struct mxr_layer *layer = vb2_get_drv_priv(vq); - - mxr_dbg(layer->mdev, "%s\n", __func__); - mutex_unlock(&layer->mutex); -} - static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct mxr_layer *layer = vb2_get_drv_priv(vq); @@ -1040,8 +1024,8 @@ static void stop_streaming(struct vb2_queue *vq) static struct vb2_ops mxr_video_qops = { .queue_setup = queue_setup, .buf_queue = buf_queue, - .wait_prepare = wait_unlock, - .wait_finish = wait_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -1122,6 +1106,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, .ops = &mxr_video_qops, .min_buffers_needed = 1, .mem_ops = &vb2_dma_contig_memops, + .lock = &layer->mutex, }; return layer; -- cgit v0.10.2 From 654a731be1a0b6f606f3f3d12b50db08f2ae3c34 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Wed, 26 Nov 2014 19:42:32 -0300 Subject: [media] media: s5p-mfc: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Cc: Kyungmin Park Cc: Kamil Debski Cc: Jeongtae Park Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index fbfdf03..8e44a59 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -810,6 +810,7 @@ static int s5p_mfc_open(struct file *file) q = &ctx->vq_dst; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; q->drv_priv = &ctx->fh; + q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; q->ops = get_dec_queue_ops(); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index c6c3452..9b14827 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -944,22 +944,6 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, return 0; } -static void s5p_mfc_unlock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_unlock(&dev->mfc_mutex); -} - -static void s5p_mfc_lock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_lock(&dev->mfc_mutex); -} - static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; @@ -1107,8 +1091,8 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static struct vb2_ops s5p_mfc_dec_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = s5p_mfc_unlock, - .wait_finish = s5p_mfc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .start_streaming = s5p_mfc_start_streaming, .stop_streaming = s5p_mfc_stop_streaming, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index bd64f1d..ac12f65 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1867,22 +1867,6 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, return 0; } -static void s5p_mfc_unlock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_unlock(&dev->mfc_mutex); -} - -static void s5p_mfc_lock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_lock(&dev->mfc_mutex); -} - static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; @@ -2052,8 +2036,8 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static struct vb2_ops s5p_mfc_enc_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = s5p_mfc_unlock, - .wait_finish = s5p_mfc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .buf_prepare = s5p_mfc_buf_prepare, .start_streaming = s5p_mfc_start_streaming, -- cgit v0.10.2 From 6c80f87ed4483bff0ecbf4455a1b09e7f950e9ab Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sun, 21 Dec 2014 08:18:25 -0800 Subject: x86, mce: Improve timeout error messages There are four different possible types of timeouts. Distinguish them in the logs to help debug them. Signed-off-by: Andy Lutomirski Link: http://lkml.kernel.org/r/0fa6d2653a54a01c48b43a3583caf950ea99606e.1419178397.git.luto@amacapital.net Signed-off-by: Borislav Petkov diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index d2c6116..323e02c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -311,7 +311,7 @@ static void wait_for_panic(void) panic("Panicing machine check CPU died"); } -static void mce_panic(char *msg, struct mce *final, char *exp) +static void mce_panic(const char *msg, struct mce *final, char *exp) { int i, apei_err = 0; @@ -735,7 +735,7 @@ static atomic_t mce_callin; /* * Check if a timeout waiting for other CPUs happened. */ -static int mce_timed_out(u64 *t) +static int mce_timed_out(u64 *t, const char *msg) { /* * The others already did panic for some reason. @@ -750,8 +750,7 @@ static int mce_timed_out(u64 *t) goto out; if ((s64)*t < SPINUNIT) { if (mca_cfg.tolerant <= 1) - mce_panic("Timeout synchronizing machine check over CPUs", - NULL, NULL); + mce_panic(msg, NULL, NULL); cpu_missing = 1; return 1; } @@ -867,7 +866,8 @@ static int mce_start(int *no_way_out) * Wait for everyone. */ while (atomic_read(&mce_callin) != cpus) { - if (mce_timed_out(&timeout)) { + if (mce_timed_out(&timeout, + "Timeout: Not all CPUs entered broadcast exception handler")) { atomic_set(&global_nwo, 0); return -1; } @@ -892,7 +892,8 @@ static int mce_start(int *no_way_out) * only seen by one CPU before cleared, avoiding duplicates. */ while (atomic_read(&mce_executing) < order) { - if (mce_timed_out(&timeout)) { + if (mce_timed_out(&timeout, + "Timeout: Subject CPUs unable to finish machine check processing")) { atomic_set(&global_nwo, 0); return -1; } @@ -936,7 +937,8 @@ static int mce_end(int order) * loops. */ while (atomic_read(&mce_executing) <= cpus) { - if (mce_timed_out(&timeout)) + if (mce_timed_out(&timeout, + "Timeout: Monarch CPU unable to finish machine check processing")) goto reset; ndelay(SPINUNIT); } @@ -949,7 +951,8 @@ static int mce_end(int order) * Subject: Wait for Monarch to finish. */ while (atomic_read(&mce_executing) != 0) { - if (mce_timed_out(&timeout)) + if (mce_timed_out(&timeout, + "Timeout: Monarch CPU did not finish machine check processing")) goto reset; ndelay(SPINUNIT); } -- cgit v0.10.2 From 6fd753572c34a2469b41813aa6f376569cf2681f Mon Sep 17 00:00:00 2001 From: Arnaud Ebalard Date: Tue, 16 Dec 2014 22:20:50 +0100 Subject: regulator: isl9305: deprecate use of isl in compatible string for isil "isil" and "isl" prefixes are used at various locations inside the kernel to reference Intersil corporation. This patch is part of a series fixing those locations were "isl" is used in compatible strings to use the now expected "isil" prefix instead (NASDAQ symbol for Intersil and most used version). The old compatible string is kept for backward compatibility. Signed-off-by: Arnaud Ebalard Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/isl9305.txt b/Documentation/devicetree/bindings/regulator/isl9305.txt index a626fc1..d6e7c9e 100644 --- a/Documentation/devicetree/bindings/regulator/isl9305.txt +++ b/Documentation/devicetree/bindings/regulator/isl9305.txt @@ -2,7 +2,7 @@ Intersil ISL9305/ISL9305H voltage regulator Required properties: -- compatible: "isl,isl9305" or "isl,isl9305h" +- compatible: "isil,isl9305" or "isil,isl9305h" - reg: I2C slave address, usually 0x68. - regulators: A node that houses a sub-node for each regulator within the device. Each sub-node is identified using the node's name, with valid @@ -19,7 +19,7 @@ Optional properties: Example pmic: isl9305@68 { - compatible = "isl,isl9305"; + compatible = "isil,isl9305"; reg = <0x68>; VINDCD1-supply = <&system_power>; diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 92fefd9..6e3a15f 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -177,8 +177,10 @@ static int isl9305_i2c_probe(struct i2c_client *i2c, #ifdef CONFIG_OF static const struct of_device_id isl9305_dt_ids[] = { - { .compatible = "isl,isl9305" }, - { .compatible = "isl,isl9305h" }, + { .compatible = "isl,isl9305" }, /* for backward compat., don't use */ + { .compatible = "isil,isl9305" }, + { .compatible = "isl,isl9305h" }, /* for backward compat., don't use */ + { .compatible = "isil,isl9305h" }, {}, }; #endif -- cgit v0.10.2 From ba5295e55dd941425b10924f4f5c7af6eac4a1cb Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 9 Dec 2014 09:28:09 +0100 Subject: ASoC: pcm512x: Also support PCM514x devices Signed-off-by: Peter Rosin Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt index faff75e..98e0d34 100644 --- a/Documentation/devicetree/bindings/sound/pcm512x.txt +++ b/Documentation/devicetree/bindings/sound/pcm512x.txt @@ -5,7 +5,8 @@ on the board). Required properties: - - compatible : One of "ti,pcm5121" or "ti,pcm5122" + - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or + "ti,pcm5142" - reg : the I2C address of the device for I2C, the chip select number for SPI. diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index d0547fa..dcdfac0 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -46,6 +46,8 @@ static int pcm512x_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id pcm512x_i2c_id[] = { { "pcm5121", }, { "pcm5122", }, + { "pcm5141", }, + { "pcm5142", }, { } }; MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); @@ -53,6 +55,8 @@ MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); static const struct of_device_id pcm512x_of_match[] = { { .compatible = "ti,pcm5121", }, { .compatible = "ti,pcm5122", }, + { .compatible = "ti,pcm5141", }, + { .compatible = "ti,pcm5142", }, { } }; MODULE_DEVICE_TABLE(of, pcm512x_of_match); diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index f297058..7b64a9c 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -43,6 +43,8 @@ static int pcm512x_spi_remove(struct spi_device *spi) static const struct spi_device_id pcm512x_spi_id[] = { { "pcm5121", }, { "pcm5122", }, + { "pcm5141", }, + { "pcm5142", }, { }, }; MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); @@ -50,6 +52,8 @@ MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); static const struct of_device_id pcm512x_of_match[] = { { .compatible = "ti,pcm5121", }, { .compatible = "ti,pcm5122", }, + { .compatible = "ti,pcm5141", }, + { .compatible = "ti,pcm5142", }, { } }; MODULE_DEVICE_TABLE(of, pcm512x_of_match); -- cgit v0.10.2 From 5129ad6e4e699924f7bc77d3d70ffc011a9024b8 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Dec 2014 09:10:44 +0800 Subject: ASoC: Intel: fix sparse non static symbol warnings Fixes the following sparse warnings: sound/soc/intel/sst/sst_acpi.c:248:5: warning: symbol 'sst_acpi_probe' was not declared. Should it be static? sound/soc/intel/sst/sst_acpi.c:335:5: warning: symbol 'sst_acpi_remove' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index f1180ff..df2b5cc 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -245,7 +245,7 @@ static struct sst_machines *sst_acpi_find_machine( return NULL; } -int sst_acpi_probe(struct platform_device *pdev) +static int sst_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret = 0; @@ -332,7 +332,7 @@ do_sst_cleanup: * This function is called by OS when a device is unloaded * This frees the interrupt etc */ -int sst_acpi_remove(struct platform_device *pdev) +static int sst_acpi_remove(struct platform_device *pdev) { struct intel_sst_drv *ctx; -- cgit v0.10.2 From 9e862375c5420a329521c458a3c808c127e9038f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 9 Dec 2014 20:21:30 +0000 Subject: spi: Add new driver for STMicroelectronics' SPI Controller This patch adds support for the SPI portion of ST's SSC device. Signed-off-by: Lee Jones Signed-off-by: Mark Brown diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9982998..000f774 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -503,6 +503,13 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_ST_SSC4 + tristate "STMicroelectronics SPI SSC-based driver" + depends on ARCH_STI + help + STMicroelectronics SoCs support for SPI. If you say yes to + this option, support will be included for the SSC driven SPI. + config SPI_SUN4I tristate "Allwinner A10 SoCs SPI controller" depends on ARCH_SUNXI || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6b9d2ac..c33577b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c new file mode 100644 index 0000000..8f8770a --- /dev/null +++ b/drivers/spi/spi-st-ssc4.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2008-2014 STMicroelectronics Limited + * + * Author: Angus Clark + * Patrice Chotard + * Lee Jones + * + * SPI master mode controller driver, used in STMicroelectronics devices. + * + * May be copied or modified under the terms of the GNU General Public + * License Version 2.0 only. See linux/COPYING for more information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SSC registers */ +#define SSC_BRG 0x000 +#define SSC_TBUF 0x004 +#define SSC_RBUF 0x008 +#define SSC_CTL 0x00C +#define SSC_IEN 0x010 +#define SSC_I2C 0x018 + +/* SSC Control */ +#define SSC_CTL_DATA_WIDTH_9 0x8 +#define SSC_CTL_DATA_WIDTH_MSK 0xf +#define SSC_CTL_BM 0xf +#define SSC_CTL_HB BIT(4) +#define SSC_CTL_PH BIT(5) +#define SSC_CTL_PO BIT(6) +#define SSC_CTL_SR BIT(7) +#define SSC_CTL_MS BIT(8) +#define SSC_CTL_EN BIT(9) +#define SSC_CTL_LPB BIT(10) +#define SSC_CTL_EN_TX_FIFO BIT(11) +#define SSC_CTL_EN_RX_FIFO BIT(12) +#define SSC_CTL_EN_CLST_RX BIT(13) + +/* SSC Interrupt Enable */ +#define SSC_IEN_TEEN BIT(2) + +#define FIFO_SIZE 8 + +struct spi_st { + /* SSC SPI Controller */ + void __iomem *base; + struct clk *clk; + struct device *dev; + + /* SSC SPI current transaction */ + const u8 *tx_ptr; + u8 *rx_ptr; + u16 bytes_per_word; + unsigned int words_remaining; + unsigned int baud; + struct completion done; +}; + +static int spi_st_clk_enable(struct spi_st *spi_st) +{ + /* + * Current platforms use one of the core clocks for SPI and I2C. + * If we attempt to disable the clock, the system will hang. + * + * TODO: Remove this when platform supports power domains. + */ + return 0; + + return clk_prepare_enable(spi_st->clk); +} + +static void spi_st_clk_disable(struct spi_st *spi_st) +{ + /* + * Current platforms use one of the core clocks for SPI and I2C. + * If we attempt to disable the clock, the system will hang. + * + * TODO: Remove this when platform supports power domains. + */ + return; + + clk_disable_unprepare(spi_st->clk); +} + +/* Load the TX FIFO */ +static void ssc_write_tx_fifo(struct spi_st *spi_st) +{ + unsigned int count, i; + uint32_t word = 0; + + if (spi_st->words_remaining > FIFO_SIZE) + count = FIFO_SIZE; + else + count = spi_st->words_remaining; + + for (i = 0; i < count; i++) { + if (spi_st->tx_ptr) { + if (spi_st->bytes_per_word == 1) { + word = *spi_st->tx_ptr++; + } else { + word = *spi_st->tx_ptr++; + word = *spi_st->tx_ptr++ | (word << 8); + } + } + writel_relaxed(word, spi_st->base + SSC_TBUF); + } +} + +/* Read the RX FIFO */ +static void ssc_read_rx_fifo(struct spi_st *spi_st) +{ + unsigned int count, i; + uint32_t word = 0; + + if (spi_st->words_remaining > FIFO_SIZE) + count = FIFO_SIZE; + else + count = spi_st->words_remaining; + + for (i = 0; i < count; i++) { + word = readl_relaxed(spi_st->base + SSC_RBUF); + + if (spi_st->rx_ptr) { + if (spi_st->bytes_per_word == 1) { + *spi_st->rx_ptr++ = (uint8_t)word; + } else { + *spi_st->rx_ptr++ = (word >> 8); + *spi_st->rx_ptr++ = word & 0xff; + } + } + } + spi_st->words_remaining -= count; +} + +static int spi_st_transfer_one(struct spi_master *master, + struct spi_device *spi, struct spi_transfer *t) +{ + struct spi_st *spi_st = spi_master_get_devdata(master); + uint32_t ctl = 0; + + /* Setup transfer */ + spi_st->tx_ptr = t->tx_buf; + spi_st->rx_ptr = t->rx_buf; + + if (spi->bits_per_word > 8) { + /* + * Anything greater than 8 bits-per-word requires 2 + * bytes-per-word in the RX/TX buffers + */ + spi_st->bytes_per_word = 2; + spi_st->words_remaining = t->len / 2; + + } else if (spi->bits_per_word == 8 && !(t->len & 0x1)) { + /* + * If transfer is even-length, and 8 bits-per-word, then + * implement as half-length 16 bits-per-word transfer + */ + spi_st->bytes_per_word = 2; + spi_st->words_remaining = t->len / 2; + + /* Set SSC_CTL to 16 bits-per-word */ + ctl = readl_relaxed(spi_st->base + SSC_CTL); + writel_relaxed((ctl | 0xf), spi_st->base + SSC_CTL); + + readl_relaxed(spi_st->base + SSC_RBUF); + + } else { + spi_st->bytes_per_word = 1; + spi_st->words_remaining = t->len; + } + + reinit_completion(&spi_st->done); + + /* Start transfer by writing to the TX FIFO */ + ssc_write_tx_fifo(spi_st); + writel_relaxed(SSC_IEN_TEEN, spi_st->base + SSC_IEN); + + /* Wait for transfer to complete */ + wait_for_completion(&spi_st->done); + + /* Restore SSC_CTL if necessary */ + if (ctl) + writel_relaxed(ctl, spi_st->base + SSC_CTL); + + spi_finalize_current_transfer(spi->master); + + return t->len; +} + +static void spi_st_cleanup(struct spi_device *spi) +{ + int cs = spi->cs_gpio; + + if (gpio_is_valid(cs)) + devm_gpio_free(&spi->dev, cs); +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) +static int spi_st_setup(struct spi_device *spi) +{ + struct spi_st *spi_st = spi_master_get_devdata(spi->master); + u32 spi_st_clk, sscbrg, var; + u32 hz = spi->max_speed_hz; + int cs = spi->cs_gpio; + int ret; + + if (spi->mode & ~MODEBITS) { + dev_err(&spi->dev, "unsupported mode bits 0x%x\n", + spi->mode & ~MODEBITS); + return -EINVAL; + } + + if (!hz) { + dev_err(&spi->dev, "max_speed_hz unspecified\n"); + return -EINVAL; + } + + if (!gpio_is_valid(cs)) { + dev_err(&spi->dev, "%d is not a valid gpio\n", cs); + return -EINVAL; + } + + if (devm_gpio_request(&spi->dev, cs, dev_name(&spi->dev))) { + dev_err(&spi->dev, "could not request gpio:%d\n", cs); + return -EINVAL; + } + + ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); + if (ret) + return ret; + + spi_st_clk = clk_get_rate(spi_st->clk); + + /* Set SSC_BRF */ + sscbrg = spi_st_clk / (2 * hz); + if (sscbrg < 0x07 || sscbrg > BIT(16)) { + dev_err(&spi->dev, + "baudrate %d outside valid range %d\n", sscbrg, hz); + return -EINVAL; + } + + spi_st->baud = spi_st_clk / (2 * sscbrg); + if (sscbrg == BIT(16)) /* 16-bit counter wraps */ + sscbrg = 0x0; + + writel_relaxed(sscbrg, spi_st->base + SSC_BRG); + + dev_dbg(&spi->dev, + "setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n", + hz, spi_st->baud, sscbrg); + + /* Set SSC_CTL and enable SSC */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var |= SSC_CTL_MS; + + if (spi->mode & SPI_CPOL) + var |= SSC_CTL_PO; + else + var &= ~SSC_CTL_PO; + + if (spi->mode & SPI_CPHA) + var |= SSC_CTL_PH; + else + var &= ~SSC_CTL_PH; + + if ((spi->mode & SPI_LSB_FIRST) == 0) + var |= SSC_CTL_HB; + else + var &= ~SSC_CTL_HB; + + if (spi->mode & SPI_LOOP) + var |= SSC_CTL_LPB; + else + var &= ~SSC_CTL_LPB; + + var &= ~SSC_CTL_DATA_WIDTH_MSK; + var |= (spi->bits_per_word - 1); + + var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO; + var |= SSC_CTL_EN; + + writel_relaxed(var, spi_st->base + SSC_CTL); + + /* Clear the status register */ + readl_relaxed(spi_st->base + SSC_RBUF); + + return 0; +} + +/* Interrupt fired when TX shift register becomes empty */ +static irqreturn_t spi_st_irq(int irq, void *dev_id) +{ + struct spi_st *spi_st = (struct spi_st *)dev_id; + + /* Read RX FIFO */ + ssc_read_rx_fifo(spi_st); + + /* Fill TX FIFO */ + if (spi_st->words_remaining) { + ssc_write_tx_fifo(spi_st); + } else { + /* TX/RX complete */ + writel_relaxed(0x0, spi_st->base + SSC_IEN); + /* + * read SSC_IEN to ensure that this bit is set + * before re-enabling interrupt + */ + readl(spi_st->base + SSC_IEN); + complete(&spi_st->done); + } + + return IRQ_HANDLED; +} + +static int spi_st_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spi_master *master; + struct resource *res; + struct spi_st *spi_st; + int irq, ret = 0; + u32 var; + + master = spi_alloc_master(&pdev->dev, sizeof(*spi_st)); + if (!master) + return -ENOMEM; + + master->dev.of_node = np; + master->mode_bits = MODEBITS; + master->setup = spi_st_setup; + master->cleanup = spi_st_cleanup; + master->transfer_one = spi_st_transfer_one; + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->auto_runtime_pm = true; + master->bus_num = pdev->id; + spi_st = spi_master_get_devdata(master); + + spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); + if (IS_ERR(spi_st->clk)) { + dev_err(&pdev->dev, "Unable to request clock\n"); + return PTR_ERR(spi_st->clk); + } + + ret = spi_st_clk_enable(spi_st); + if (ret) + return ret; + + init_completion(&spi_st->done); + + /* Get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + spi_st->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(spi_st->base)) { + ret = PTR_ERR(spi_st->base); + goto clk_disable; + } + + /* Disable I2C and Reset SSC */ + writel_relaxed(0x0, spi_st->base + SSC_I2C); + var = readw_relaxed(spi_st->base + SSC_CTL); + var |= SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + + udelay(1); + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + + /* Set SSC into slave mode before reconfiguring PIO pins */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_MS; + writel_relaxed(var, spi_st->base + SSC_CTL); + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + dev_err(&pdev->dev, "IRQ missing or invalid\n"); + ret = -EINVAL; + goto clk_disable; + } + + ret = devm_request_irq(&pdev->dev, irq, spi_st_irq, 0, + pdev->name, spi_st); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq %d\n", irq); + goto clk_disable; + } + + /* by default the device is on */ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + platform_set_drvdata(pdev, master); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "Failed to register master\n"); + goto clk_disable; + } + + return 0; + +clk_disable: + spi_st_clk_disable(spi_st); + + return ret; +} + +static int spi_st_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct spi_st *spi_st = spi_master_get_devdata(master); + + spi_st_clk_disable(spi_st); + + pinctrl_pm_select_sleep_state(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int spi_st_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_master_get_devdata(master); + + writel_relaxed(0, spi_st->base + SSC_IEN); + pinctrl_pm_select_sleep_state(dev); + + spi_st_clk_disable(spi_st); + + return 0; +} + +static int spi_st_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_master_get_devdata(master); + int ret; + + ret = spi_st_clk_enable(spi_st); + pinctrl_pm_select_default_state(dev); + + return ret; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int spi_st_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + return pm_runtime_force_suspend(dev); +} + +static int spi_st_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_resume(master); + if (ret) + return ret; + + return pm_runtime_force_resume(dev); +} +#endif + +static const struct dev_pm_ops spi_st_pm = { + SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume) + SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL) +}; + +static struct of_device_id stm_spi_match[] = { + { .compatible = "st,comms-ssc4-spi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm_spi_match); + +static struct platform_driver spi_st_driver = { + .driver = { + .name = "spi-st", + .pm = &spi_st_pm, + .of_match_table = of_match_ptr(stm_spi_match), + }, + .probe = spi_st_probe, + .remove = spi_st_remove, +}; +module_platform_driver(spi_st_driver); + +MODULE_AUTHOR("Patrice Chotard "); +MODULE_DESCRIPTION("STM SSC SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From f5bac70f4fec1fdc7798f025edd5666c17bcf51f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 9 Dec 2014 20:21:31 +0000 Subject: spi: st: Provide Device Tree binding documentation This patch adds DT documentation for the SPI portion of ST's SSC device. Signed-off-by: Lee Jones Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/spi/spi-st-ssc.txt b/Documentation/devicetree/bindings/spi/spi-st-ssc.txt new file mode 100644 index 0000000..fe54959 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-st-ssc.txt @@ -0,0 +1,40 @@ +STMicroelectronics SSC (SPI) Controller +--------------------------------------- + +Required properties: +- compatible : "st,comms-ssc4-spi" +- reg : Offset and length of the device's register set +- interrupts : The interrupt specifier +- clock-names : Must contain "ssc" +- clocks : Must contain an entry for each name in clock-names + See ../clk/* +- pinctrl-names : Uses "default", can use "sleep" if provided + See ../pinctrl/pinctrl-binding.txt + +Optional properties: +- cs-gpios : List of GPIO chip selects + See ../spi/spi-bus.txt + +Child nodes represent devices on the SPI bus + See ../spi/spi-bus.txt + +Example: + spi@9840000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9840000 0x110>; + interrupts = ; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + pinctrl-0 = <&pinctrl_spi0_default>; + pinctrl-names = "default"; + cs-gpios = <&pio17 5 0>; + #address-cells = <1>; + #size-cells = <0>; + + st95hf@0{ + compatible = "st,st95hf"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + }; + }; -- cgit v0.10.2 From 3d8c0d749da326310a525d19e1a7aef83ae872b3 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Mon, 8 Dec 2014 15:52:29 +0200 Subject: spi: add support for DLN-2 USB-SPI adapter This adds support for Diolan DLN2 USB-SPI adapter. Information about the USB protocol interface can be found in the Programmer's Reference Manual [1], see section 5.4.6 for the SPI master module commands and responses. [1] https://www.diolan.com/downloads/dln-api-manual.pdf Signed-off-by: Laurentiu Palcu Signed-off-by: Mark Brown diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9982998..f60f37c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -185,6 +185,16 @@ config SPI_DAVINCI help SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules. +config SPI_DLN2 + tristate "Diolan DLN-2 USB SPI adapter" + depends on MFD_DLN2 + help + If you say yes to this option, support will be included for Diolan + DLN2, a USB to SPI interface. + + This driver can also be built as a module. If so, the module + will be called spi-dln2. + config SPI_EFM32 tristate "EFM32 SPI controller" depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6b9d2ac..df5e23c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o +obj-$(CONFIG_SPI_DLN2) += spi-dln2.o obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c new file mode 100644 index 0000000..7b35454 --- /dev/null +++ b/drivers/spi/spi-dln2.c @@ -0,0 +1,890 @@ +/* + * Driver for the Diolan DLN-2 USB-SPI adapter + * + * Copyright (c) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DLN2_SPI_MODULE_ID 0x02 +#define DLN2_SPI_CMD(cmd) DLN2_CMD(cmd, DLN2_SPI_MODULE_ID) + +/* SPI commands */ +#define DLN2_SPI_GET_PORT_COUNT DLN2_SPI_CMD(0x00) +#define DLN2_SPI_ENABLE DLN2_SPI_CMD(0x11) +#define DLN2_SPI_DISABLE DLN2_SPI_CMD(0x12) +#define DLN2_SPI_IS_ENABLED DLN2_SPI_CMD(0x13) +#define DLN2_SPI_SET_MODE DLN2_SPI_CMD(0x14) +#define DLN2_SPI_GET_MODE DLN2_SPI_CMD(0x15) +#define DLN2_SPI_SET_FRAME_SIZE DLN2_SPI_CMD(0x16) +#define DLN2_SPI_GET_FRAME_SIZE DLN2_SPI_CMD(0x17) +#define DLN2_SPI_SET_FREQUENCY DLN2_SPI_CMD(0x18) +#define DLN2_SPI_GET_FREQUENCY DLN2_SPI_CMD(0x19) +#define DLN2_SPI_READ_WRITE DLN2_SPI_CMD(0x1A) +#define DLN2_SPI_READ DLN2_SPI_CMD(0x1B) +#define DLN2_SPI_WRITE DLN2_SPI_CMD(0x1C) +#define DLN2_SPI_SET_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x20) +#define DLN2_SPI_GET_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x21) +#define DLN2_SPI_SET_DELAY_AFTER_SS DLN2_SPI_CMD(0x22) +#define DLN2_SPI_GET_DELAY_AFTER_SS DLN2_SPI_CMD(0x23) +#define DLN2_SPI_SET_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x24) +#define DLN2_SPI_GET_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x25) +#define DLN2_SPI_SET_SS DLN2_SPI_CMD(0x26) +#define DLN2_SPI_GET_SS DLN2_SPI_CMD(0x27) +#define DLN2_SPI_RELEASE_SS DLN2_SPI_CMD(0x28) +#define DLN2_SPI_SS_VARIABLE_ENABLE DLN2_SPI_CMD(0x2B) +#define DLN2_SPI_SS_VARIABLE_DISABLE DLN2_SPI_CMD(0x2C) +#define DLN2_SPI_SS_VARIABLE_IS_ENABLED DLN2_SPI_CMD(0x2D) +#define DLN2_SPI_SS_AAT_ENABLE DLN2_SPI_CMD(0x2E) +#define DLN2_SPI_SS_AAT_DISABLE DLN2_SPI_CMD(0x2F) +#define DLN2_SPI_SS_AAT_IS_ENABLED DLN2_SPI_CMD(0x30) +#define DLN2_SPI_SS_BETWEEN_FRAMES_ENABLE DLN2_SPI_CMD(0x31) +#define DLN2_SPI_SS_BETWEEN_FRAMES_DISABLE DLN2_SPI_CMD(0x32) +#define DLN2_SPI_SS_BETWEEN_FRAMES_IS_ENABLED DLN2_SPI_CMD(0x33) +#define DLN2_SPI_SET_CPHA DLN2_SPI_CMD(0x34) +#define DLN2_SPI_GET_CPHA DLN2_SPI_CMD(0x35) +#define DLN2_SPI_SET_CPOL DLN2_SPI_CMD(0x36) +#define DLN2_SPI_GET_CPOL DLN2_SPI_CMD(0x37) +#define DLN2_SPI_SS_MULTI_ENABLE DLN2_SPI_CMD(0x38) +#define DLN2_SPI_SS_MULTI_DISABLE DLN2_SPI_CMD(0x39) +#define DLN2_SPI_SS_MULTI_IS_ENABLED DLN2_SPI_CMD(0x3A) +#define DLN2_SPI_GET_SUPPORTED_MODES DLN2_SPI_CMD(0x40) +#define DLN2_SPI_GET_SUPPORTED_CPHA_VALUES DLN2_SPI_CMD(0x41) +#define DLN2_SPI_GET_SUPPORTED_CPOL_VALUES DLN2_SPI_CMD(0x42) +#define DLN2_SPI_GET_SUPPORTED_FRAME_SIZES DLN2_SPI_CMD(0x43) +#define DLN2_SPI_GET_SS_COUNT DLN2_SPI_CMD(0x44) +#define DLN2_SPI_GET_MIN_FREQUENCY DLN2_SPI_CMD(0x45) +#define DLN2_SPI_GET_MAX_FREQUENCY DLN2_SPI_CMD(0x46) +#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x47) +#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x48) +#define DLN2_SPI_GET_MIN_DELAY_AFTER_SS DLN2_SPI_CMD(0x49) +#define DLN2_SPI_GET_MAX_DELAY_AFTER_SS DLN2_SPI_CMD(0x4A) +#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4B) +#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4C) + +#define DLN2_SPI_MAX_XFER_SIZE 256 +#define DLN2_SPI_BUF_SIZE (DLN2_SPI_MAX_XFER_SIZE + 16) +#define DLN2_SPI_ATTR_LEAVE_SS_LOW BIT(0) +#define DLN2_TRANSFERS_WAIT_COMPLETE 1 +#define DLN2_TRANSFERS_CANCEL 0 +#define DLN2_RPM_AUTOSUSPEND_TIMEOUT 2000 + +struct dln2_spi { + struct platform_device *pdev; + struct spi_master *master; + u8 port; + + /* + * This buffer will be used mainly for read/write operations. Since + * they're quite large, we cannot use the stack. Protection is not + * needed because all SPI communication is serialized by the SPI core. + */ + void *buf; + + u8 bpw; + u32 speed; + u16 mode; + u8 cs; +}; + +/* + * Enable/Disable SPI module. The disable command will wait for transfers to + * complete first. + */ +static int dln2_spi_enable(struct dln2_spi *dln2, bool enable) +{ + int ret; + u16 cmd; + struct { + u8 port; + u8 wait_for_completion; + } tx; + unsigned len = sizeof(tx); + + tx.port = dln2->port; + + if (enable) { + cmd = DLN2_SPI_ENABLE; + len -= sizeof(tx.wait_for_completion); + } else { + tx.wait_for_completion = DLN2_TRANSFERS_WAIT_COMPLETE; + cmd = DLN2_SPI_DISABLE; + } + + ret = dln2_transfer_tx(dln2->pdev, cmd, &tx, len); + if (ret < 0) + return ret; + + return 0; +} + +/* + * Select/unselect multiple CS lines. The selected lines will be automatically + * toggled LOW/HIGH by the board firmware during transfers, provided they're + * enabled first. + * + * Ex: cs_mask = 0x03 -> CS0 & CS1 will be selected and the next WR/RD operation + * will toggle the lines LOW/HIGH automatically. + */ +static int dln2_spi_cs_set(struct dln2_spi *dln2, u8 cs_mask) +{ + struct { + u8 port; + u8 cs; + } tx; + + tx.port = dln2->port; + + /* + * According to Diolan docs, "a slave device can be selected by changing + * the corresponding bit value to 0". The rest must be set to 1. Hence + * the bitwise NOT in front. + */ + tx.cs = ~cs_mask; + + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_SS, &tx, sizeof(tx)); +} + +/* + * Select one CS line. The other lines will be un-selected. + */ +static int dln2_spi_cs_set_one(struct dln2_spi *dln2, u8 cs) +{ + return dln2_spi_cs_set(dln2, BIT(cs)); +} + +/* + * Enable/disable CS lines for usage. The module has to be disabled first. + */ +static int dln2_spi_cs_enable(struct dln2_spi *dln2, u8 cs_mask, bool enable) +{ + struct { + u8 port; + u8 cs; + } tx; + u16 cmd; + + tx.port = dln2->port; + tx.cs = cs_mask; + cmd = enable ? DLN2_SPI_SS_MULTI_ENABLE : DLN2_SPI_SS_MULTI_DISABLE; + + return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx)); +} + +static int dln2_spi_cs_enable_all(struct dln2_spi *dln2, bool enable) +{ + u8 cs_mask = GENMASK(dln2->master->num_chipselect - 1, 0); + + return dln2_spi_cs_enable(dln2, cs_mask, enable); +} + +static int dln2_spi_get_cs_num(struct dln2_spi *dln2, u16 *cs_num) +{ + int ret; + struct { + u8 port; + } tx; + struct { + __le16 cs_count; + } rx; + unsigned rx_len = sizeof(rx); + + tx.port = dln2->port; + ret = dln2_transfer(dln2->pdev, DLN2_SPI_GET_SS_COUNT, &tx, sizeof(tx), + &rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx)) + return -EPROTO; + + *cs_num = le16_to_cpu(rx.cs_count); + + dev_dbg(&dln2->pdev->dev, "cs_num = %d\n", *cs_num); + + return 0; +} + +static int dln2_spi_get_speed(struct dln2_spi *dln2, u16 cmd, u32 *freq) +{ + int ret; + struct { + u8 port; + } tx; + struct { + __le32 speed; + } rx; + unsigned rx_len = sizeof(rx); + + tx.port = dln2->port; + + ret = dln2_transfer(dln2->pdev, cmd, &tx, sizeof(tx), &rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx)) + return -EPROTO; + + *freq = le32_to_cpu(rx.speed); + + return 0; +} + +/* + * Get bus min/max frequencies. + */ +static int dln2_spi_get_speed_range(struct dln2_spi *dln2, u32 *fmin, u32 *fmax) +{ + int ret; + + ret = dln2_spi_get_speed(dln2, DLN2_SPI_GET_MIN_FREQUENCY, fmin); + if (ret < 0) + return ret; + + ret = dln2_spi_get_speed(dln2, DLN2_SPI_GET_MAX_FREQUENCY, fmax); + if (ret < 0) + return ret; + + dev_dbg(&dln2->pdev->dev, "freq_min = %d, freq_max = %d\n", + *fmin, *fmax); + + return 0; +} + +/* + * Set the bus speed. The module will automatically round down to the closest + * available frequency and returns it. The module has to be disabled first. + */ +static int dln2_spi_set_speed(struct dln2_spi *dln2, u32 speed) +{ + int ret; + struct { + u8 port; + __le32 speed; + } __packed tx; + struct { + __le32 speed; + } rx; + int rx_len = sizeof(rx); + + tx.port = dln2->port; + tx.speed = cpu_to_le32(speed); + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_SET_FREQUENCY, &tx, sizeof(tx), + &rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx)) + return -EPROTO; + + return 0; +} + +/* + * Change CPOL & CPHA. The module has to be disabled first. + */ +static int dln2_spi_set_mode(struct dln2_spi *dln2, u8 mode) +{ + struct { + u8 port; + u8 mode; + } tx; + + tx.port = dln2->port; + tx.mode = mode; + + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_MODE, &tx, sizeof(tx)); +} + +/* + * Change frame size. The module has to be disabled first. + */ +static int dln2_spi_set_bpw(struct dln2_spi *dln2, u8 bpw) +{ + struct { + u8 port; + u8 bpw; + } tx; + + tx.port = dln2->port; + tx.bpw = bpw; + + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_FRAME_SIZE, + &tx, sizeof(tx)); +} + +static int dln2_spi_get_supported_frame_sizes(struct dln2_spi *dln2, + u32 *bpw_mask) +{ + int ret; + struct { + u8 port; + } tx; + struct { + u8 count; + u8 frame_sizes[36]; + } *rx = dln2->buf; + unsigned rx_len = sizeof(*rx); + int i; + + tx.port = dln2->port; + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_GET_SUPPORTED_FRAME_SIZES, + &tx, sizeof(tx), rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(*rx)) + return -EPROTO; + if (rx->count > ARRAY_SIZE(rx->frame_sizes)) + return -EPROTO; + + *bpw_mask = 0; + for (i = 0; i < rx->count; i++) + *bpw_mask |= BIT(rx->frame_sizes[i] - 1); + + dev_dbg(&dln2->pdev->dev, "bpw_mask = 0x%X\n", *bpw_mask); + + return 0; +} + +/* + * Copy the data to DLN2 buffer and change the byte order to LE, requested by + * DLN2 module. SPI core makes sure that the data length is a multiple of word + * size. + */ +static int dln2_spi_copy_to_buf(u8 *dln2_buf, const u8 *src, u16 len, u8 bpw) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dln2_buf, src, len); +#else + if (bpw <= 8) { + memcpy(dln2_buf, src, len); + } else if (bpw <= 16) { + __le16 *d = (__le16 *)dln2_buf; + u16 *s = (u16 *)src; + + len = len / 2; + while (len--) + *d++ = cpu_to_le16p(s++); + } else { + __le32 *d = (__le32 *)dln2_buf; + u32 *s = (u32 *)src; + + len = len / 4; + while (len--) + *d++ = cpu_to_le32p(s++); + } +#endif + + return 0; +} + +/* + * Copy the data from DLN2 buffer and convert to CPU byte order since the DLN2 + * buffer is LE ordered. SPI core makes sure that the data length is a multiple + * of word size. The RX dln2_buf is 2 byte aligned so, for BE, we have to make + * sure we avoid unaligned accesses for 32 bit case. + */ +static int dln2_spi_copy_from_buf(u8 *dest, const u8 *dln2_buf, u16 len, u8 bpw) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dest, dln2_buf, len); +#else + if (bpw <= 8) { + memcpy(dest, dln2_buf, len); + } else if (bpw <= 16) { + u16 *d = (u16 *)dest; + __le16 *s = (__le16 *)dln2_buf; + + len = len / 2; + while (len--) + *d++ = le16_to_cpup(s++); + } else { + u32 *d = (u32 *)dest; + __le32 *s = (__le32 *)dln2_buf; + + len = len / 4; + while (len--) + *d++ = get_unaligned_le32(s++); + } +#endif + + return 0; +} + +/* + * Perform one write operation. + */ +static int dln2_spi_write_one(struct dln2_spi *dln2, const u8 *data, + u16 data_len, u8 attr) +{ + struct { + u8 port; + __le16 size; + u8 attr; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *tx = dln2->buf; + unsigned tx_len; + + BUILD_BUG_ON(sizeof(*tx) > DLN2_SPI_BUF_SIZE); + + if (data_len > DLN2_SPI_MAX_XFER_SIZE) + return -EINVAL; + + tx->port = dln2->port; + tx->size = cpu_to_le16(data_len); + tx->attr = attr; + + dln2_spi_copy_to_buf(tx->buf, data, data_len, dln2->bpw); + + tx_len = sizeof(*tx) + data_len - DLN2_SPI_MAX_XFER_SIZE; + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_WRITE, tx, tx_len); +} + +/* + * Perform one read operation. + */ +static int dln2_spi_read_one(struct dln2_spi *dln2, u8 *data, + u16 data_len, u8 attr) +{ + int ret; + struct { + u8 port; + __le16 size; + u8 attr; + } __packed tx; + struct { + __le16 size; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *rx = dln2->buf; + unsigned rx_len = sizeof(*rx); + + BUILD_BUG_ON(sizeof(*rx) > DLN2_SPI_BUF_SIZE); + + if (data_len > DLN2_SPI_MAX_XFER_SIZE) + return -EINVAL; + + tx.port = dln2->port; + tx.size = cpu_to_le16(data_len); + tx.attr = attr; + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_READ, &tx, sizeof(tx), + rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx->size) + data_len) + return -EPROTO; + if (le16_to_cpu(rx->size) != data_len) + return -EPROTO; + + dln2_spi_copy_from_buf(data, rx->buf, data_len, dln2->bpw); + + return 0; +} + +/* + * Perform one write & read operation. + */ +static int dln2_spi_read_write_one(struct dln2_spi *dln2, const u8 *tx_data, + u8 *rx_data, u16 data_len, u8 attr) +{ + int ret; + struct { + u8 port; + __le16 size; + u8 attr; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *tx; + struct { + __le16 size; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *rx; + unsigned tx_len, rx_len; + + BUILD_BUG_ON(sizeof(*tx) > DLN2_SPI_BUF_SIZE || + sizeof(*rx) > DLN2_SPI_BUF_SIZE); + + if (data_len > DLN2_SPI_MAX_XFER_SIZE) + return -EINVAL; + + /* + * Since this is a pseudo full-duplex communication, we're perfectly + * safe to use the same buffer for both tx and rx. When DLN2 sends the + * response back, with the rx data, we don't need the tx buffer anymore. + */ + tx = dln2->buf; + rx = dln2->buf; + + tx->port = dln2->port; + tx->size = cpu_to_le16(data_len); + tx->attr = attr; + + dln2_spi_copy_to_buf(tx->buf, tx_data, data_len, dln2->bpw); + + tx_len = sizeof(*tx) + data_len - DLN2_SPI_MAX_XFER_SIZE; + rx_len = sizeof(*rx); + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_READ_WRITE, tx, tx_len, + rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx->size) + data_len) + return -EPROTO; + if (le16_to_cpu(rx->size) != data_len) + return -EPROTO; + + dln2_spi_copy_from_buf(rx_data, rx->buf, data_len, dln2->bpw); + + return 0; +} + +/* + * Read/Write wrapper. It will automatically split an operation into multiple + * single ones due to device buffer constraints. + */ +static int dln2_spi_rdwr(struct dln2_spi *dln2, const u8 *tx_data, + u8 *rx_data, u16 data_len, u8 attr) { + int ret; + u16 len; + u8 temp_attr; + u16 remaining = data_len; + u16 offset; + + do { + if (remaining > DLN2_SPI_MAX_XFER_SIZE) { + len = DLN2_SPI_MAX_XFER_SIZE; + temp_attr = DLN2_SPI_ATTR_LEAVE_SS_LOW; + } else { + len = remaining; + temp_attr = attr; + } + + offset = data_len - remaining; + + if (tx_data && rx_data) { + ret = dln2_spi_read_write_one(dln2, + tx_data + offset, + rx_data + offset, + len, temp_attr); + } else if (tx_data) { + ret = dln2_spi_write_one(dln2, + tx_data + offset, + len, temp_attr); + } else if (rx_data) { + ret = dln2_spi_read_one(dln2, + rx_data + offset, + len, temp_attr); + } else { + return -EINVAL; + } + + if (ret < 0) + return ret; + + remaining -= len; + } while (remaining); + + return 0; +} + +static int dln2_spi_prepare_message(struct spi_master *master, + struct spi_message *message) +{ + int ret; + struct dln2_spi *dln2 = spi_master_get_devdata(master); + struct spi_device *spi = message->spi; + + if (dln2->cs != spi->chip_select) { + ret = dln2_spi_cs_set_one(dln2, spi->chip_select); + if (ret < 0) + return ret; + + dln2->cs = spi->chip_select; + } + + return 0; +} + +static int dln2_spi_transfer_setup(struct dln2_spi *dln2, u32 speed, + u8 bpw, u8 mode) +{ + int ret; + bool bus_setup_change; + + bus_setup_change = dln2->speed != speed || dln2->mode != mode || + dln2->bpw != bpw; + + if (!bus_setup_change) + return 0; + + ret = dln2_spi_enable(dln2, false); + if (ret < 0) + return ret; + + if (dln2->speed != speed) { + ret = dln2_spi_set_speed(dln2, speed); + if (ret < 0) + return ret; + + dln2->speed = speed; + } + + if (dln2->mode != mode) { + ret = dln2_spi_set_mode(dln2, mode & 0x3); + if (ret < 0) + return ret; + + dln2->mode = mode; + } + + if (dln2->bpw != bpw) { + ret = dln2_spi_set_bpw(dln2, bpw); + if (ret < 0) + return ret; + + dln2->bpw = bpw; + } + + ret = dln2_spi_enable(dln2, true); + if (ret < 0) + return ret; + + return 0; +} + +static int dln2_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct dln2_spi *dln2 = spi_master_get_devdata(master); + int status; + u8 attr = 0; + + status = dln2_spi_transfer_setup(dln2, xfer->speed_hz, + xfer->bits_per_word, + spi->mode); + if (status < 0) { + dev_err(&dln2->pdev->dev, "Cannot setup transfer\n"); + return status; + } + + if (!xfer->cs_change && !spi_transfer_is_last(master, xfer)) + attr = DLN2_SPI_ATTR_LEAVE_SS_LOW; + + status = dln2_spi_rdwr(dln2, xfer->tx_buf, xfer->rx_buf, + xfer->len, attr); + if (status < 0) + dev_err(&dln2->pdev->dev, "write/read failed!\n"); + + return status; +} + +static int dln2_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct dln2_spi *dln2; + struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev); + int ret; + + master = spi_alloc_master(&pdev->dev, sizeof(*dln2)); + if (!master) + return -ENOMEM; + + platform_set_drvdata(pdev, master); + + dln2 = spi_master_get_devdata(master); + + dln2->buf = devm_kmalloc(&pdev->dev, DLN2_SPI_BUF_SIZE, GFP_KERNEL); + if (!dln2->buf) { + ret = -ENOMEM; + goto exit_free_master; + } + + dln2->master = master; + dln2->pdev = pdev; + dln2->port = pdata->port; + /* cs/mode can never be 0xff, so the first transfer will set them */ + dln2->cs = 0xff; + dln2->mode = 0xff; + + /* disable SPI module before continuing with the setup */ + ret = dln2_spi_enable(dln2, false); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to disable SPI module\n"); + goto exit_free_master; + } + + ret = dln2_spi_get_cs_num(dln2, &master->num_chipselect); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get number of CS pins\n"); + goto exit_free_master; + } + + ret = dln2_spi_get_speed_range(dln2, + &master->min_speed_hz, + &master->max_speed_hz); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read bus min/max freqs\n"); + goto exit_free_master; + } + + ret = dln2_spi_get_supported_frame_sizes(dln2, + &master->bits_per_word_mask); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read supported frame sizes\n"); + goto exit_free_master; + } + + ret = dln2_spi_cs_enable_all(dln2, true); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable CS pins\n"); + goto exit_free_master; + } + + master->bus_num = -1; + master->mode_bits = SPI_CPOL | SPI_CPHA; + master->prepare_message = dln2_spi_prepare_message; + master->transfer_one = dln2_spi_transfer_one; + master->auto_runtime_pm = true; + + /* enable SPI module, we're good to go */ + ret = dln2_spi_enable(dln2, true); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable SPI module\n"); + goto exit_free_master; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, + DLN2_RPM_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register master\n"); + goto exit_register; + } + + return ret; + +exit_register: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + + if (dln2_spi_enable(dln2, false) < 0) + dev_err(&pdev->dev, "Failed to disable SPI module\n"); +exit_free_master: + spi_master_put(master); + + return ret; +} + +static int dln2_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + pm_runtime_disable(&pdev->dev); + + if (dln2_spi_enable(dln2, false) < 0) + dev_err(&pdev->dev, "Failed to disable SPI module\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dln2_spi_suspend(struct device *dev) +{ + int ret; + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + ret = spi_master_suspend(master); + if (ret < 0) + return ret; + + if (!pm_runtime_suspended(dev)) { + ret = dln2_spi_enable(dln2, false); + if (ret < 0) + return ret; + } + + /* + * USB power may be cut off during sleep. Resetting the following + * parameters will force the board to be set up before first transfer. + */ + dln2->cs = 0xff; + dln2->speed = 0; + dln2->bpw = 0; + dln2->mode = 0xff; + + return 0; +} + +static int dln2_spi_resume(struct device *dev) +{ + int ret; + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + if (!pm_runtime_suspended(dev)) { + ret = dln2_spi_cs_enable_all(dln2, true); + if (ret < 0) + return ret; + + ret = dln2_spi_enable(dln2, true); + if (ret < 0) + return ret; + } + + return spi_master_resume(master); +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int dln2_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + return dln2_spi_enable(dln2, false); +} + +static int dln2_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + return dln2_spi_enable(dln2, true); +} +#endif /* CONFIG_PM_RUNTIME */ + +static const struct dev_pm_ops dln2_spi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(dln2_spi_suspend, dln2_spi_resume) + SET_RUNTIME_PM_OPS(dln2_spi_runtime_suspend, + dln2_spi_runtime_resume, NULL) +}; + +static struct platform_driver spi_dln2_driver = { + .driver = { + .name = "dln2-spi", + .pm = &dln2_spi_pm, + }, + .probe = dln2_spi_probe, + .remove = dln2_spi_remove, +}; +module_platform_driver(spi_dln2_driver); + +MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI master interface"); +MODULE_AUTHOR("Laurentiu Palcu "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dln2-spi"); -- cgit v0.10.2 From f2ecf2ef59b57bd495c40d8a3e9d03e80f66afa4 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 15 Dec 2014 15:42:33 +0800 Subject: ASoC: rt5670: Add runtime PM support This patch adds runtime PM support on rt5670 codec. Signed-off-by: Lin Mengdong Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index cd47ef1..78d85de 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -2734,18 +2735,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, rt5670_dai, ARRAY_SIZE(rt5670_dai)); if (ret < 0) goto err; + pm_runtime_put(&i2c->dev); + return 0; err: + pm_runtime_disable(&i2c->dev); + return ret; } static int rt5670_i2c_remove(struct i2c_client *i2c) { + pm_runtime_disable(&i2c->dev); snd_soc_unregister_codec(&i2c->dev); return 0; -- cgit v0.10.2 From 026e73683ad5665a45b01ca1a221fa87e0e8e6fb Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 15 Dec 2014 15:42:34 +0800 Subject: ASoC: rt5670: Keep sysclk on if JD func is used System clock is necessary for rt5670 JD function. We assume system clock source will be set in machine driver. So there are two things left we should do in codec driver. 1. Set sysclk to codec internal clock in probe since machine driver may not do that before JD function is registered. 2. Power up PLL once sysclk source is switched to PLL. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 78d85de..0a027bc 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2190,6 +2190,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) return 0; + if (rt5670->pdata.jd_mode) { + if (clk_id == RT5670_SCLK_S_PLL1) + snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); + else + snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); + snd_soc_dapm_sync(&codec->dapm); + } switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2628,6 +2635,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } if (rt5670->pdata.jd_mode) { + regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK, + RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); + rt5670->sysclk = 0; + rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, RT5670_PWR_MB, RT5670_PWR_MB); regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, -- cgit v0.10.2 From 33e8612f64d4973ae3617a01224ec02b7b879597 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 22 Dec 2014 13:39:54 +0100 Subject: livepatch: use FTRACE_OPS_FL_IPMODIFY Use the FTRACE_OPS_FL_IPMODIFY flag to prevent conflicts with other ftrace users who also modify regs->ip. Signed-off-by: Josh Poimboeuf Reviewed-by: Petr Mladek Acked-by: Masami Hiramatsu Signed-off-by: Jiri Kosina diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 07a2db9..6f63879 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -641,7 +641,8 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) ops->private = func; ops->func = klp_ftrace_handler; - ops->flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_DYNAMIC; + ops->flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_DYNAMIC | + FTRACE_OPS_FL_IPMODIFY; func->fops = ops; func->state = KLP_DISABLED; -- cgit v0.10.2 From 215cedec379b69427c457104f0c36b389edc471c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 1 Dec 2014 10:10:42 -0300 Subject: [media] media: remove emacs editor variables 1) This is not allowed by the kernel coding style 2) Just configure your editor correctly 3) It's really ugly Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml index 28a8c1e..a2017bf 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml @@ -212,11 +212,3 @@ standards set in the standards field. &return-value; - - diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml index b9fdfea..6e3cadd 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml @@ -131,11 +131,3 @@ is out of bounds or the pad number is invalid. - - diff --git a/drivers/media/common/btcx-risc.c b/drivers/media/common/btcx-risc.c index ac1b268..e67338a 100644 --- a/drivers/media/common/btcx-risc.c +++ b/drivers/media/common/btcx-risc.c @@ -252,9 +252,3 @@ EXPORT_SYMBOL(btcx_screen_clips); EXPORT_SYMBOL(btcx_align); EXPORT_SYMBOL(btcx_sort_clips); EXPORT_SYMBOL(btcx_calc_skips); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/btcx-risc.h b/drivers/media/common/btcx-risc.h index f8bc6e8..03583ef 100644 --- a/drivers/media/common/btcx-risc.h +++ b/drivers/media/common/btcx-risc.h @@ -26,9 +26,3 @@ void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); void btcx_calc_skips(int line, int width, int *maxy, struct btcx_skiplist *skips, unsigned int *nskips, const struct v4l2_clip *clips, unsigned int nclips); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index 83fe9a6..6122519 100644 --- a/drivers/media/dvb-frontends/au8522.h +++ b/drivers/media/dvb-frontends/au8522.h @@ -91,8 +91,3 @@ enum au8522_audio_input { }; #endif /* __AU8522_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index 5fd14f8..99efeba 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1456,9 +1456,3 @@ MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.3"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c index 92c891a..60df376 100644 --- a/drivers/media/dvb-frontends/lgdt3305.c +++ b/drivers/media/dvb-frontends/lgdt3305.c @@ -1215,9 +1215,3 @@ MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.2"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index e046622..2e1a618 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -823,9 +823,3 @@ MODULE_AUTHOR("Wilson Michaels"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(lgdt330x_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h index ca0eab5..8bb3322 100644 --- a/drivers/media/dvb-frontends/lgdt330x.h +++ b/drivers/media/dvb-frontends/lgdt330x.h @@ -65,9 +65,3 @@ static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* #endif // CONFIG_DVB_LGDT330X #endif /* LGDT330X_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt330x_priv.h b/drivers/media/dvb-frontends/lgdt330x_priv.h index 38c7669..1922f09 100644 --- a/drivers/media/dvb-frontends/lgdt330x_priv.h +++ b/drivers/media/dvb-frontends/lgdt330x_priv.h @@ -69,9 +69,3 @@ enum I2C_REG { }; #endif /* _LGDT330X_PRIV_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h index b518d54..e38d01f 100644 --- a/drivers/media/dvb-frontends/nxt200x.h +++ b/drivers/media/dvb-frontends/nxt200x.h @@ -55,9 +55,3 @@ static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* c #endif // CONFIG_DVB_NXT200X #endif /* NXT200X_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index 5ef9218..cbbd259 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -623,9 +623,3 @@ MODULE_AUTHOR("Trent Piepho"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(or51132_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h index 9389583..cdb5be3 100644 --- a/drivers/media/dvb-frontends/or51132.h +++ b/drivers/media/dvb-frontends/or51132.h @@ -47,9 +47,3 @@ static inline struct dvb_frontend* or51132_attach(const struct or51132_config* c #endif // CONFIG_DVB_OR51132 #endif // OR51132_H - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index f71b062..5ff474a 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -1021,9 +1021,3 @@ static struct dvb_frontend_ops s5h1409_ops = { MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index 63b1e0a..9e143f5 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -81,8 +81,3 @@ static inline struct dvb_frontend *s5h1409_attach( #endif /* CONFIG_DVB_S5H1409 */ #endif /* __S5H1409_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index 6cc4b7a..64f35fe 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -944,8 +944,3 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages"); MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index e4f5687..1d7deb6 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -83,8 +83,3 @@ static inline struct dvb_frontend *s5h1411_attach( #endif /* CONFIG_DVB_S5H1411 */ #endif /* __S5H1411_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 4d9c6bc..dcc68ec 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -904,11 +904,3 @@ static struct i2c_driver msp_driver = { }; module_i2c_driver(msp_driver); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 1176583..0939d39 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -590,9 +590,3 @@ module_init(bt878_init_module); module_exit(bt878_cleanup_module); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 4105560..c518677 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -5048,10 +5048,3 @@ int bttv_handle_chipset(struct bttv *btv) pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); return 0; } - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 4a8176c..665e46d 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -4429,9 +4429,3 @@ static void __exit bttv_cleanup_module(void) module_init(bttv_init_module); module_exit(bttv_cleanup_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-gpio.c b/drivers/media/pci/bt8xx/bttv-gpio.c index 3f364b7..25b9916 100644 --- a/drivers/media/pci/bt8xx/bttv-gpio.c +++ b/drivers/media/pci/bt8xx/bttv-gpio.c @@ -181,9 +181,3 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) btwrite(data,BT848_GPIO_DATA); spin_unlock_irqrestore(&btv->gpio_lock,flags); } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-if.c b/drivers/media/pci/bt8xx/bttv-if.c index a6a540d..538652e 100644 --- a/drivers/media/pci/bt8xx/bttv-if.c +++ b/drivers/media/pci/bt8xx/bttv-if.c @@ -113,9 +113,3 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) bttv_gpio_tracking(btv,"extern write"); return 0; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 4d3f05a..3859dde 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -901,9 +901,3 @@ bttv_overlay_risc(struct bttv *btv, buf->vb.field = ov->field; return 0; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index b433267..e77129c 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -450,10 +450,3 @@ void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm) /* See bttv_vbi_fmt_set(). */ f->end = tvnorm->vbistart[0] * 2 + 2; } - -/* ----------------------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h index f081262..91301c3 100644 --- a/drivers/media/pci/bt8xx/bttv.h +++ b/drivers/media/pci/bt8xx/bttv.h @@ -378,8 +378,3 @@ extern void bttv_input_fini(struct bttv *dev); extern void bttv_input_irq(struct bttv *dev); #endif /* _BTTV_H_ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 9fe19488..e6e2c60 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -531,9 +531,3 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv, #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) #endif /* _BTTVP_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index dee177e..c38d5a1 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -1091,10 +1091,3 @@ EXPORT_SYMBOL(cx88_core_put); EXPORT_SYMBOL(cx88_ir_start); EXPORT_SYMBOL(cx88_ir_stop); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 1c1f69e..a369b08 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -833,10 +833,3 @@ EXPORT_SYMBOL(cx8802_start_dma); EXPORT_SYMBOL(cx8802_register_driver); EXPORT_SYMBOL(cx8802_unregister_driver); EXPORT_SYMBOL(cx8802_get_driver); -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 424fd97..6bbce6a 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -1050,10 +1050,3 @@ EXPORT_SYMBOL(cx88_newstation); EXPORT_SYMBOL(cx88_set_stereo); EXPORT_SYMBOL(cx88_get_stereo); EXPORT_SYMBOL(cx88_audio_thread); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 0e74e97..9e03104 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c @@ -660,11 +660,3 @@ EXPORT_SYMBOL_GPL(microtune_attach); MODULE_DESCRIPTION("Microtune tuner driver"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c index f83b0c1..6e2cdd2 100644 --- a/drivers/media/tuners/mt2131.c +++ b/drivers/media/tuners/mt2131.c @@ -294,8 +294,3 @@ EXPORT_SYMBOL(mt2131_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h index 09ceaf6..837c854 100644 --- a/drivers/media/tuners/mt2131.h +++ b/drivers/media/tuners/mt2131.h @@ -47,8 +47,3 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, #endif /* CONFIG_MEDIA_TUNER_MT2131 */ #endif /* __MT2131_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h index 62aeedf..91283b5 100644 --- a/drivers/media/tuners/mt2131_priv.h +++ b/drivers/media/tuners/mt2131_priv.h @@ -41,8 +41,3 @@ struct mt2131_priv { }; #endif /* __MT2131_PRIV_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c index 1810ad6..f4ae04c 100644 --- a/drivers/media/tuners/mxl5007t.c +++ b/drivers/media/tuners/mxl5007t.c @@ -938,11 +938,3 @@ MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.2"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h index 37b0942..ae7037d 100644 --- a/drivers/media/tuners/mxl5007t.h +++ b/drivers/media/tuners/mxl5007t.h @@ -93,12 +93,3 @@ static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, #endif #endif /* __MXL5007T_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index 4995b89..f862074 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -1355,11 +1355,3 @@ MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.4"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c index b62e925..1e89dd9 100644 --- a/drivers/media/tuners/tda18271-maps.c +++ b/drivers/media/tuners/tda18271-maps.c @@ -1305,11 +1305,3 @@ int tda18271_assign_map_layout(struct dvb_frontend *fe) return ret; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h index b36a7b7..cc80f54 100644 --- a/drivers/media/tuners/tda18271-priv.h +++ b/drivers/media/tuners/tda18271-priv.h @@ -226,11 +226,3 @@ extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); #endif /* __TDA18271_PRIV_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index 73453a2..edcb4a7 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c @@ -907,11 +907,3 @@ MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann "); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index ab4106c..998e82b 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -881,11 +881,3 @@ EXPORT_SYMBOL_GPL(tda829x_probe); MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c index 9823248..56be6c2 100644 --- a/drivers/media/tuners/tda9887.c +++ b/drivers/media/tuners/tda9887.c @@ -707,11 +707,3 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, EXPORT_SYMBOL_GPL(tda9887_attach); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index ca274c2..8e9ce14 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -1148,11 +1148,3 @@ EXPORT_SYMBOL_GPL(simple_tuner_attach); MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index 0a98d04..ecefa5c 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -604,9 +604,3 @@ MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h index 2d4530f..0bd83e5 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h @@ -47,9 +47,3 @@ struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, #endif /* CONFIG_DVB_USB_MXL111SF */ #endif /* __MXL111SF_DEMOD_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c index a619410..2180c13 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c @@ -755,9 +755,3 @@ int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) } return 0; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h index b85a577..16fa4d4 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h @@ -48,9 +48,3 @@ int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, enum mxl111sf_mux_config pin_mux_config); #endif /* _DVB_USB_MXL111SF_GPIO_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c index a101d06..283495c 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c @@ -842,9 +842,3 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap, return i == num ? num : -EREMOTEIO; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h index 4657621..c486fe0 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h @@ -27,9 +27,3 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num); #endif /* _DVB_USB_MXL111SF_I2C_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c index f6b3480..5b01911 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c @@ -335,9 +335,3 @@ int mxl111sf_idac_config(struct mxl111sf_state *state, return ret; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h index 0643738..25aa4a1 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h @@ -45,9 +45,3 @@ int mxl111sf_idac_config(struct mxl111sf_state *state, u8 current_value, u8 hysteresis_value); #endif /* _DVB_USB_MXL111SF_PHY_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h index 89bf115..1f4bfbc 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h @@ -171,9 +171,3 @@ #define V6_DIG_RF_PWR_MSB_REG 0x47 #endif /* _DVB_USB_MXL111SF_REG_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c index a8d2c70..444579b 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c @@ -515,11 +515,3 @@ MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h index 2046db2..e6caab2 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h @@ -77,12 +77,3 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, #endif #endif /* __MXL111SF_TUNER_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index c3447ea..bec12b0 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -1425,9 +1425,3 @@ MODULE_AUTHOR("Michael Krufky "); MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h index 8516c01..ee70df1 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h @@ -152,9 +152,3 @@ extern int dvb_usb_mxl111sf_debug; }) #endif /* _DVB_USB_MXL111SF_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index abf8ab2..eafc5c8 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -1269,8 +1269,3 @@ MODULE_AUTHOR("Aapo Tahkola "); MODULE_DESCRIPTION("DVB Driver for ULI M920x"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c index cc06d5e..45276c6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c @@ -84,13 +84,3 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0); } } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.h b/drivers/media/usb/pvrusb2/pvrusb2-audio.h index e3e63d7..27cefb5 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.h @@ -25,13 +25,3 @@ #include "pvrusb2-hdw-internal.h" void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); #endif /* __PVRUSB2_AUDIO_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c index c8761c7..924fc4c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c @@ -418,14 +418,3 @@ struct pvr2_ioread *pvr2_channel_create_mpeg_stream( pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); return cp; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h index d657e53..1c1d442 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h @@ -83,12 +83,3 @@ int pvr2_context_global_init(void); void pvr2_context_global_done(void); #endif /* __PVRUSB2_CONTEXT_H */ -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c index 8832090..f82f0f0 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c @@ -82,14 +82,3 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->audio->s_routing(sd, input, 0, 0); } } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h index 53ba548..86c17be 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h @@ -36,13 +36,3 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); #endif /* __PVRUSB2_AUDIO_CS53L32A_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c index 7d5a713..958db17 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c @@ -596,14 +596,3 @@ int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr, } while(0); LOCK_GIVE(cptr->hdw->big_lock); return ret; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h index 794ff90..c175571 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h @@ -110,13 +110,3 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *, unsigned int *len); #endif /* __PVRUSB2_CTRL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c index c514d0b..1a81aa7 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -152,15 +152,3 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->audio->s_routing(sd, (u32)aud_input, 0, 0); } } - - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h index e35c232..2eed7b7 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h @@ -40,13 +40,3 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd); #endif /* __PVRUSB2_CX2584X_V4L_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h index be79249..4ef2ebc 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h @@ -57,13 +57,3 @@ extern int pvrusb2_debug; #endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c index 4279ebb..e4022bc 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c @@ -322,14 +322,3 @@ int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf, return 0; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h index 2f8d467..a8dfc55 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h @@ -40,13 +40,3 @@ int pvr2_debugifc_docmd(struct pvr2_hdw *, const char *buf_ptr,unsigned int buf_size); #endif /* __PVRUSB2_DEBUGIFC_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c index adc501d3..06c4c3d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c @@ -564,13 +564,3 @@ MODULE_FIRMWARE(PVR2_FIRMWARE_29xxx); MODULE_FIRMWARE(PVR2_FIRMWARE_24xxx); MODULE_FIRMWARE(PVR2_FIRMWARE_73xxx); MODULE_FIRMWARE(PVR2_FIRMWARE_75xxx); - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h index 273c8d4..5aeefb6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h @@ -187,13 +187,3 @@ struct pvr2_device_desc { extern struct usb_device_id pvr2_device_table[]; #endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index 9515f3a..e1907cd 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c @@ -152,13 +152,3 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) return 0; } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h index cca3216..f1e33c8 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h @@ -27,13 +27,3 @@ struct pvr2_hdw; int pvr2_eeprom_analyze(struct pvr2_hdw *); #endif /* __PVRUSB2_EEPROM_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index f7702ae..593b3e9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -538,14 +538,3 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw) return status; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h index 232fefb..a2bfb48 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h @@ -30,13 +30,3 @@ int pvr2_encoder_start(struct pvr2_hdw *); int pvr2_encoder_stop(struct pvr2_hdw *); #endif /* __PVRUSB2_ENCODER_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h index 614755e..06a15a6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h @@ -60,13 +60,3 @@ #define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3u #endif /* _PVRUSB2_FX2_CMD_H_ */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h index 036952f..1f9c028 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h @@ -394,13 +394,3 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *); void pvr2_hdw_status_poll(struct pvr2_hdw *); #endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index 4184707..fc50379 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -343,13 +343,3 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); int pvr2_upload_firmware2(struct pvr2_hdw *hdw); #endif /* __PVRUSB2_HDW_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index b5e929f..4baa9d6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -686,13 +686,3 @@ void pvr2_i2c_core_done(struct pvr2_hdw *hdw) hdw->i2c_linked = 0; } } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h index 6a757692..a10a3e8 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h @@ -27,14 +27,3 @@ void pvr2_i2c_core_done(struct pvr2_hdw *); #endif /* __PVRUSB2_I2C_ADAPTER_H */ - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 1e35474..0c08f22 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -682,14 +682,3 @@ int pvr2_buffer_get_id(struct pvr2_buffer *bp) { return bp->id; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.h b/drivers/media/usb/pvrusb2/pvrusb2-io.h index afb7e87..0c47c6a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.h @@ -90,13 +90,3 @@ int pvr2_buffer_get_id(struct pvr2_buffer *); int pvr2_buffer_queue(struct pvr2_buffer *); #endif /* __PVRUSB2_IO_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c index bba6115..cd995b5 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c @@ -499,14 +499,3 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) cp,req_cnt,ret); return ret; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h index 100e078..0b1f0fb 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h @@ -36,13 +36,3 @@ int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt); int pvr2_ioread_avail(struct pvr2_ioread *); #endif /* __PVRUSB2_IOREAD_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c index c1d9bb6..86be902 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-main.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c @@ -169,14 +169,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION("0.9.1"); - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index 453627b..9a596a3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -398,14 +398,3 @@ v4l2_std_id pvr2_std_get_usable(void) { return CSTD_ALL; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h index a35c53d..ed4ec04 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h @@ -47,13 +47,3 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, v4l2_std_id pvr2_std_get_usable(void); #endif /* __PVRUSB2_STD_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 6ef1335..06fe63c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -848,14 +848,3 @@ static ssize_t debugcmd_store(struct device *class_dev, return count; } #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h index 6d875bf..6f0579e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h @@ -34,13 +34,3 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, struct pvr2_sysfs_class *); #endif /* __PVRUSB2_SYSFS_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-util.h b/drivers/media/usb/pvrusb2/pvrusb2-util.h index 92b7554..5465bf9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-util.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-util.h @@ -50,13 +50,3 @@ #endif /* __PVRUSB2_UTIL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 1b158f1..422d79e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -1360,13 +1360,3 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) pvr2_v4l2_destroy_no_lock(vp); return NULL; } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h index 34c011a..e455c95 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h @@ -27,13 +27,3 @@ struct pvr2_v4l2; struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *); #endif /* __PVRUSB2_V4L2_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c index 2e205c9..139b397 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c @@ -101,14 +101,3 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->video->s_routing(sd, input, 0, 0); } } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h index 3b0bd5d..dacf3ec 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h @@ -36,13 +36,3 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); #endif /* __PVRUSB2_VIDEO_V4L_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c index 3ac8d75..f1df94a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c @@ -56,15 +56,3 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->audio->s_routing(sd, input, 0, 0); } } - - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h index 0577bc7..a4ee12e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h @@ -40,13 +40,3 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd); #endif /* __PVRUSB2_WM8775_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2.h b/drivers/media/usb/pvrusb2/pvrusb2.h index 240de9b..95f98a8 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2.h +++ b/drivers/media/usb/pvrusb2/pvrusb2.h @@ -30,13 +30,3 @@ #define PVR_NUM 20 #endif /* __PVRUSB2_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 302aa07..2144b7b 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -2502,11 +2502,3 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) usbvision_set_audio(usbvision, audio[channel]); return 0; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/usbvision/usbvision-i2c.c b/drivers/media/usb/usbvision/usbvision-i2c.c index ba262a3..26dbcb1 100644 --- a/drivers/media/usb/usbvision/usbvision-i2c.c +++ b/drivers/media/usb/usbvision/usbvision-i2c.c @@ -445,11 +445,3 @@ static struct i2c_adapter i2c_adap_template = { .owner = THIS_MODULE, .name = "usbvision", }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 693d5f4..cd2fbf1 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -1716,11 +1716,3 @@ static void __exit usbvision_exit(void) module_init(usbvision_init); module_exit(usbvision_exit); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index a0c73cf..77aeb1e 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -517,11 +517,3 @@ int usbvision_power_off(struct usb_usbvision *usbvision); int usbvision_power_on(struct usb_usbvision *usbvision); #endif /* __LINUX_USBVISION_H */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 9aa530a..a13cc61 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -1033,10 +1033,3 @@ MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR); - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h index d63965a..c3bfa47 100644 --- a/include/media/videobuf-dvb.h +++ b/include/media/videobuf-dvb.h @@ -56,9 +56,3 @@ struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_fro int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p); #endif /* _VIDEOBUF_DVB_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v0.10.2 From 83737691e586cd2767fa4fc87cd41251d1a49e9e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 22 Dec 2014 21:04:31 +0100 Subject: x86, mce: Fix sparse errors Make stuff used in mce.c only, static. Signed-off-by: Borislav Petkov diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 323e02c..4c5cd75 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -115,7 +115,7 @@ static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs); * CPU/chipset specific EDAC code can register a notifier call here to print * MCE errors in a human-readable form. */ -ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); +static ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); /* Do initial initialization of a struct mce */ void mce_setup(struct mce *m) @@ -529,7 +529,7 @@ static void mce_schedule_work(void) schedule_work(this_cpu_ptr(&mce_work)); } -DEFINE_PER_CPU(struct irq_work, mce_irq_work); +static DEFINE_PER_CPU(struct irq_work, mce_irq_work); static void mce_irq_work_cb(struct irq_work *entry) { @@ -1012,7 +1012,7 @@ static void mce_clear_state(unsigned long *toclear) */ #define MCE_INFO_MAX 16 -struct mce_info { +static struct mce_info { atomic_t inuse; struct task_struct *t; __u64 paddr; -- cgit v0.10.2 From 1a023feb9c880bdf61502c5f8ef7b499133de8da Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Dec 2014 06:54:52 -0300 Subject: [media] v4l2 subdevs: replace get/set_crop by get/set_selection The crop and selection pad ops are duplicates. Replace all uses of get/set_crop by get/set_selection. This will make it possible to drop get/set_crop altogether. Signed-off-by: Hans Verkuil Acked-by: Sylwester Nawrocki Acked-by: Laurent Pinchart Cc: Prabhakar Lad Cc: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 45b3fca..7643122 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -422,22 +422,25 @@ done: return ret; } -static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + mutex_lock(&sensor->lock); - crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which); + sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which); mutex_unlock(&sensor->lock); return 0; } -static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); struct v4l2_mbus_framefmt *format; @@ -445,9 +448,12 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, struct v4l2_rect rect; int ret = 0; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + mutex_lock(&sensor->lock); - if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sensor->streaming && sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ret = -EBUSY; goto done; } @@ -455,13 +461,13 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, /* Clamp the crop rectangle boundaries and align them to a multiple of 2 * pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN, + rect.left = clamp(ALIGN(sel->r.left, 2), MT9M032_COLUMN_START_MIN, MT9M032_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, + rect.top = clamp(ALIGN(sel->r.top, 2), MT9M032_ROW_START_MIN, MT9M032_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX); rect.width = min_t(unsigned int, rect.width, @@ -469,21 +475,21 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); + __crop = __mt9m032_get_pad_crop(sensor, fh, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - format = __mt9m032_get_pad_format(sensor, fh, crop->which); + format = __mt9m032_get_pad_format(sensor, fh, sel->which); format->width = rect.width; format->height = rect.height; } *__crop = rect; - crop->rect = rect; + sel->r = rect; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) ret = mt9m032_update_geom_timing(sensor); done: @@ -690,8 +696,8 @@ static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = { .enum_frame_size = mt9m032_enum_frame_size, .get_fmt = mt9m032_get_pad_format, .set_fmt = mt9m032_set_pad_format, - .set_crop = mt9m032_set_pad_crop, - .get_crop = mt9m032_get_pad_crop, + .set_selection = mt9m032_set_pad_selection, + .get_selection = mt9m032_get_pad_selection, }; static const struct v4l2_subdev_ops mt9m032_ops = { diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index edb76bd..e3acae9 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -581,37 +581,42 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9p031_get_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9p031_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); - crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad, - crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); return 0; } -static int mt9p031_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9p031_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; struct v4l2_rect rect; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 * pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN, + rect.left = clamp(ALIGN(sel->r.left, 2), MT9P031_COLUMN_START_MIN, MT9P031_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN, + rect.top = clamp(ALIGN(sel->r.top, 2), MT9P031_ROW_START_MIN, MT9P031_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9P031_WINDOW_WIDTH_MIN, MT9P031_WINDOW_WIDTH_MAX); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9P031_WINDOW_HEIGHT_MIN, MT9P031_WINDOW_HEIGHT_MAX); @@ -620,20 +625,20 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which); + __crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad, - crop->which); + __format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad, + sel->which); __format->width = rect.width; __format->height = rect.height; } *__crop = rect; - crop->rect = rect; + sel->r = rect; return 0; } @@ -980,8 +985,8 @@ static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = { .enum_frame_size = mt9p031_enum_frame_size, .get_fmt = mt9p031_get_format, .set_fmt = mt9p031_set_format, - .get_crop = mt9p031_get_crop, - .set_crop = mt9p031_set_crop, + .get_selection = mt9p031_get_selection, + .set_selection = mt9p031_set_selection, }; static struct v4l2_subdev_ops mt9p031_subdev_ops = { diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index d9e9889..f6ca636 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -401,39 +401,44 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9t001_get_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9t001_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); - crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad, - crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); return 0; } -static int mt9t001_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9t001_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; struct v4l2_rect rect; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 * pixels. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), + rect.left = clamp(ALIGN(sel->r.left, 2), MT9T001_COLUMN_START_MIN, MT9T001_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), + rect.top = clamp(ALIGN(sel->r.top, 2), MT9T001_ROW_START_MIN, MT9T001_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9T001_WINDOW_WIDTH_MIN + 1, MT9T001_WINDOW_WIDTH_MAX + 1); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9T001_WINDOW_HEIGHT_MIN + 1, MT9T001_WINDOW_HEIGHT_MAX + 1); @@ -442,20 +447,20 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which); + __crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad, - crop->which); + __format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad, + sel->which); __format->width = rect.width; __format->height = rect.height; } *__crop = rect; - crop->rect = rect; + sel->r = rect; return 0; } @@ -819,8 +824,8 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { .enum_frame_size = mt9t001_enum_frame_size, .get_fmt = mt9t001_get_format, .set_fmt = mt9t001_set_format, - .get_crop = mt9t001_get_crop, - .set_crop = mt9t001_set_crop, + .get_selection = mt9t001_get_selection, + .set_selection = mt9t001_set_selection, }; static struct v4l2_subdev_ops mt9t001_subdev_ops = { diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 93687c1..bd3f979 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -552,39 +552,44 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9v032_get_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9v032_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); - crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad, - crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); return 0; } -static int mt9v032_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9v032_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; struct v4l2_rect rect; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + /* Clamp the crop rectangle boundaries and align them to a non multiple * of 2 pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1, + rect.left = clamp(ALIGN(sel->r.left + 1, 2) - 1, MT9V032_COLUMN_START_MIN, MT9V032_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, + rect.top = clamp(ALIGN(sel->r.top + 1, 2) - 1, MT9V032_ROW_START_MIN, MT9V032_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9V032_WINDOW_WIDTH_MIN, MT9V032_WINDOW_WIDTH_MAX); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9V032_WINDOW_HEIGHT_MIN, MT9V032_WINDOW_HEIGHT_MAX); @@ -593,17 +598,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); + __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad, - crop->which); + __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad, + sel->which); __format->width = rect.width; __format->height = rect.height; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { mt9v032->hratio = 1; mt9v032->vratio = 1; mt9v032_configure_pixel_rate(mt9v032); @@ -611,7 +616,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, } *__crop = rect; - crop->rect = rect; + sel->r = rect; return 0; } @@ -844,8 +849,8 @@ static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = { .enum_frame_size = mt9v032_enum_frame_size, .get_fmt = mt9v032_get_format, .set_fmt = mt9v032_set_format, - .get_crop = mt9v032_get_crop, - .set_crop = mt9v032_set_crop, + .get_selection = mt9v032_get_selection, + .set_selection = mt9v032_set_selection, }; static struct v4l2_subdev_ops mt9v032_subdev_ops = { diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index 2851581..19edafb 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -1161,17 +1161,21 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } -static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int s5k6aa_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); struct v4l2_rect *rect; - memset(crop->reserved, 0, sizeof(crop->reserved)); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + memset(sel->reserved, 0, sizeof(sel->reserved)); mutex_lock(&s5k6aa->lock); - rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); - crop->rect = *rect; + rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + sel->r = *rect; mutex_unlock(&s5k6aa->lock); v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", @@ -1180,35 +1184,39 @@ static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int s5k6aa_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); struct v4l2_mbus_framefmt *mf; unsigned int max_x, max_y; struct v4l2_rect *crop_r; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + mutex_lock(&s5k6aa->lock); - crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); + crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { mf = &s5k6aa->preset->mbus_fmt; s5k6aa->apply_crop = 1; } else { mf = v4l2_subdev_get_try_format(fh, 0); } - v4l_bound_align_image(&crop->rect.width, mf->width, + v4l_bound_align_image(&sel->r.width, mf->width, S5K6AA_WIN_WIDTH_MAX, 1, - &crop->rect.height, mf->height, + &sel->r.height, mf->height, S5K6AA_WIN_HEIGHT_MAX, 1, 0); - max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1; - max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1; + max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1; + max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1; - crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x); - crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y); + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x); + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, max_y); - *crop_r = crop->rect; + *crop_r = sel->r; mutex_unlock(&s5k6aa->lock); @@ -1224,8 +1232,8 @@ static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { .enum_frame_interval = s5k6aa_enum_frame_interval, .get_fmt = s5k6aa_get_fmt, .set_fmt = s5k6aa_set_fmt, - .get_crop = s5k6aa_get_crop, - .set_crop = s5k6aa_set_crop, + .get_selection = s5k6aa_get_selection, + .set_selection = s5k6aa_set_selection, }; static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index 0ba0bf2..bcf762b 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -1535,7 +1535,7 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, } /* - * isif_pad_set_crop() - set crop rectangle on pad + * isif_pad_set_selection() - set crop rectangle on pad * @sd: VPFE isif V4L2 subdevice * @fh: V4L2 subdev file handle * @code: pointer to v4l2_subdev_mbus_code_enum structure @@ -1543,35 +1543,36 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * Return 0 on success, -EINVAL if pad is invalid */ static int -isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +isif_pad_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - /* check wether its a valid pad */ - if (crop->pad != ISIF_PAD_SINK) + /* check whether it's a valid pad and target */ + if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - format = __isif_get_format(vpfe_isif, fh, crop->pad, crop->which); + format = __isif_get_format(vpfe_isif, fh, sel->pad, sel->which); if (format == NULL) return -EINVAL; /* check wether crop rect is within limits */ - if (crop->rect.top < 0 || crop->rect.left < 0 || - (crop->rect.left + crop->rect.width > + if (sel->r.top < 0 || sel->r.left < 0 || + (sel->r.left + sel->r.width > vpfe_isif->formats[ISIF_PAD_SINK].width) || - (crop->rect.top + crop->rect.height > + (sel->r.top + sel->r.height > vpfe_isif->formats[ISIF_PAD_SINK].height)) { - crop->rect.left = 0; - crop->rect.top = 0; - crop->rect.width = format->width; - crop->rect.height = format->height; + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = format->width; + sel->r.height = format->height; } /* adjust the width to 16 pixel boundary */ - crop->rect.width = ((crop->rect.width + 15) & ~0xf); - vpfe_isif->crop = crop->rect; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sel->r.width = ((sel->r.width + 15) & ~0xf); + vpfe_isif->crop = sel->r; + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { isif_set_image_window(vpfe_isif); } else { struct v4l2_rect *rect; @@ -1583,7 +1584,7 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, } /* - * isif_pad_get_crop() - get crop rectangle on pad + * isif_pad_get_selection() - get crop rectangle on pad * @sd: VPFE isif V4L2 subdevice * @fh: V4L2 subdev file handle * @code: pointer to v4l2_subdev_mbus_code_enum structure @@ -1591,22 +1592,23 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * Return 0 on success, -EINVAL if pad is invalid */ static int -isif_pad_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +isif_pad_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - /* check wether its a valid pad */ - if (crop->pad != ISIF_PAD_SINK) + /* check whether it's a valid pad and target */ + if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (crop->which == V4L2_SUBDEV_FORMAT_TRY) { + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_rect *rect; rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK); - memcpy(&crop->rect, rect, sizeof(*rect)); + memcpy(&sel->r, rect, sizeof(*rect)); } else { - crop->rect = vpfe_isif->crop; + sel->r = vpfe_isif->crop; } return 0; @@ -1626,7 +1628,7 @@ isif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_subdev_format format; - struct v4l2_subdev_crop crop; + struct v4l2_subdev_selection sel; memset(&format, 0, sizeof(format)); format.pad = ISIF_PAD_SINK; @@ -1644,12 +1646,13 @@ isif_init_formats(struct v4l2_subdev *sd, format.format.height = MAX_HEIGHT; isif_set_format(sd, fh, &format); - memset(&crop, 0, sizeof(crop)); - crop.pad = ISIF_PAD_SINK; - crop.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - crop.rect.width = MAX_WIDTH; - crop.rect.height = MAX_HEIGHT; - isif_pad_set_crop(sd, fh, &crop); + memset(&sel, 0, sizeof(sel)); + sel.pad = ISIF_PAD_SINK; + sel.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + sel.target = V4L2_SEL_TGT_CROP; + sel.r.width = MAX_WIDTH; + sel.r.height = MAX_HEIGHT; + isif_pad_set_selection(sd, fh, &sel); return 0; } @@ -1675,8 +1678,8 @@ static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = { .enum_frame_size = isif_enum_frame_size, .get_fmt = isif_get_format, .set_fmt = isif_set_format, - .set_crop = isif_pad_set_crop, - .get_crop = isif_pad_get_crop, + .set_selection = isif_pad_set_selection, + .get_selection = isif_pad_get_selection, }; /* subdev operations */ -- cgit v0.10.2 From 05b9cc3eeffcb2b0d6720930fc144058d4ace1aa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Dec 2014 06:54:53 -0300 Subject: [media] v4l2-subdev: drop get/set_crop pad ops Drop the duplicate get/set_crop pad ops and only use get/set_selection. It makes no sense to have two duplicate ops in the internal subdev API. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 543631c..19a034e 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -283,10 +283,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); - if (rval != -ENOIOCTLCMD) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -308,10 +304,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); - if (rval != -ENOIOCTLCMD) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5860292..b052184 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -503,10 +503,6 @@ struct v4l2_subdev_pad_ops { struct v4l2_subdev_format *format); int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *format); - int (*set_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop); - int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop); int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_selection *sel); int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, -- cgit v0.10.2 From cb03893e3e55924c87943435ab6c7b38e507466c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Dec 2014 06:54:54 -0300 Subject: [media] v4l2-subdev: drop unused op enum_mbus_fmt Weird, this op isn't used at all. Seems to be orphaned code. Remove it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index b052184..5beeb87 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -342,8 +342,6 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, u32 *code); - int (*enum_mbus_fsizes)(struct v4l2_subdev *sd, - struct v4l2_frmsizeenum *fsize); int (*g_mbus_fmt)(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt); int (*try_mbus_fmt)(struct v4l2_subdev *sd, -- cgit v0.10.2 From 584ca0252abf31388cacbdb3018aab2c70362d8d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Dec 2014 06:54:56 -0300 Subject: [media] media/i2c/Kconfig: drop superfluous MEDIA_CONTROLLER These drivers depend on VIDEO_V4L2_SUBDEV_API, which in turn depends on MEDIA_CONTROLLER. So it is sufficient to just depend on VIDEO_V4L2_SUBDEV_API. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 205d713..ca84543 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -196,7 +196,7 @@ config VIDEO_ADV7183 config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ---help--- Support for the Analog Devices ADV7604 video decoder. @@ -208,7 +208,7 @@ config VIDEO_ADV7604 config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ---help--- Support for the Analog Devices ADV7842 video decoder. @@ -422,7 +422,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ---help--- Support for the Analog Devices ADV7511 video encoder. -- cgit v0.10.2 From 2db73d4482da9bd979edee345e95bb3a88441b30 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 18 Dec 2014 15:04:19 +0200 Subject: spi: pxa2xx: Remove unused define Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 05c623c..e1dc8618 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -45,8 +45,6 @@ MODULE_DESCRIPTION("PXA2xx SSP SPI Controller"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pxa2xx-spi"); -#define MAX_BUSES 3 - #define TIMOUT_DFLT 1000 /* -- cgit v0.10.2 From 7566bcc76b15186172c4db0414cf30c8a61e4a73 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 18 Dec 2014 15:04:20 +0200 Subject: spi: pxa2xx: Move is_lpss_ssp() tests to caller Move is_lpss_ssp() tests from functions to caller. Although this aims to improve readability it also saves a few code bytes on x86. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e1dc8618..cc08500 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -251,9 +251,6 @@ static void lpss_ssp_setup(struct driver_data *drv_data) unsigned offset = 0x400; u32 value, orig; - if (!is_lpss_ssp(drv_data)) - return; - /* * Perform auto-detection of the LPSS SSP private registers. They * can be either at 1k or 2k offset from the base address. @@ -302,9 +299,6 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) { u32 value; - if (!is_lpss_ssp(drv_data)) - return; - value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL); if (enable) value &= ~SPI_CS_CONTROL_CS_HIGH; @@ -332,7 +326,8 @@ static void cs_assert(struct driver_data *drv_data) return; } - lpss_ssp_cs_control(drv_data, true); + if (is_lpss_ssp(drv_data)) + lpss_ssp_cs_control(drv_data, true); } static void cs_deassert(struct driver_data *drv_data) @@ -352,7 +347,8 @@ static void cs_deassert(struct driver_data *drv_data) return; } - lpss_ssp_cs_control(drv_data, false); + if (is_lpss_ssp(drv_data)) + lpss_ssp_cs_control(drv_data, false); } int pxa2xx_spi_flush(struct driver_data *drv_data) @@ -1415,7 +1411,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) if (!is_quark_x1000_ssp(drv_data)) write_SSPSP(0, drv_data->ioaddr); - lpss_ssp_setup(drv_data); + if (is_lpss_ssp(drv_data)) + lpss_ssp_setup(drv_data); tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); -- cgit v0.10.2 From c4827bb859cbe8afad9287c9dd4e7162119d3d59 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 18 Dec 2014 15:04:21 +0200 Subject: spi: pxa2xx: Add definition for Intel Quark DDS_RATE register Intel Quark DDS_RATE register is defined only in register access macro. Add a definition for it to common SSP register definitions for preparing to cleanup those macros. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 77aed9e..dab545b 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -37,6 +37,7 @@ #define SSDR (0x10) /* SSP Data Write/Data Read Register */ #define SSTO (0x28) /* SSP Time Out Register */ +#define DDS_RATE (0x28) /* SSP DDS Clock Rate Register (Intel Quark) */ #define SSPSP (0x2C) /* SSP Programmable Serial Protocol */ #define SSTSA (0x30) /* SSP Tx Timeslot Active */ #define SSRSA (0x34) /* SSP Rx Timeslot Active */ -- cgit v0.10.2 From 8e8dd9fb25f6dab6ac3f19f445a51b2c71e08d5c Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 18 Dec 2014 15:04:22 +0200 Subject: spi: pxa2xx: Pass driver data instead of ioaddr to wait_ssp_rx_stall() Pass pointer to struct driver_data instead of ioaddr to wait_ssp_rx_stall() for preparing to register access macro cleanup. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c index e8a26f2..aaa5fc6 100644 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ b/drivers/spi/spi-pxa2xx-pxadma.c @@ -118,11 +118,11 @@ static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data) drv_data->dma_mapped = 0; } -static int wait_ssp_rx_stall(void const __iomem *ioaddr) +static int wait_ssp_rx_stall(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit) + while ((read_SSSR(drv_data->ioaddr) & SSSR_BSY) && --limit) cpu_relax(); return limit; @@ -228,7 +228,7 @@ void pxa2xx_spi_dma_handler(int channel, void *data) && (drv_data->ssp_type == PXA25x_SSP)) { /* Wait for rx to stall */ - if (wait_ssp_rx_stall(drv_data->ioaddr) == 0) + if (wait_ssp_rx_stall(drv_data) == 0) dev_err(&drv_data->pdev->dev, "dma_handler: ssp rx stall failed\n"); -- cgit v0.10.2 From c039dd275e88989478abe5f28e4e15648c28ce33 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 18 Dec 2014 15:04:23 +0200 Subject: spi: pxa2xx: Cleanup register access macros Currently SSP registers are accessed by having an own read and write macros for each register. For instance read_SSSR(iobase) and write_SSSR(iobase). In my opinion this hurts readability and requires new macros to be defined for each new added register. Let's define and use instead common pxa2xx_spi_read() and pxa2xx_spi_write() accessors. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 62a9297..66a1739 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -111,23 +111,24 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, * by using ->dma_running. */ if (atomic_dec_and_test(&drv_data->dma_running)) { - void __iomem *reg = drv_data->ioaddr; - /* * If the other CPU is still handling the ROR interrupt we * might not know about the error yet. So we re-check the * ROR bit here before we clear the status register. */ if (!error) { - u32 status = read_SSSR(reg) & drv_data->mask_sr; + u32 status = pxa2xx_spi_read(drv_data, SSSR) + & drv_data->mask_sr; error = status & SSSR_ROR; } /* Clear status & disable interrupts */ - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->dma_cr1); write_SSSR_CS(drv_data, drv_data->clear_sr); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); if (!error) { pxa2xx_spi_unmap_dma_buffers(drv_data); @@ -139,7 +140,9 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, msg->state = pxa2xx_spi_next_transfer(drv_data); } else { /* In case we got an error we disable the SSP now */ - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) + & ~SSCR0_SSE); msg->state = ERROR_STATE; } @@ -247,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) { u32 status; - status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr; + status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; if (status & SSSR_ROR) { dev_err(&drv_data->pdev->dev, "FIFO overrun\n"); diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c index aaa5fc6..6c82d49 100644 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ b/drivers/spi/spi-pxa2xx-pxadma.c @@ -122,7 +122,7 @@ static int wait_ssp_rx_stall(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - while ((read_SSSR(drv_data->ioaddr) & SSSR_BSY) && --limit) + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit) cpu_relax(); return limit; @@ -141,17 +141,18 @@ static int wait_dma_channel_stop(int channel) static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data, const char *msg) { - void __iomem *reg = drv_data->ioaddr; - /* Stop and reset */ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; write_SSSR_CS(drv_data, drv_data->clear_sr); - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->dma_cr1); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); pxa2xx_spi_flush(drv_data); - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); pxa2xx_spi_unmap_dma_buffers(drv_data); @@ -163,11 +164,12 @@ static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data, static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; struct spi_message *msg = drv_data->cur_msg; /* Clear and disable interrupts on SSP and DMA channels*/ - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->dma_cr1); write_SSSR_CS(drv_data, drv_data->clear_sr); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; @@ -240,9 +242,8 @@ void pxa2xx_spi_dma_handler(int channel, void *data) irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) { u32 irq_status; - void __iomem *reg = drv_data->ioaddr; - irq_status = read_SSSR(reg) & drv_data->mask_sr; + irq_status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; if (irq_status & SSSR_ROR) { pxa2xx_spi_dma_error_stop(drv_data, "dma_transfer: fifo overrun"); @@ -252,7 +253,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) /* Check for false positive timeout */ if ((irq_status & SSSR_TINT) && (DCSR(drv_data->tx_channel) & DCSR_RUN)) { - write_SSSR(SSSR_TINT, reg); + pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT); return IRQ_HANDLED; } @@ -261,7 +262,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) /* Clear and disable timeout interrupt, do the rest in * dma_transfer_complete */ if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); /* finish this transfer, start the next */ pxa2xx_spi_dma_transfer_complete(drv_data); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index cc08500..b00db8b 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -160,7 +160,6 @@ pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data) static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; u32 mask; switch (drv_data->ssp_type) { @@ -172,7 +171,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) break; } - return (read_SSSR(reg) & mask) == mask; + return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask; } static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, @@ -312,7 +311,7 @@ static void cs_assert(struct driver_data *drv_data) struct chip_data *chip = drv_data->cur_chip; if (drv_data->ssp_type == CE4100_SSP) { - write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSSR, drv_data->cur_chip->frm); return; } @@ -355,13 +354,10 @@ int pxa2xx_spi_flush(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - void __iomem *reg = drv_data->ioaddr; - do { - while (read_SSSR(reg) & SSSR_RNE) { - read_SSDR(reg); - } - } while ((read_SSSR(reg) & SSSR_BSY) && --limit); + while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + pxa2xx_spi_read(drv_data, SSDR); + } while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit); write_SSSR_CS(drv_data, SSSR_ROR); return limit; @@ -369,14 +365,13 @@ int pxa2xx_spi_flush(struct driver_data *drv_data) static int null_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(0, reg); + pxa2xx_spi_write(drv_data, SSDR, 0); drv_data->tx += n_bytes; return 1; @@ -384,12 +379,11 @@ static int null_writer(struct driver_data *drv_data) static int null_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += n_bytes; } @@ -398,13 +392,11 @@ static int null_reader(struct driver_data *drv_data) static int u8_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(*(u8 *)(drv_data->tx), reg); + pxa2xx_spi_write(drv_data, SSDR, *(u8 *)(drv_data->tx)); ++drv_data->tx; return 1; @@ -412,11 +404,9 @@ static int u8_writer(struct driver_data *drv_data) static int u8_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - *(u8 *)(drv_data->rx) = read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + *(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); ++drv_data->rx; } @@ -425,13 +415,11 @@ static int u8_reader(struct driver_data *drv_data) static int u16_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(*(u16 *)(drv_data->tx), reg); + pxa2xx_spi_write(drv_data, SSDR, *(u16 *)(drv_data->tx)); drv_data->tx += 2; return 1; @@ -439,11 +427,9 @@ static int u16_writer(struct driver_data *drv_data) static int u16_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - *(u16 *)(drv_data->rx) = read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + *(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += 2; } @@ -452,13 +438,11 @@ static int u16_reader(struct driver_data *drv_data) static int u32_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(*(u32 *)(drv_data->tx), reg); + pxa2xx_spi_write(drv_data, SSDR, *(u32 *)(drv_data->tx)); drv_data->tx += 4; return 1; @@ -466,11 +450,9 @@ static int u32_writer(struct driver_data *drv_data) static int u32_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - *(u32 *)(drv_data->rx) = read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + *(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += 4; } @@ -546,27 +528,25 @@ static void giveback(struct driver_data *drv_data) static void reset_sccr1(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; struct chip_data *chip = drv_data->cur_chip; u32 sccr1_reg; - sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1; + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; sccr1_reg &= ~SSCR1_RFT; sccr1_reg |= chip->threshold; - write_SSCR1(sccr1_reg, reg); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } static void int_error_stop(struct driver_data *drv_data, const char* msg) { - void __iomem *reg = drv_data->ioaddr; - /* Stop and reset SSP */ write_SSSR_CS(drv_data, drv_data->clear_sr); reset_sccr1(drv_data); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); pxa2xx_spi_flush(drv_data); - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); dev_err(&drv_data->pdev->dev, "%s\n", msg); @@ -576,13 +556,11 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) static void int_transfer_complete(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - /* Stop SSP */ write_SSSR_CS(drv_data, drv_data->clear_sr); reset_sccr1(drv_data); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); /* Update total byte transferred return count actual bytes read */ drv_data->cur_msg->actual_length += drv_data->len - @@ -601,12 +579,10 @@ static void int_transfer_complete(struct driver_data *drv_data) static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ? - drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; + u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ? + drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; - u32 irq_status = read_SSSR(reg) & irq_mask; + u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask; if (irq_status & SSSR_ROR) { int_error_stop(drv_data, "interrupt_transfer: fifo overrun"); @@ -614,7 +590,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) } if (irq_status & SSSR_TINT) { - write_SSSR(SSSR_TINT, reg); + pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT); if (drv_data->read(drv_data)) { int_transfer_complete(drv_data); return IRQ_HANDLED; @@ -638,7 +614,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) u32 bytes_left; u32 sccr1_reg; - sccr1_reg = read_SSCR1(reg); + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1); sccr1_reg &= ~SSCR1_TIE; /* @@ -664,7 +640,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre); } - write_SSCR1(sccr1_reg, reg); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } /* We did something */ @@ -674,7 +650,6 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; - void __iomem *reg = drv_data->ioaddr; u32 sccr1_reg; u32 mask = drv_data->mask_sr; u32 status; @@ -694,11 +669,11 @@ static irqreturn_t ssp_int(int irq, void *dev_id) * are all set to one. That means that the device is already * powered off. */ - status = read_SSSR(reg); + status = pxa2xx_spi_read(drv_data, SSSR); if (status == ~0) return IRQ_NONE; - sccr1_reg = read_SSCR1(reg); + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1); /* Ignore possible writes if we don't need to write */ if (!(sccr1_reg & SSCR1_TIE)) @@ -709,10 +684,14 @@ static irqreturn_t ssp_int(int irq, void *dev_id) if (!drv_data->cur_msg) { - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) + & ~SSCR0_SSE); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->int_cr1); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); write_SSSR_CS(drv_data, drv_data->clear_sr); dev_err(&drv_data->pdev->dev, @@ -781,7 +760,6 @@ static void pump_transfers(unsigned long data) struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; struct chip_data *chip = NULL; - void __iomem *reg = drv_data->ioaddr; u32 clk_div = 0; u8 bits = 0; u32 speed = 0; @@ -925,7 +903,7 @@ static void pump_transfers(unsigned long data) /* Clear status and start DMA engine */ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1; - write_SSSR(drv_data->clear_sr, reg); + pxa2xx_spi_write(drv_data, SSSR, drv_data->clear_sr); pxa2xx_spi_dma_start(drv_data); } else { @@ -938,39 +916,43 @@ static void pump_transfers(unsigned long data) } if (is_lpss_ssp(drv_data)) { - if ((read_SSIRF(reg) & 0xff) != chip->lpss_rx_threshold) - write_SSIRF(chip->lpss_rx_threshold, reg); - if ((read_SSITF(reg) & 0xffff) != chip->lpss_tx_threshold) - write_SSITF(chip->lpss_tx_threshold, reg); + if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff) + != chip->lpss_rx_threshold) + pxa2xx_spi_write(drv_data, SSIRF, + chip->lpss_rx_threshold); + if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff) + != chip->lpss_tx_threshold) + pxa2xx_spi_write(drv_data, SSITF, + chip->lpss_tx_threshold); } if (is_quark_x1000_ssp(drv_data) && - (read_DDS_RATE(reg) != chip->dds_rate)) - write_DDS_RATE(chip->dds_rate, reg); + (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate)) + pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate); /* see if we need to reload the config registers */ - if ((read_SSCR0(reg) != cr0) || - (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) { - + if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0) + || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask) + != (cr1 & change_mask)) { /* stop the SSP, and update the other bits */ - write_SSCR0(cr0 & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(chip->timeout, reg); + pxa2xx_spi_write(drv_data, SSTO, chip->timeout); /* first set CR1 without interrupt and service enables */ - write_SSCR1(cr1 & change_mask, reg); + pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask); /* restart the SSP */ - write_SSCR0(cr0, reg); + pxa2xx_spi_write(drv_data, SSCR0, cr0); } else { if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(chip->timeout, reg); + pxa2xx_spi_write(drv_data, SSTO, chip->timeout); } cs_assert(drv_data); /* after chip select, release the data by enabling service * requests and interrupts, without changing any mode bits */ - write_SSCR1(cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, cr1); } static int pxa2xx_spi_transfer_one_message(struct spi_master *master, @@ -999,8 +981,8 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) struct driver_data *drv_data = spi_master_get_devdata(master); /* Disable the SSP now */ - write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE, - drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); return 0; } @@ -1283,6 +1265,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) struct driver_data *drv_data; struct ssp_device *ssp; int status; + u32 tmp; platform_info = dev_get_platdata(dev); if (!platform_info) { @@ -1380,36 +1363,32 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) drv_data->max_clk_rate = clk_get_rate(ssp->clk); /* Load default SSP configuration */ - write_SSCR0(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, 0); switch (drv_data->ssp_type) { case QUARK_X1000_SSP: - write_SSCR1(QUARK_X1000_SSCR1_RxTresh( - RX_THRESH_QUARK_X1000_DFLT) | - QUARK_X1000_SSCR1_TxTresh( - TX_THRESH_QUARK_X1000_DFLT), - drv_data->ioaddr); + tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) + | QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT); + pxa2xx_spi_write(drv_data, SSCR1, tmp); /* using the Motorola SPI protocol and use 8 bit frame */ - write_SSCR0(QUARK_X1000_SSCR0_Motorola - | QUARK_X1000_SSCR0_DataSize(8), - drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, + QUARK_X1000_SSCR0_Motorola + | QUARK_X1000_SSCR0_DataSize(8)); break; default: - write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) | - SSCR1_TxTresh(TX_THRESH_DFLT), - drv_data->ioaddr); - write_SSCR0(SSCR0_SCR(2) - | SSCR0_Motorola - | SSCR0_DataSize(8), - drv_data->ioaddr); + tmp = SSCR1_RxTresh(RX_THRESH_DFLT) | + SSCR1_TxTresh(TX_THRESH_DFLT); + pxa2xx_spi_write(drv_data, SSCR1, tmp); + tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8); + pxa2xx_spi_write(drv_data, SSCR0, tmp); break; } if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSTO, 0); if (!is_quark_x1000_ssp(drv_data)) - write_SSPSP(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSPSP, 0); if (is_lpss_ssp(drv_data)) lpss_ssp_setup(drv_data); @@ -1455,7 +1434,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); /* Disable the SSP at the peripheral and SOC level */ - write_SSCR0(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, 0); clk_disable_unprepare(ssp->clk); /* Release DMA */ @@ -1492,7 +1471,7 @@ static int pxa2xx_spi_suspend(struct device *dev) status = spi_master_suspend(drv_data->master); if (status != 0) return status; - write_SSCR0(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, 0); if (!pm_runtime_suspended(dev)) clk_disable_unprepare(ssp->clk); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 6bec59c..85a58c9 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -115,23 +115,17 @@ struct chip_data { void (*cs_control)(u32 command); }; -#define DEFINE_SSP_REG(reg, off) \ -static inline u32 read_##reg(void const __iomem *p) \ -{ return __raw_readl(p + (off)); } \ -\ -static inline void write_##reg(u32 v, void __iomem *p) \ -{ __raw_writel(v, p + (off)); } - -DEFINE_SSP_REG(SSCR0, 0x00) -DEFINE_SSP_REG(SSCR1, 0x04) -DEFINE_SSP_REG(SSSR, 0x08) -DEFINE_SSP_REG(SSITR, 0x0c) -DEFINE_SSP_REG(SSDR, 0x10) -DEFINE_SSP_REG(DDS_RATE, 0x28) /* DDS Clock Rate */ -DEFINE_SSP_REG(SSTO, 0x28) -DEFINE_SSP_REG(SSPSP, 0x2c) -DEFINE_SSP_REG(SSITF, SSITF) -DEFINE_SSP_REG(SSIRF, SSIRF) +static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, + unsigned reg) +{ + return __raw_readl(drv_data->ioaddr + reg); +} + +static inline void pxa2xx_spi_write(const struct driver_data *drv_data, + unsigned reg, u32 val) +{ + __raw_writel(val, drv_data->ioaddr + reg); +} #define START_STATE ((void *)0) #define RUNNING_STATE ((void *)1) @@ -155,13 +149,11 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data) static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) { - void __iomem *reg = drv_data->ioaddr; - if (drv_data->ssp_type == CE4100_SSP || drv_data->ssp_type == QUARK_X1000_SSP) - val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; + val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK; - write_SSSR(val, reg); + pxa2xx_spi_write(drv_data, SSSR, val); } extern int pxa2xx_spi_flush(struct driver_data *drv_data); -- cgit v0.10.2 From 74d50da3e47f9e0b9eba2be4372556aa82d0f05d Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 22 Dec 2014 13:40:20 +0100 Subject: livepatch: MAINTAINERS: add git tree location Update MAINTAINERS entry for live patching infrastructure so that it points to git tree hosted at kernel.org. Signed-off-by: Jiri Kosina diff --git a/MAINTAINERS b/MAINTAINERS index afe93ea..cff1f33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5797,6 +5797,7 @@ F: arch/x86/kernel/livepatch.c F: Documentation/ABI/testing/sysfs-kernel-livepatch F: samples/livepatch/ L: live-patching@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git LLC (802.2) M: Arnaldo Carvalho de Melo -- cgit v0.10.2 From b2e5dda14fbc2ca1155c614c500c6de6f5b4ba8c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 23 Dec 2014 00:27:41 +0000 Subject: spi/dln2: Fix for PM_RUNTIME removal Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c index 7b35454..cede063 100644 --- a/drivers/spi/spi-dln2.c +++ b/drivers/spi/spi-dln2.c @@ -850,7 +850,7 @@ static int dln2_spi_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int dln2_spi_runtime_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); -- cgit v0.10.2 From 6ca7a8a15035add0a4f9b2fd658118d41dbeb20c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 21 Dec 2014 15:02:23 +0100 Subject: x86/fpu: Use a symbolic name for asm operand Fix up the else-case in fpu_fxsave() which seems like it has been overlooked. Correct comment style in restore_fpu_checking() while at it. Signed-off-by: Borislav Petkov Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1419170543-11393-1-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index e97622f..0dbc082 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -207,7 +207,7 @@ static inline void fpu_fxsave(struct fpu *fpu) if (config_enabled(CONFIG_X86_32)) asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave)); else if (config_enabled(CONFIG_AS_FXSAVEQ)) - asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave)); + asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state->fxsave)); else { /* Using "rex64; fxsave %0" is broken because, if the memory * operand uses any extended registers for addressing, a second @@ -290,9 +290,11 @@ static inline int fpu_restore_checking(struct fpu *fpu) static inline int restore_fpu_checking(struct task_struct *tsk) { - /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception - is pending. Clear the x87 state here by setting it to fixed - values. "m" is a random variable that should be in L1 */ + /* + * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is + * pending. Clear the x87 state here by setting it to fixed values. + * "m" is a random variable that should be in L1. + */ if (unlikely(static_cpu_has_bug_safe(X86_BUG_FXSAVE_LEAK))) { asm volatile( "fnclex\n\t" -- cgit v0.10.2 From 2b261f9f7bd9333e62140ca7e02a2f4ffec5e44f Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 21 Dec 2014 13:58:18 +0100 Subject: x86/platform: Remove unused function from apb_timer.c Remove the function is_apbt_capable() that is not used anywhere. This was partially found by using a static code analysis program called 'cppcheck'. Signed-off-by: Rickard Strandqvist Reviewed-by: Jiang Liu Cc: Christoph Lameter Cc: Tejun Heo Link: http://lkml.kernel.org/r/1419166698-2470-1-git-send-email-rickard_strandqvist@spectrumdigital.se Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index b708738..6a7c23f 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -135,14 +135,6 @@ static inline void apbt_clear_mapping(void) apbt_virt_address = NULL; } -/* - * APBT timer interrupt enable / disable - */ -static inline int is_apbt_capable(void) -{ - return apbt_virt_address ? 1 : 0; -} - static int __init apbt_clockevent_register(void) { struct sfi_timer_table_entry *mtmr; -- cgit v0.10.2 From aadec012eabf0e5147103cfd2ffde27e5aad65e2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 25 Sep 2014 09:22:00 -0300 Subject: [media] omap3isp: Fix division by 0 If the requested clock rate passed to the XCLK set_rate or round_rate operation is 0, the driver will try to divide by 0. Fix this. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 51c2129..deca809 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -220,6 +220,9 @@ static u32 isp_xclk_calc_divider(unsigned long *rate, unsigned long parent_rate) return ISPTCTRL_CTRL_DIV_BYPASS; } + if (*rate == 0) + *rate = 1; + divider = DIV_ROUND_CLOSEST(parent_rate, *rate); if (divider >= ISPTCTRL_CTRL_DIV_BYPASS) divider = ISPTCTRL_CTRL_DIV_BYPASS - 1; -- cgit v0.10.2 From 3e90f789739e5685da0d0b716b04e49e17671877 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Nov 2013 01:03:10 -0300 Subject: [media] v4l: omap4iss: Enable DMABUF support Enable DMABUF import and export operations using videobuf2. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index cdee596..2085f69 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -773,6 +773,14 @@ iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) } static int +iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e) +{ + struct iss_video_fh *vfh = to_iss_video_fh(fh); + + return vb2_expbuf(&vfh->queue, e); +} + +static int iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) { struct iss_video_fh *vfh = to_iss_video_fh(fh); @@ -1021,6 +1029,7 @@ static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { .vidioc_reqbufs = iss_video_reqbufs, .vidioc_querybuf = iss_video_querybuf, .vidioc_qbuf = iss_video_qbuf, + .vidioc_expbuf = iss_video_expbuf, .vidioc_dqbuf = iss_video_dqbuf, .vidioc_streamon = iss_video_streamon, .vidioc_streamoff = iss_video_streamoff, @@ -1071,7 +1080,7 @@ static int iss_video_open(struct file *file) q = &handle->queue; q->type = video->type; - q->io_modes = VB2_MMAP; + q->io_modes = VB2_MMAP | VB2_DMABUF; q->drv_priv = handle; q->ops = &iss_video_vb2ops; q->mem_ops = &vb2_dma_contig_memops; -- cgit v0.10.2 From dd162547f10132b8ea63adb7f795acc5020616fd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Jul 2014 18:31:24 -0300 Subject: [media] v4l: omap4iss: Remove bogus frame number propagation Frame number propagation tries to increase the robustness of the frame number counter by using sources less likely to be missed than the end of frame interrupts, such as hardware frame counters or start of frame interrupts. Increasing the frame number in the IPIPE ISIF and resizer end of frame interrupt handlers is pointless as it doesn't bring any improvement. Don't do it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index 32a7483..3943fae 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -242,23 +242,6 @@ static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif) } /* - * ipipeif_isif0_isr - Handle ISIF0 event - * @ipipeif: Pointer to ISP IPIPEIF device. - * - * Executes LSC deferred enablement before next frame starts. - */ -static void ipipeif_isif0_isr(struct iss_ipipeif_device *ipipeif) -{ - struct iss_pipeline *pipe = - to_iss_pipeline(&ipipeif->subdev.entity); - if (pipe->do_propagation) - atomic_inc(&pipe->frame_number); - - if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) - ipipeif_isr_buffer(ipipeif); -} - -/* * omap4iss_ipipeif_isr - Configure ipipeif during interframe time. * @ipipeif: Pointer to ISP IPIPEIF device. * @events: IPIPEIF events @@ -269,8 +252,9 @@ void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events) &ipipeif->stopping)) return; - if (events & ISP5_IRQ_ISIF_INT(0)) - ipipeif_isif0_isr(ipipeif); + if ((events & ISP5_IRQ_ISIF_INT(0)) && + (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) + ipipeif_isr_buffer(ipipeif); } /* ----------------------------------------------------------------------------- diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index 88522a8..3ab9728 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -283,22 +283,6 @@ static void resizer_isr_buffer(struct iss_resizer_device *resizer) } /* - * resizer_isif0_isr - Handle ISIF0 event - * @resizer: Pointer to ISP RESIZER device. - * - * Executes LSC deferred enablement before next frame starts. - */ -static void resizer_int_dma_isr(struct iss_resizer_device *resizer) -{ - struct iss_pipeline *pipe = - to_iss_pipeline(&resizer->subdev.entity); - if (pipe->do_propagation) - atomic_inc(&pipe->frame_number); - - resizer_isr_buffer(resizer); -} - -/* * omap4iss_resizer_isr - Configure resizer during interframe time. * @resizer: Pointer to ISP RESIZER device. * @events: RESIZER events @@ -322,7 +306,7 @@ void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events) return; if (events & ISP5_IRQ_RSZ_INT_DMA) - resizer_int_dma_isr(resizer); + resizer_isr_buffer(resizer); } /* ----------------------------------------------------------------------------- -- cgit v0.10.2 From 707acfc072676d4b9f5db8d2082e2f0c79c34bb4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Jul 2014 18:44:15 -0300 Subject: [media] v4l: omap4iss: csi2: Perform real frame number propagation Compute the pipeline frame number from the frame number sent by the sensor instead of incrementing the frame number in software. This improves dropped frames detection. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index cc1dfad..d6534f5 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -612,7 +612,12 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe, ret = v4l2_subdev_call(subdev, video, s_stream, mode); if (ret < 0 && ret != -ENOIOCTLCMD) return ret; + + if (subdev == &iss->csi2a.subdev || + subdev == &iss->csi2b.subdev) + pipe->do_propagation = true; } + iss_print_status(pipe->output->iss); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index 21971c6..2d96fb3 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -319,6 +319,8 @@ static void csi2_ctx_config(struct iss_csi2_device *csi2, { u32 reg = 0; + ctx->frame = 0; + /* Set up CSI2_CTx_CTRL1 */ if (ctx->eof_enabled) reg = CSI2_CTX_CTRL1_EOF_EN; @@ -396,21 +398,18 @@ static void csi2_timing_config(struct iss_csi2_device *csi2, */ static void csi2_irq_ctx_set(struct iss_csi2_device *csi2, int enable) { - u32 reg = CSI2_CTX_IRQ_FE; + const u32 mask = CSI2_CTX_IRQ_FE | CSI2_CTX_IRQ_FS; int i; - if (csi2->use_fs_irq) - reg |= CSI2_CTX_IRQ_FS; - for (i = 0; i < 8; i++) { iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(i), - reg); + mask); if (enable) iss_reg_set(csi2->iss, csi2->regs1, - CSI2_CTX_IRQENABLE(i), reg); + CSI2_CTX_IRQENABLE(i), mask); else iss_reg_clr(csi2->iss, csi2->regs1, - CSI2_CTX_IRQENABLE(i), reg); + CSI2_CTX_IRQENABLE(i), mask); } } @@ -679,8 +678,34 @@ static void csi2_isr_ctx(struct iss_csi2_device *csi2, if (status & CSI2_CTX_IRQ_FS) { struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); - if (pipe->do_propagation) + u16 frame; + u16 delta; + + frame = iss_reg_read(csi2->iss, csi2->regs1, + CSI2_CTX_CTRL2(ctx->ctxnum)) + >> CSI2_CTX_CTRL2_FRAME_SHIFT; + + if (frame == 0) { + /* A zero value means that the counter isn't implemented + * by the source. Increment the frame number in software + * in that case. + */ atomic_inc(&pipe->frame_number); + } else { + /* Extend the 16 bit frame number to 32 bits by + * computing the delta between two consecutive CSI2 + * frame numbers and adding it to the software frame + * number. The hardware counter starts at 1 and wraps + * from 0xffff to 1 without going through 0, so subtract + * 1 when the counter wraps. + */ + delta = frame - ctx->frame; + if (frame < ctx->frame) + delta--; + ctx->frame = frame; + + atomic_add(delta, &pipe->frame_number); + } } if (!(status & CSI2_CTX_IRQ_FE)) @@ -1039,7 +1064,6 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct iss_device *iss = csi2->iss; - struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); struct iss_video *video_out = &csi2->video_out; int ret = 0; @@ -1058,7 +1082,6 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) if (omap4iss_csiphy_acquire(csi2->phy) < 0) return -ENODEV; - csi2->use_fs_irq = pipe->do_propagation; csi2_configure(csi2); csi2_print_status(csi2); diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h index 971aa7b..3b37978 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.h +++ b/drivers/staging/media/omap4iss/iss_csi2.h @@ -82,6 +82,7 @@ struct iss_csi2_ctx_cfg { u8 virtual_id; u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */ u8 dpcm_predictor; /* 1: simple, 0: advanced */ + u16 frame; /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */ u16 alpha; @@ -137,7 +138,6 @@ struct iss_csi2_device { u32 output; /* output to IPIPEIF, memory or both? */ bool dpcm_decompress; unsigned int frame_skip; - bool use_fs_irq; struct iss_csiphy *phy; struct iss_csi2_ctx_cfg contexts[ISS_CSI2_MAX_CTX_NUM + 1]; diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h index efd0291..d2b6b6a 100644 --- a/drivers/staging/media/omap4iss/iss_regs.h +++ b/drivers/staging/media/omap4iss/iss_regs.h @@ -215,6 +215,8 @@ #define CSI2_CTX_CTRL1_CTX_EN (1 << 0) #define CSI2_CTX_CTRL2(i) (0x74 + (0x20 * i)) +#define CSI2_CTX_CTRL2_FRAME_MASK (0xffff << 16) +#define CSI2_CTX_CTRL2_FRAME_SHIFT 16 #define CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 #define CSI2_CTX_CTRL2_USER_DEF_MAP_MASK \ (0x3 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT) -- cgit v0.10.2 From 9587a3fc4333efd9cfd56a0754cabf76bdcdb3b0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 28 Oct 2014 09:07:37 -0300 Subject: [media] v4l: omap4iss: Stop started entities when pipeline start fails If an entity can't be started when starting a pipeline we need to clean up by stopping all entities that have been successfully started. Otherwise the hardware and software states won't match, potentially leading to crashes (for instance due to the CSI2 receiver receiving interrupts with a NULL pipeline pointer). Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index d6534f5..44b81a2 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -560,6 +560,61 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags, */ /* + * iss_pipeline_disable - Disable streaming on a pipeline + * @pipe: ISS pipeline + * @until: entity at which to stop pipeline walk + * + * Walk the entities chain starting at the pipeline output video node and stop + * all modules in the chain. Wait synchronously for the modules to be stopped if + * necessary. + * + * If the until argument isn't NULL, stop the pipeline walk when reaching the + * until entity. This is used to disable a partially started pipeline due to a + * subdev start error. + */ +static int iss_pipeline_disable(struct iss_pipeline *pipe, + struct media_entity *until) +{ + struct iss_device *iss = pipe->output->iss; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int failure = 0; + int ret; + + entity = &pipe->output->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + if (entity == until) + break; + + subdev = media_entity_to_v4l2_subdev(entity); + ret = v4l2_subdev_call(subdev, video, s_stream, 0); + if (ret < 0) { + dev_dbg(iss->dev, "%s: module stop timeout.\n", + subdev->name); + /* If the entity failed to stopped, assume it has + * crashed. Mark it as such, the ISS will be reset when + * applications will release it. + */ + iss->crashed |= 1U << subdev->entity.id; + failure = -ETIMEDOUT; + } + } + + return failure; +} + +/* * iss_pipeline_enable - Enable streaming on a pipeline * @pipe: ISS pipeline * @mode: Stream mode (single shot or continuous) @@ -610,8 +665,10 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe, subdev = media_entity_to_v4l2_subdev(entity); ret = v4l2_subdev_call(subdev, video, s_stream, mode); - if (ret < 0 && ret != -ENOIOCTLCMD) + if (ret < 0 && ret != -ENOIOCTLCMD) { + iss_pipeline_disable(pipe, entity); return ret; + } if (subdev == &iss->csi2a.subdev || subdev == &iss->csi2b.subdev) @@ -623,53 +680,6 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe, } /* - * iss_pipeline_disable - Disable streaming on a pipeline - * @pipe: ISS pipeline - * - * Walk the entities chain starting at the pipeline output video node and stop - * all modules in the chain. Wait synchronously for the modules to be stopped if - * necessary. - */ -static int iss_pipeline_disable(struct iss_pipeline *pipe) -{ - struct iss_device *iss = pipe->output->iss; - struct media_entity *entity; - struct media_pad *pad; - struct v4l2_subdev *subdev; - int failure = 0; - int ret; - - entity = &pipe->output->video.entity; - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - entity = pad->entity; - subdev = media_entity_to_v4l2_subdev(entity); - - ret = v4l2_subdev_call(subdev, video, s_stream, 0); - if (ret < 0) { - dev_dbg(iss->dev, "%s: module stop timeout.\n", - subdev->name); - /* If the entity failed to stopped, assume it has - * crashed. Mark it as such, the ISS will be reset when - * applications will release it. - */ - iss->crashed |= 1U << subdev->entity.id; - failure = -ETIMEDOUT; - } - } - - return failure; -} - -/* * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline * @pipe: ISS pipeline * @state: Stream state (stopped, single shot or continuous) @@ -687,7 +697,7 @@ int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe, int ret; if (state == ISS_PIPELINE_STREAM_STOPPED) - ret = iss_pipeline_disable(pipe); + ret = iss_pipeline_disable(pipe, NULL); else ret = iss_pipeline_enable(pipe, state); -- cgit v0.10.2 From 5fb3f55504d5d9b6ca97131091707afd351fe1dc Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 26 Nov 2014 20:25:44 -0300 Subject: [media] media: usb: uvc: use vb2_ops_wait_prepare/finish helper This patch drops driver specific wait_prepare() and wait_finish() callbacks from vb2_ops and instead uses the the helpers vb2_ops_wait_prepare/finish() provided by the vb2 core, the lock member of the queue needs to be initalized to a mutex so that vb2 helpers vb2_ops_wait_prepare/finish() can make use of it. Signed-off-by: Lad, Prabhakar Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cc96072..10c554e 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -143,20 +143,6 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) uvc_video_clock_update(stream, &vb->v4l2_buf, buf); } -static void uvc_wait_prepare(struct vb2_queue *vq) -{ - struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - - mutex_unlock(&queue->mutex); -} - -static void uvc_wait_finish(struct vb2_queue *vq) -{ - struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - - mutex_lock(&queue->mutex); -} - static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); @@ -195,8 +181,8 @@ static struct vb2_ops uvc_queue_qops = { .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, .buf_finish = uvc_buffer_finish, - .wait_prepare = uvc_wait_prepare, - .wait_finish = uvc_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = uvc_start_streaming, .stop_streaming = uvc_stop_streaming, }; @@ -214,6 +200,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.mem_ops = &vb2_vmalloc_memops; queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | V4L2_BUF_FLAG_TSTAMP_SRC_SOE; + queue->queue.lock = &queue->mutex; ret = vb2_queue_init(&queue->queue); if (ret) return ret; -- cgit v0.10.2 From 1b8dc32286a1a4fb73cfc7793ef103f3993a6478 Mon Sep 17 00:00:00 2001 From: William Manley Date: Mon, 8 Dec 2014 15:57:58 -0300 Subject: [media] uvcvideo: Add GUID for BGR 8:8:8 The Magewell XI100DUSB-HDMI[1] video capture device reports the pixel format "e436eb7d-524f-11ce-9f53-0020af0ba770". This is its GUID for BGR 8:8:8. The UVC 1.5 spec[2] only defines GUIDs for YUY2, NV12, M420 and I420. This seems to be an extension documented in the Microsoft Windows Media Format SDK[3] - or at least the Media Format SDK was the only hit that Google gave when searching for the GUID. This Media Format SDK defines this GUID as corresponding to `MEDIASUBTYPE_RGB24`. Note though, the XI100DUSB outputs BGR e.g. byte-reversed. I don't know if its the capture device in error or Microsoft mean BGR when they say RGB. [1]: http://www.magewell.com/hardware/dongles/xi100dusb-hdmi/xi100dusb-hdmi_features.html?lang=en [2]: http://www.usb.org/developers/docs/devclass_docs/USB_Video_Class_1_5.zip [3]: http://msdn.microsoft.com/en-gb/library/windows/desktop/dd757532(v=vs.85).aspx Signed-off-by: William Manley Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 6a4b0b8..cf27006 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -138,6 +138,11 @@ static struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_RGB565, }, { + .name = "BGR 8:8:8 (BGR3)", + .guid = UVC_GUID_FORMAT_BGR3, + .fcc = V4L2_PIX_FMT_BGR24, + }, + { .name = "H.264", .guid = UVC_GUID_FORMAT_H264, .fcc = V4L2_PIX_FMT_H264, diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index f0a04b5..c63e5b5 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -109,6 +109,9 @@ #define UVC_GUID_FORMAT_RGBP \ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BGR3 \ + { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \ + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} #define UVC_GUID_FORMAT_M420 \ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -- cgit v0.10.2 From 32d17597d3e299ffe8b07e3afc12f8074e7ae483 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Apr 2014 08:13:18 -0300 Subject: [media] v4l: vsp1: Remove support for platform data Now that all platforms instantiate the VSP1 through DT, platform data support isn't needed anymore. Signed-off-by: Laurent Pinchart Acked-by: Simon Horman Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 765bffb..480a174 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -223,7 +223,7 @@ config VIDEO_SH_VEU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on ARCH_SHMOBILE || COMPILE_TEST + depends on (ARCH_SHMOBILE && OF) || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 1246719..989e96f 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -40,9 +39,20 @@ struct vsp1_uds; #define VSP1_MAX_UDS 3 #define VSP1_MAX_WPF 4 +#define VSP1_HAS_LIF (1 << 0) +#define VSP1_HAS_LUT (1 << 1) +#define VSP1_HAS_SRU (1 << 2) + +struct vsp1_platform_data { + unsigned int features; + unsigned int rpf_count; + unsigned int uds_count; + unsigned int wpf_count; +}; + struct vsp1_device { struct device *dev; - struct vsp1_platform_data *pdata; + struct vsp1_platform_data pdata; void __iomem *mmio; struct clk *clock; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 5eb16e8..913485a 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -40,7 +40,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) irqreturn_t ret = IRQ_NONE; unsigned int i; - for (i = 0; i < vsp1->pdata->wpf_count; ++i) { + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; u32 status; @@ -181,7 +181,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); - if (vsp1->pdata->features & VSP1_HAS_LIF) { + if (vsp1->pdata.features & VSP1_HAS_LIF) { vsp1->lif = vsp1_lif_create(vsp1); if (IS_ERR(vsp1->lif)) { ret = PTR_ERR(vsp1->lif); @@ -191,7 +191,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); } - if (vsp1->pdata->features & VSP1_HAS_LUT) { + if (vsp1->pdata.features & VSP1_HAS_LUT) { vsp1->lut = vsp1_lut_create(vsp1); if (IS_ERR(vsp1->lut)) { ret = PTR_ERR(vsp1->lut); @@ -201,7 +201,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->pdata->rpf_count; ++i) { + for (i = 0; i < vsp1->pdata.rpf_count; ++i) { struct vsp1_rwpf *rpf; rpf = vsp1_rpf_create(vsp1, i); @@ -214,7 +214,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&rpf->entity.list_dev, &vsp1->entities); } - if (vsp1->pdata->features & VSP1_HAS_SRU) { + if (vsp1->pdata.features & VSP1_HAS_SRU) { vsp1->sru = vsp1_sru_create(vsp1); if (IS_ERR(vsp1->sru)) { ret = PTR_ERR(vsp1->sru); @@ -224,7 +224,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->pdata->uds_count; ++i) { + for (i = 0; i < vsp1->pdata.uds_count; ++i) { struct vsp1_uds *uds; uds = vsp1_uds_create(vsp1, i); @@ -237,7 +237,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&uds->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->pdata->wpf_count; ++i) { + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { struct vsp1_rwpf *wpf; wpf = vsp1_wpf_create(vsp1, i); @@ -261,7 +261,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) goto done; } - if (vsp1->pdata->features & VSP1_HAS_LIF) { + if (vsp1->pdata.features & VSP1_HAS_LIF) { ret = media_entity_create_link( &vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE, &vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0); @@ -294,7 +294,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1) /* Reset any channel that might be running. */ status = vsp1_read(vsp1, VI6_STATUS); - for (i = 0; i < vsp1->pdata->wpf_count; ++i) { + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { unsigned int timeout; if (!(status & VI6_STATUS_SYS_ACT(i))) @@ -318,10 +318,10 @@ static int vsp1_device_init(struct vsp1_device *vsp1) vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); - for (i = 0; i < vsp1->pdata->rpf_count; ++i) + for (i = 0; i < vsp1->pdata.rpf_count; ++i) vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); - for (i = 0; i < vsp1->pdata->uds_count; ++i) + for (i = 0; i < vsp1->pdata.uds_count; ++i) vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); @@ -428,28 +428,36 @@ static const struct dev_pm_ops vsp1_pm_ops = { * Platform Driver */ -static int vsp1_validate_platform_data(struct platform_device *pdev, - struct vsp1_platform_data *pdata) +static int vsp1_parse_dt(struct vsp1_device *vsp1) { - if (pdata == NULL) { - dev_err(&pdev->dev, "missing platform data\n"); - return -EINVAL; - } + struct device_node *np = vsp1->dev->of_node; + struct vsp1_platform_data *pdata = &vsp1->pdata; + + if (of_property_read_bool(np, "renesas,has-lif")) + pdata->features |= VSP1_HAS_LIF; + if (of_property_read_bool(np, "renesas,has-lut")) + pdata->features |= VSP1_HAS_LUT; + if (of_property_read_bool(np, "renesas,has-sru")) + pdata->features |= VSP1_HAS_SRU; + + of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count); + of_property_read_u32(np, "renesas,#uds", &pdata->uds_count); + of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count); if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) { - dev_err(&pdev->dev, "invalid number of RPF (%u)\n", + dev_err(vsp1->dev, "invalid number of RPF (%u)\n", pdata->rpf_count); return -EINVAL; } if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) { - dev_err(&pdev->dev, "invalid number of UDS (%u)\n", + dev_err(vsp1->dev, "invalid number of UDS (%u)\n", pdata->uds_count); return -EINVAL; } if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) { - dev_err(&pdev->dev, "invalid number of WPF (%u)\n", + dev_err(vsp1->dev, "invalid number of WPF (%u)\n", pdata->wpf_count); return -EINVAL; } @@ -457,33 +465,6 @@ static int vsp1_validate_platform_data(struct platform_device *pdev, return 0; } -static struct vsp1_platform_data * -vsp1_get_platform_data(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct vsp1_platform_data *pdata; - - if (!IS_ENABLED(CONFIG_OF) || np == NULL) - return pdev->dev.platform_data; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) - return NULL; - - if (of_property_read_bool(np, "renesas,has-lif")) - pdata->features |= VSP1_HAS_LIF; - if (of_property_read_bool(np, "renesas,has-lut")) - pdata->features |= VSP1_HAS_LUT; - if (of_property_read_bool(np, "renesas,has-sru")) - pdata->features |= VSP1_HAS_SRU; - - of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count); - of_property_read_u32(np, "renesas,#uds", &pdata->uds_count); - of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count); - - return pdata; -} - static int vsp1_probe(struct platform_device *pdev) { struct vsp1_device *vsp1; @@ -499,11 +480,7 @@ static int vsp1_probe(struct platform_device *pdev) mutex_init(&vsp1->lock); INIT_LIST_HEAD(&vsp1->entities); - vsp1->pdata = vsp1_get_platform_data(pdev); - if (vsp1->pdata == NULL) - return -ENODEV; - - ret = vsp1_validate_platform_data(pdev, vsp1->pdata); + ret = vsp1_parse_dt(vsp1); if (ret < 0) return ret; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 6e05776..b1089d0 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -280,7 +280,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) * except for the WPF0 source link if a LIF is present. */ flags = MEDIA_LNK_FL_ENABLED; - if (!(vsp1->pdata->features & VSP1_HAS_LIF) || index != 0) + if (!(vsp1->pdata.features & VSP1_HAS_LIF) || index != 0) flags |= MEDIA_LNK_FL_IMMUTABLE; ret = media_entity_create_link(&wpf->entity.subdev.entity, diff --git a/include/linux/platform_data/vsp1.h b/include/linux/platform_data/vsp1.h deleted file mode 100644 index 63170e26..0000000 --- a/include/linux/platform_data/vsp1.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * vsp1.h -- R-Car VSP1 Platform Data - * - * Copyright (C) 2013 Renesas Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef __PLATFORM_VSP1_H__ -#define __PLATFORM_VSP1_H__ - -#define VSP1_HAS_LIF (1 << 0) -#define VSP1_HAS_LUT (1 << 1) -#define VSP1_HAS_SRU (1 << 2) - -struct vsp1_platform_data { - unsigned int features; - unsigned int rpf_count; - unsigned int uds_count; - unsigned int wpf_count; -}; - -#endif /* __PLATFORM_VSP1_H__ */ -- cgit v0.10.2 From 857161fc7d3734f8fd8707f1bc756c1158694371 Mon Sep 17 00:00:00 2001 From: Takanari Hayama Date: Wed, 26 Nov 2014 22:25:01 -0300 Subject: [media] v4l: vsp1: Reset VSP1 RPF source address Source address of VSP1 RPF needs to be reset whenever crop offsets are recalculated. This correctly reflects a crop setting even VIDIOC_QBUF is called before VIDIOC_STREAMON is called. Signed-off-by: Takanari Hayama Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index d14d26b..3294529 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -106,11 +106,22 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) + crop->left * fmtinfo->bpp[0] / 8; pstride = format->plane_fmt[0].bytesperline << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; + + vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, + rpf->buf_addr[0] + rpf->offsets[0]); + if (format->num_planes > 1) { rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline + crop->left * fmtinfo->bpp[1] / 8; pstride |= format->plane_fmt[1].bytesperline << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; + + vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, + rpf->buf_addr[1] + rpf->offsets[1]); + + if (format->num_planes > 2) + vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, + rpf->buf_addr[2] + rpf->offsets[1]); } vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride); @@ -179,6 +190,13 @@ static void rpf_vdev_queue(struct vsp1_video *video, struct vsp1_video_buffer *buf) { struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video); + unsigned int i; + + for (i = 0; i < 3; ++i) + rpf->buf_addr[i] = buf->addr[i]; + + if (!vsp1_entity_is_streaming(&rpf->entity)) + return; vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0] + rpf->offsets[0]); diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 28dd9e7..2cf1f13 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -39,6 +39,7 @@ struct vsp1_rwpf { struct v4l2_rect crop; unsigned int offsets[2]; + dma_addr_t buf_addr[3]; }; static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) -- cgit v0.10.2 From 5d0beeec59e303c76160ddd67fa73dcfc5d76de0 Mon Sep 17 00:00:00 2001 From: Takanari Hayama Date: Wed, 26 Nov 2014 22:25:02 -0300 Subject: [media] v4l: vsp1: Always enable virtual RPF when BRU is in use Regardless of a number of inputs, we should always enable virtual RPF when BRU is used. This allows the case when there's only one input to BRU, and a size of the input is smaller than a size of an output of BRU. Signed-off-by: Takanari Hayama Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index b1089d0..1d2b3a2 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -92,19 +92,20 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) return 0; } - /* Sources. If the pipeline has a single input configure it as the - * master layer. Otherwise configure all inputs as sub-layers and - * select the virtual RPF as the master layer. + /* Sources. If the pipeline has a single input and BRU is not used, + * configure it as the master layer. Otherwise configure all + * inputs as sub-layers and select the virtual RPF as the master + * layer. */ for (i = 0; i < pipe->num_inputs; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; - srcrpf |= pipe->num_inputs == 1 + srcrpf |= (!pipe->bru && pipe->num_inputs == 1) ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } - if (pipe->num_inputs > 1) + if (pipe->bru || pipe->num_inputs > 1) srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); -- cgit v0.10.2 From 5ede94c7055392bb55c6d2e26f1912f68ef4b875 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:27:54 -0300 Subject: [media] cx25821: remove bogus btcx_risc dependency Those btcx_risc functions are meant for use with bttv, other drivers should just allocate the memory themselves. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 6439a84..0e69cab 100644 --- a/drivers/media/pci/cx25821/Kconfig +++ b/drivers/media/pci/cx25821/Kconfig @@ -2,7 +2,6 @@ config VIDEO_CX25821 tristate "Conexant cx25821 support" depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT - select VIDEO_BTCX select VIDEOBUF_DMA_SG ---help--- This is a video4linux driver for Conexant 25821 based diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index fb76c3d..5872feb 100644 --- a/drivers/media/pci/cx25821/Makefile +++ b/drivers/media/pci/cx25821/Makefile @@ -6,4 +6,3 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821.o obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o ccflags-y += -Idrivers/media/i2c -ccflags-y += -Idrivers/media/common diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 2dd5bca..27e6493 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -63,7 +63,7 @@ static int devno; struct cx25821_audio_buffer { unsigned int bpl; - struct btcx_riscmem risc; + struct cx25821_riscmem risc; struct videobuf_dmabuf dma; }; @@ -330,12 +330,14 @@ out: static int dsp_buffer_free(struct cx25821_audio_dev *chip) { + struct cx25821_riscmem *risc = &chip->buf->risc; + BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); videobuf_dma_free(chip->dma_risc); - btcx_riscmem_free(chip->pci, &chip->buf->risc); + pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); kfree(chip->buf); chip->dma_risc = NULL; diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 389fffd..c8c65b7 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -979,6 +979,27 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) } EXPORT_SYMBOL(cx25821_dev_unregister); +int cx25821_riscmem_alloc(struct pci_dev *pci, + struct cx25821_riscmem *risc, + unsigned int size) +{ + __le32 *cpu; + dma_addr_t dma = 0; + + if (NULL != risc->cpu && risc->size < size) + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + if (NULL == risc->cpu) { + cpu = pci_zalloc_consistent(pci, size, &dma); + if (NULL == cpu) + return -ENOMEM; + risc->cpu = cpu; + risc->dma = dma; + risc->size = size; + } + return 0; +} +EXPORT_SYMBOL(cx25821_riscmem_alloc); + static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, @@ -1035,7 +1056,7 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, return rp; } -int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) @@ -1059,7 +1080,7 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 2; - rc = btcx_riscmem_alloc(pci, risc, instructions * 12); + rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); if (rc < 0) return rc; @@ -1146,7 +1167,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, } int cx25821_risc_databuffer_audio(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi) @@ -1163,7 +1184,7 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; - rc = btcx_riscmem_alloc(pci, risc, instructions * 12); + rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); if (rc < 0) return rc; @@ -1179,13 +1200,13 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci, } EXPORT_SYMBOL(cx25821_risc_databuffer_audio); -int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx25821_risc_stopper(struct pci_dev *pci, struct cx25821_riscmem *risc, u32 reg, u32 mask, u32 value) { __le32 *rp; int rc; - rc = btcx_riscmem_alloc(pci, risc, 4 * 16); + rc = cx25821_riscmem_alloc(pci, risc, 4 * 16); if (rc < 0) return rc; @@ -1211,7 +1232,8 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + pci_free_consistent(to_pci_dev(q->dev), + buf->risc.size, buf->risc.cpu, buf->risc.dma); buf->vb.state = VIDEOBUF_NEEDS_INIT; } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 3a419f1..3eda1a1 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1017,11 +1017,13 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) cx_clear(PCI_INT_MSK, 1); if (video_is_registered(&dev->channels[chan_num].vdev)) { + struct cx25821_riscmem *risc = + &dev->channels[chan_num].dma_vidq.stopper; + video_unregister_device(&dev->channels[chan_num].vdev); v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl); - btcx_riscmem_free(dev->pci, - &dev->channels[chan_num].dma_vidq.stopper); + pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); } } diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 90bdc19..38beec2 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -36,7 +36,6 @@ #include #include -#include "btcx-risc.h" #include "cx25821-reg.h" #include "cx25821-medusa-reg.h" #include "cx25821-sram.h" @@ -111,6 +110,13 @@ enum cx25821_src_sel_type { CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO }; +struct cx25821_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + /* buffer for one video frame */ struct cx25821_buffer { /* common v4l buffer stuff -- must be first */ @@ -118,7 +124,7 @@ struct cx25821_buffer { /* cx25821 specific */ unsigned int bpl; - struct btcx_riscmem risc; + struct cx25821_riscmem risc; const struct cx25821_fmt *fmt; u32 count; }; @@ -161,7 +167,7 @@ struct cx25821_dmaqueue { struct list_head active; struct list_head queued; struct timer_list timeout; - struct btcx_riscmem stopper; + struct cx25821_riscmem stopper; u32 count; }; @@ -405,20 +411,23 @@ extern int cx25821_sram_channel_setup(struct cx25821_dev *dev, const struct sram_channel *ch, unsigned int bpl, u32 risc); -extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +extern int cx25821_riscmem_alloc(struct pci_dev *pci, + struct cx25821_riscmem *risc, + unsigned int size); +extern int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); extern int cx25821_risc_databuffer_audio(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi); extern void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf); -extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, +extern int cx25821_risc_stopper(struct pci_dev *pci, struct cx25821_riscmem *risc, u32 reg, u32 mask, u32 value); extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch); -- cgit v0.10.2 From 1e4518086ae863814a3481a180264a1ac89a730b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:27:55 -0300 Subject: [media] cx231xx: remove btcx_riscmem reference Remove this comment block, it's unused. This removes the btcx_riscmem reference as well, since that will no longer be available to other drivers except bttv. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index f9e262eb..6d6f3ee 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -532,15 +532,7 @@ struct cx231xx_video_mode { unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ u16 end_point_addr; }; -/* -struct cx23885_dmaqueue { - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - u32 count; -}; -*/ + struct cx231xx_tsport { struct cx231xx *dev; -- cgit v0.10.2 From 90ca8bef9082c2036a200dd2cd17924944cd339b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:27:56 -0300 Subject: [media] btcx-risc: move to bt8xx The btcx-risc module is no longer used by other drivers except for bttv. So move it from common to bt8xx and make it part of the bttv driver instead of as a separate module. This module should never have been a common module since most of the code has always been bttv specific. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index b85f88c..21154dd 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -8,10 +8,6 @@ comment "common driver options" config VIDEO_CX2341X tristate -config VIDEO_BTCX - depends on PCI - tristate - config VIDEO_TVEEPROM tristate depends on I2C diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index d208de3..89b795d 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,5 +1,4 @@ obj-y += b2c2/ saa7146/ siano/ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o -obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o diff --git a/drivers/media/common/btcx-risc.c b/drivers/media/common/btcx-risc.c deleted file mode 100644 index e67338a..0000000 --- a/drivers/media/common/btcx-risc.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - - btcx-risc.c - - bt848/bt878/cx2388x risc code generator. - - (c) 2000-03 Gerd Knorr [SuSE Labs] - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "btcx-risc.h" - -MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); - -/* ---------------------------------------------------------- */ -/* allocate/free risc memory */ - -static int memcnt; - -void btcx_riscmem_free(struct pci_dev *pci, - struct btcx_riscmem *risc) -{ - if (NULL == risc->cpu) - return; - if (debug) { - memcnt--; - printk("btcx: riscmem free [%d] dma=%lx\n", - memcnt, (unsigned long)risc->dma); - } - pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); - memset(risc,0,sizeof(*risc)); -} - -int btcx_riscmem_alloc(struct pci_dev *pci, - struct btcx_riscmem *risc, - unsigned int size) -{ - __le32 *cpu; - dma_addr_t dma = 0; - - if (NULL != risc->cpu && risc->size < size) - btcx_riscmem_free(pci,risc); - if (NULL == risc->cpu) { - cpu = pci_alloc_consistent(pci, size, &dma); - if (NULL == cpu) - return -ENOMEM; - risc->cpu = cpu; - risc->dma = dma; - risc->size = size; - if (debug) { - memcnt++; - printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", - memcnt, (unsigned long)dma, cpu, size); - } - } - memset(risc->cpu,0,risc->size); - return 0; -} - -/* ---------------------------------------------------------- */ -/* screen overlay helpers */ - -int -btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, - struct v4l2_clip *clips, unsigned int n) -{ - if (win->left < 0) { - /* left */ - clips[n].c.left = 0; - clips[n].c.top = 0; - clips[n].c.width = -win->left; - clips[n].c.height = win->height; - n++; - } - if (win->left + win->width > swidth) { - /* right */ - clips[n].c.left = swidth - win->left; - clips[n].c.top = 0; - clips[n].c.width = win->width - clips[n].c.left; - clips[n].c.height = win->height; - n++; - } - if (win->top < 0) { - /* top */ - clips[n].c.left = 0; - clips[n].c.top = 0; - clips[n].c.width = win->width; - clips[n].c.height = -win->top; - n++; - } - if (win->top + win->height > sheight) { - /* bottom */ - clips[n].c.left = 0; - clips[n].c.top = sheight - win->top; - clips[n].c.width = win->width; - clips[n].c.height = win->height - clips[n].c.top; - n++; - } - return n; -} - -int -btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) -{ - s32 nx,nw,dx; - unsigned int i; - - /* fixup window */ - nx = (win->left + mask) & ~mask; - nw = (win->width) & ~mask; - if (nx + nw > win->left + win->width) - nw -= mask+1; - dx = nx - win->left; - win->left = nx; - win->width = nw; - if (debug) - printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", - win->width, win->height, win->left, win->top, dx); - - /* fixup clips */ - for (i = 0; i < n; i++) { - nx = (clips[i].c.left-dx) & ~mask; - nw = (clips[i].c.width) & ~mask; - if (nx + nw < clips[i].c.left-dx + clips[i].c.width) - nw += mask+1; - clips[i].c.left = nx; - clips[i].c.width = nw; - if (debug) - printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", - clips[i].c.width, clips[i].c.height, - clips[i].c.left, clips[i].c.top); - } - return 0; -} - -void -btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) -{ - struct v4l2_clip swap; - int i,j,n; - - if (nclips < 2) - return; - for (i = nclips-2; i >= 0; i--) { - for (n = 0, j = 0; j <= i; j++) { - if (clips[j].c.left > clips[j+1].c.left) { - swap = clips[j]; - clips[j] = clips[j+1]; - clips[j+1] = swap; - n++; - } - } - if (0 == n) - break; - } -} - -void -btcx_calc_skips(int line, int width, int *maxy, - struct btcx_skiplist *skips, unsigned int *nskips, - const struct v4l2_clip *clips, unsigned int nclips) -{ - unsigned int clip,skip; - int end, maxline; - - skip=0; - maxline = 9999; - for (clip = 0; clip < nclips; clip++) { - - /* sanity checks */ - if (clips[clip].c.left + clips[clip].c.width <= 0) - continue; - if (clips[clip].c.left > (signed)width) - break; - - /* vertical range */ - if (line > clips[clip].c.top+clips[clip].c.height-1) - continue; - if (line < clips[clip].c.top) { - if (maxline > clips[clip].c.top-1) - maxline = clips[clip].c.top-1; - continue; - } - if (maxline > clips[clip].c.top+clips[clip].c.height-1) - maxline = clips[clip].c.top+clips[clip].c.height-1; - - /* horizontal range */ - if (0 == skip || clips[clip].c.left > skips[skip-1].end) { - /* new one */ - skips[skip].start = clips[clip].c.left; - if (skips[skip].start < 0) - skips[skip].start = 0; - skips[skip].end = clips[clip].c.left + clips[clip].c.width; - if (skips[skip].end > width) - skips[skip].end = width; - skip++; - } else { - /* overlaps -- expand last one */ - end = clips[clip].c.left + clips[clip].c.width; - if (skips[skip-1].end < end) - skips[skip-1].end = end; - if (skips[skip-1].end > width) - skips[skip-1].end = width; - } - } - *nskips = skip; - *maxy = maxline; - - if (debug) { - printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); - for (skip = 0; skip < *nskips; skip++) { - printk(" %d-%d",skips[skip].start,skips[skip].end); - } - printk("\n"); - } -} - -/* ---------------------------------------------------------- */ - -EXPORT_SYMBOL(btcx_riscmem_alloc); -EXPORT_SYMBOL(btcx_riscmem_free); - -EXPORT_SYMBOL(btcx_screen_clips); -EXPORT_SYMBOL(btcx_align); -EXPORT_SYMBOL(btcx_sort_clips); -EXPORT_SYMBOL(btcx_calc_skips); diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index 61d09e0..496cf6b 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -2,7 +2,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 select I2C_ALGOBIT - select VIDEO_BTCX select VIDEOBUF_DMA_SG depends on RC_CORE select VIDEO_TUNER diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile index f9fe7c4..2d4c3dd 100644 --- a/drivers/media/pci/bt8xx/Makefile +++ b/drivers/media/pci/bt8xx/Makefile @@ -1,6 +1,6 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o bttv-audio-hook.o + bttv-input.o bttv-audio-hook.o btcx-risc.o obj-$(CONFIG_VIDEO_BT848) += bttv.o obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c new file mode 100644 index 0000000..00f0880 --- /dev/null +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -0,0 +1,240 @@ +/* + + btcx-risc.c + + bt848/bt878/cx2388x risc code generator. + + (c) 2000-03 Gerd Knorr [SuSE Labs] + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "btcx-risc.h" + +static unsigned int btcx_debug; +module_param(btcx_debug, int, 0644); +MODULE_PARM_DESC(btcx_debug,"debug messages, default is 0 (no)"); + +/* ---------------------------------------------------------- */ +/* allocate/free risc memory */ + +static int memcnt; + +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc) +{ + if (NULL == risc->cpu) + return; + if (btcx_debug) { + memcnt--; + printk("btcx: riscmem free [%d] dma=%lx\n", + memcnt, (unsigned long)risc->dma); + } + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + memset(risc,0,sizeof(*risc)); +} + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size) +{ + __le32 *cpu; + dma_addr_t dma = 0; + + if (NULL != risc->cpu && risc->size < size) + btcx_riscmem_free(pci,risc); + if (NULL == risc->cpu) { + cpu = pci_alloc_consistent(pci, size, &dma); + if (NULL == cpu) + return -ENOMEM; + risc->cpu = cpu; + risc->dma = dma; + risc->size = size; + if (btcx_debug) { + memcnt++; + printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", + memcnt, (unsigned long)dma, cpu, size); + } + } + memset(risc->cpu,0,risc->size); + return 0; +} + +/* ---------------------------------------------------------- */ +/* screen overlay helpers */ + +int +btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n) +{ + if (win->left < 0) { + /* left */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = -win->left; + clips[n].c.height = win->height; + n++; + } + if (win->left + win->width > swidth) { + /* right */ + clips[n].c.left = swidth - win->left; + clips[n].c.top = 0; + clips[n].c.width = win->width - clips[n].c.left; + clips[n].c.height = win->height; + n++; + } + if (win->top < 0) { + /* top */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = win->width; + clips[n].c.height = -win->top; + n++; + } + if (win->top + win->height > sheight) { + /* bottom */ + clips[n].c.left = 0; + clips[n].c.top = sheight - win->top; + clips[n].c.width = win->width; + clips[n].c.height = win->height - clips[n].c.top; + n++; + } + return n; +} + +int +btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) +{ + s32 nx,nw,dx; + unsigned int i; + + /* fixup window */ + nx = (win->left + mask) & ~mask; + nw = (win->width) & ~mask; + if (nx + nw > win->left + win->width) + nw -= mask+1; + dx = nx - win->left; + win->left = nx; + win->width = nw; + if (btcx_debug) + printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", + win->width, win->height, win->left, win->top, dx); + + /* fixup clips */ + for (i = 0; i < n; i++) { + nx = (clips[i].c.left-dx) & ~mask; + nw = (clips[i].c.width) & ~mask; + if (nx + nw < clips[i].c.left-dx + clips[i].c.width) + nw += mask+1; + clips[i].c.left = nx; + clips[i].c.width = nw; + if (btcx_debug) + printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", + clips[i].c.width, clips[i].c.height, + clips[i].c.left, clips[i].c.top); + } + return 0; +} + +void +btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) +{ + struct v4l2_clip swap; + int i,j,n; + + if (nclips < 2) + return; + for (i = nclips-2; i >= 0; i--) { + for (n = 0, j = 0; j <= i; j++) { + if (clips[j].c.left > clips[j+1].c.left) { + swap = clips[j]; + clips[j] = clips[j+1]; + clips[j+1] = swap; + n++; + } + } + if (0 == n) + break; + } +} + +void +btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips) +{ + unsigned int clip,skip; + int end, maxline; + + skip=0; + maxline = 9999; + for (clip = 0; clip < nclips; clip++) { + + /* sanity checks */ + if (clips[clip].c.left + clips[clip].c.width <= 0) + continue; + if (clips[clip].c.left > (signed)width) + break; + + /* vertical range */ + if (line > clips[clip].c.top+clips[clip].c.height-1) + continue; + if (line < clips[clip].c.top) { + if (maxline > clips[clip].c.top-1) + maxline = clips[clip].c.top-1; + continue; + } + if (maxline > clips[clip].c.top+clips[clip].c.height-1) + maxline = clips[clip].c.top+clips[clip].c.height-1; + + /* horizontal range */ + if (0 == skip || clips[clip].c.left > skips[skip-1].end) { + /* new one */ + skips[skip].start = clips[clip].c.left; + if (skips[skip].start < 0) + skips[skip].start = 0; + skips[skip].end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip].end > width) + skips[skip].end = width; + skip++; + } else { + /* overlaps -- expand last one */ + end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip-1].end < end) + skips[skip-1].end = end; + if (skips[skip-1].end > width) + skips[skip-1].end = width; + } + } + *nskips = skip; + *maxy = maxline; + + if (btcx_debug) { + printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); + for (skip = 0; skip < *nskips; skip++) { + printk(" %d-%d",skips[skip].start,skips[skip].end); + } + printk("\n"); + } +} diff --git a/drivers/media/pci/bt8xx/btcx-risc.h b/drivers/media/pci/bt8xx/btcx-risc.h new file mode 100644 index 0000000..1ed7a00 --- /dev/null +++ b/drivers/media/pci/bt8xx/btcx-risc.h @@ -0,0 +1,26 @@ +struct btcx_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); -- cgit v0.10.2 From 8d8e6d6005de1f2421b7846bfb50782b09cd63a7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:27:57 -0300 Subject: [media] cx28521: drop videobuf abuse in cx25821-alsa The alsa driver uses videobuf low-level functions that are not available in vb2, so replace them by driver-specific functions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 27e6493..24f964b 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -64,7 +64,10 @@ static int devno; struct cx25821_audio_buffer { unsigned int bpl; struct cx25821_riscmem risc; - struct videobuf_dmabuf dma; + void *vaddr; + struct scatterlist *sglist; + int sglen; + int nr_pages; }; struct cx25821_audio_dev { @@ -87,8 +90,6 @@ struct cx25821_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf *dma_risc; - struct cx25821_audio_buffer *buf; struct snd_pcm_substream *substream; @@ -142,6 +143,83 @@ MODULE_PARM_DESC(debug, "enable debug messages"); #define PCI_MSK_AUD_EXT (1 << 4) #define PCI_MSK_AUD_INT (1 << 3) + +static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip, int nr_pages) +{ + struct cx25821_audio_buffer *buf = chip->buf; + struct page *pg; + int i; + + buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == buf->vaddr) { + dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); + return -ENOMEM; + } + + dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)buf->vaddr, + nr_pages << PAGE_SHIFT); + + memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); + buf->nr_pages = nr_pages; + + buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + if (NULL == buf->sglist) + goto vzalloc_err; + + sg_init_table(buf->sglist, buf->nr_pages); + for (i = 0; i < buf->nr_pages; i++) { + pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); + if (NULL == pg) + goto vmalloc_to_page_err; + sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); + } + return 0; + +vmalloc_to_page_err: + vfree(buf->sglist); + buf->sglist = NULL; +vzalloc_err: + vfree(buf->vaddr); + buf->vaddr = NULL; + return -ENOMEM; +} + +static int cx25821_alsa_dma_map(struct cx25821_audio_dev *dev) +{ + struct cx25821_audio_buffer *buf = dev->buf; + + buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist, + buf->nr_pages, PCI_DMA_FROMDEVICE); + + if (0 == buf->sglen) { + pr_warn("%s: cx25821_alsa_map_sg failed\n", __func__); + return -ENOMEM; + } + return 0; +} + +static int cx25821_alsa_dma_unmap(struct cx25821_audio_dev *dev) +{ + struct cx25821_audio_buffer *buf = dev->buf; + + if (!buf->sglen) + return 0; + + dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE); + buf->sglen = 0; + return 0; +} + +static int cx25821_alsa_dma_free(struct cx25821_audio_buffer *buf) +{ + vfree(buf->sglist); + buf->sglist = NULL; + vfree(buf->vaddr); + buf->vaddr = NULL; + return 0; +} + /* * BOARD Specific: Sets audio DMA */ @@ -335,12 +413,12 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip) BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); + cx25821_alsa_dma_unmap(chip); + cx25821_alsa_dma_free(chip->buf); pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); kfree(chip->buf); - chip->dma_risc = NULL; + chip->buf = NULL; chip->dma_size = 0; return 0; @@ -432,8 +510,6 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - struct cx25821_audio_buffer *buf; int ret; @@ -457,19 +533,18 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, chip->period_size = AUDIO_LINE_SIZE; buf->bpl = chip->period_size; + chip->buf = buf; - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + ret = cx25821_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_dma_map(&chip->pci->dev, dma); + ret = cx25821_alsa_dma_map(chip); if (ret < 0) goto error; - ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, + ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, buf->sglist, chip->period_size, chip->num_periods, 1); if (ret < 0) { pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); @@ -481,16 +556,14 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - chip->buf = buf; - chip->dma_risc = dma; - - substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; return 0; error: + chip->buf = NULL; kfree(buf); return ret; } -- cgit v0.10.2 From b671ae6bdc1ad77a63536c6f74940976b9b89322 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:27:58 -0300 Subject: [media] cx25821: convert to vb2 This patch converts the cx25821 driver from the old videobuf framework to the new vb2 framework. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 0e69cab..1755d3d 100644 --- a/drivers/media/pci/cx25821/Kconfig +++ b/drivers/media/pci/cx25821/Kconfig @@ -2,7 +2,7 @@ config VIDEO_CX25821 tristate "Conexant cx25821 support" depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DMA_SG ---help--- This is a video4linux driver for Conexant 25821 based TV cards. diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index c8c65b7..c1ea24e 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -874,10 +874,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); - return -1; - } else { - pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); + return -ENODEV; } + pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 28000000; @@ -1003,11 +1002,17 @@ EXPORT_SYMBOL(cx25821_riscmem_alloc); static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, bool jump) { struct scatterlist *sg; unsigned int line, todo; + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(0); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + } + /* sync instruction */ if (sync_line != NO_SYNC_LINE) *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); @@ -1073,13 +1078,13 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, fields++; /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding + one write per scan line + syncs + jump (all 3 dwords). Padding can cause next bpl to start close to a page border. First DMA region may be smaller than PAGE_SIZE */ /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; + instructions += 5; rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); if (rc < 0) @@ -1090,17 +1095,17 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, if (UNSET != top_offset) { rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding, - lines); + lines, true); } if (UNSET != bottom_offset) { rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl, - padding, lines); + padding, lines, UNSET == top_offset); } /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + BUG_ON((risc->jmp - risc->cpu + 3) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -1200,41 +1205,14 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci, } EXPORT_SYMBOL(cx25821_risc_databuffer_audio); -int cx25821_risc_stopper(struct pci_dev *pci, struct cx25821_riscmem *risc, - u32 reg, u32 mask, u32 value) +void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf) { - __le32 *rp; - int rc; - - rc = cx25821_riscmem_alloc(pci, risc, 4 * 16); - - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - pci_free_consistent(to_pci_dev(q->dev), + if (WARN_ON(buf->risc.size == 0)) + return; + pci_free_consistent(dev->pci, buf->risc.size, buf->risc.cpu, buf->risc.dma); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + memset(&buf->risc, 0, sizeof(buf->risc)); } static irqreturn_t cx25821_irq(int irq, void *dev_id) @@ -1319,14 +1297,15 @@ static int cx25821_initdev(struct pci_dev *pci_dev, goto fail_unregister_device; } + dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); + if (IS_ERR(dev->alloc_ctx)) { + err = PTR_ERR(dev->alloc_ctx); + goto fail_unregister_pci; + } err = cx25821_dev_setup(dev); - if (err) { - if (err == -EBUSY) - goto fail_unregister_device; - else - goto fail_unregister_pci; - } + if (err) + goto fail_free_ctx; /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); @@ -1356,6 +1335,8 @@ fail_irq: pr_info("cx25821_initdev() can't get IRQ !\n"); cx25821_dev_unregister(dev); +fail_free_ctx: + vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); fail_unregister_pci: pci_disable_device(pci_dev); fail_unregister_device: @@ -1379,6 +1360,7 @@ static void cx25821_finidev(struct pci_dev *pci_dev) free_irq(pci_dev->irq, dev); cx25821_dev_unregister(dev); + vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); v4l2_device_unregister(v4l2_dev); kfree(dev); } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 3eda1a1..3497946 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -3,7 +3,7 @@ * * Copyright (C) 2009 Conexant Systems Inc. * Authors , - * Based on Steven Toth cx23885 driver + * Based on Steven Toth cx25821 driver * Parts adapted/taken from Eduardo Moscoso Rubino * Copyright (C) 2009 Eduardo Moscoso Rubino * @@ -46,10 +46,6 @@ static unsigned int irq_debug; module_param(irq_debug, int, 0644); MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); -static unsigned int vid_limit = 16; -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - #define FORMAT_FLAGS_PACKED 0x01 static const struct cx25821_fmt formats[] = { @@ -76,41 +72,6 @@ static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) return NULL; } -void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, - u32 count) -{ - struct cx25821_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) { - dprintk(1, "bc=%d (=0: active empty)\n", bc); - break; - } - - buf = list_entry(q->active.next, struct cx25821_buffer, - vb.queue); - - /* count comes from the hw and it is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - - if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); -} - int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, @@ -123,7 +84,6 @@ int cx25821_start_video_dma(struct cx25821_dev *dev, /* reset counter */ cx_write(channel->gpcnt_ctl, 3); - q->count = 1; /* enable irq */ cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i)); @@ -139,86 +99,8 @@ int cx25821_start_video_dma(struct cx25821_dev *dev, return 0; } -static int cx25821_restart_video_queue(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, - const struct sram_channel *channel) -{ - struct cx25821_buffer *buf, *prev; - struct list_head *item; - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx25821_buffer, - vb.queue); - - cx25821_start_video_dma(dev, q, buf, channel); - - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx25821_buffer, vb.queue); - buf->count = q->count++; - } - - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - - buf = list_entry(q->queued.next, struct cx25821_buffer, - vb.queue); - - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, channel); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - } else { - return 0; - } - prev = buf; - } -} - -static void cx25821_vid_timeout(unsigned long data) -{ - struct cx25821_data *timeout_data = (struct cx25821_data *)data; - struct cx25821_dev *dev = timeout_data->dev; - const struct sram_channel *channel = timeout_data->channel; - struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq; - struct cx25821_buffer *buf; - unsigned long flags; - - /* cx25821_sram_channel_dump(dev, channel); */ - cx_clear(channel->dma_ctl, 0x11); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx25821_buffer, - vb.queue); - list_del(&buf->vb.queue); - - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - } - - cx25821_restart_video_queue(dev, q, channel); - spin_unlock_irqrestore(&dev->slock, flags); -} - int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) { - u32 count = 0; int handled = 0; u32 mask; const struct sram_channel *channel = dev->channels[chan_num].sram_channels; @@ -239,317 +121,197 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) /* risc1 y */ if (status & FLD_VID_DST_RISC1) { - spin_lock(&dev->slock); - count = cx_read(channel->gpcnt); - cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq, - count); - spin_unlock(&dev->slock); - handled++; - } + struct cx25821_dmaqueue *dmaq = + &dev->channels[channel->i].dma_vidq; + struct cx25821_buffer *buf; - /* risc2 y */ - if (status & 0x10) { - dprintk(2, "stopper video\n"); spin_lock(&dev->slock); - cx25821_restart_video_queue(dev, - &dev->channels[channel->i].dma_vidq, channel); + if (!list_empty(&dmaq->active)) { + buf = list_entry(dmaq->active.next, + struct cx25821_buffer, queue); + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.sequence = dmaq->count++; + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + } spin_unlock(&dev->slock); handled++; } return handled; } -static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +static int cx25821_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx25821_channel *chan = q->priv_data; - - *size = chan->fmt->depth * chan->width * chan->height >> 3; - - if (0 == *count) - *count = 32; - - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; + struct cx25821_channel *chan = q->drv_priv; + *num_planes = 1; + sizes[0] = (chan->fmt->depth * chan->width * chan->height) >> 3; + alloc_ctxs[0] = chan->dev->alloc_ctx; return 0; } -static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int cx25821_buffer_prepare(struct vb2_buffer *vb) { - struct cx25821_channel *chan = q->priv_data; + struct cx25821_channel *chan = vb->vb2_queue->drv_priv; struct cx25821_dev *dev = chan->dev; struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); - int rc, init_buffer = 0; + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); u32 line0_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int bpl_local = LINE_SIZE_D1; + int ret; - BUG_ON(NULL == chan->fmt); - if (chan->width < 48 || chan->width > 720 || - chan->height < 32 || chan->height > 576) - return -EINVAL; - - buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3; + if (chan->pixel_formats == PIXEL_FRMT_411) + buf->bpl = (chan->fmt->depth * chan->width) >> 3; + else + buf->bpl = (chan->fmt->depth >> 3) * chan->width; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + if (vb2_plane_size(vb, 0) < chan->height * buf->bpl) return -EINVAL; + vb2_set_plane_payload(vb, 0, chan->height * buf->bpl); + buf->vb.v4l2_buf.field = chan->field; - if (buf->fmt != chan->fmt || - buf->vb.width != chan->width || - buf->vb.height != chan->height || buf->vb.field != field) { - buf->fmt = chan->fmt; - buf->vb.width = chan->width; - buf->vb.height = chan->height; - buf->vb.field = field; - init_buffer = 1; - } + if (chan->pixel_formats == PIXEL_FRMT_411) { + bpl_local = buf->bpl; + } else { + bpl_local = buf->bpl; /* Default */ - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) { - printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n")); - goto fail; + if (chan->use_cif_resolution) { + if (dev->tvnorm & V4L2_STD_625_50) + bpl_local = 352 << 1; + else + bpl_local = chan->cif_width << 1; } } - dprintk(1, "init_buffer=%d\n", init_buffer); - - if (init_buffer) { - if (chan->pixel_formats == PIXEL_FRMT_411) - buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3; - else - buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width); - - if (chan->pixel_formats == PIXEL_FRMT_411) { - bpl_local = buf->bpl; - } else { - bpl_local = buf->bpl; /* Default */ - - if (chan->use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_625_50) - bpl_local = 352 << 1; - else - bpl_local = chan->cif_width << 1; - } - } - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - /* All other formats are top field first */ - line0_offset = 0; - dprintk(1, "top field first\n"); - - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - bpl_local, bpl_local, bpl_local, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, buf->vb.height >> 1); - break; - default: - BUG(); - } + switch (chan->field) { + case V4L2_FIELD_TOP: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, chan->height); + break; + case V4L2_FIELD_BOTTOM: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, chan->height); + break; + case V4L2_FIELD_INTERLACED: + /* All other formats are top field first */ + line0_offset = 0; + dprintk(1, "top field first\n"); + + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, line0_offset, + bpl_local, bpl_local, bpl_local, + chan->height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (chan->height >> 1), + buf->bpl, 0, chan->height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (chan->height >> 1), 0, + buf->bpl, 0, chan->height >> 1); + break; + default: + WARN_ON(1); + ret = -EINVAL; + break; } dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth, - chan->fmt->name, (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; - - return 0; + buf, buf->vb.v4l2_buf.index, chan->width, chan->height, + chan->fmt->depth, chan->fmt->name, + (unsigned long)buf->risc.dma); -fail: - cx25821_free_buffer(q, buf); - return rc; + return ret; } -static void cx25821_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void cx25821_buffer_finish(struct vb2_buffer *vb) { struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); + struct cx25821_channel *chan = vb->vb2_queue->drv_priv; + struct cx25821_dev *dev = chan->dev; - cx25821_free_buffer(q, buf); -} - -static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_mmap_mapper(&chan->vidq, vma); + cx25821_free_buffer(dev, buf); } - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void cx25821_buffer_queue(struct vb2_buffer *vb) { struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); - struct cx25821_buffer *prev; - struct cx25821_channel *chan = vq->priv_data; + struct cx25821_channel *chan = vb->vb2_queue->drv_priv; struct cx25821_dev *dev = chan->dev; + struct cx25821_buffer *prev; struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]); - - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf, - buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, chan->sram_channels); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n", - buf, buf->vb.i, buf->count, q->count); + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&q->active)) { + list_add_tail(&buf->queue, &q->active); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx25821_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width - && prev->vb.height == buf->vb.height - && prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n", - buf, buf->vb.i, buf->count); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf, - buf->vb.i); - } + queue); + list_add_tail(&buf->queue, &q->active); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); } - - if (list_empty(&q->active)) - dprintk(2, "active queue empty!\n"); } -static struct videobuf_queue_ops cx25821_video_qops = { - .buf_setup = cx25821_buffer_setup, - .buf_prepare = cx25821_buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = cx25821_buffer_release, -}; - -static ssize_t video_read(struct file *file, char __user * data, size_t count, - loff_t *ppos) +static int cx25821_start_streaming(struct vb2_queue *q, unsigned int count) { - struct v4l2_fh *fh = file->private_data; - struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_channel *chan = q->drv_priv; struct cx25821_dev *dev = chan->dev; - int err = 0; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - if (chan->streaming_fh && chan->streaming_fh != fh) { - err = -EBUSY; - goto unlock; - } - chan->streaming_fh = fh; + struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq; + struct cx25821_buffer *buf = list_entry(dmaq->active.next, + struct cx25821_buffer, queue); - err = videobuf_read_one(&chan->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); -unlock: - mutex_unlock(&dev->lock); - return err; -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx25821_channel *chan = video_drvdata(file); - unsigned long req_events = poll_requested_events(wait); - unsigned int res = v4l2_ctrl_poll(file, wait); - - if (req_events & (POLLIN | POLLRDNORM)) - res |= videobuf_poll_stream(file, &chan->vidq, wait); - return res; - - /* This doesn't belong in poll(). This can be done - * much better with vb2. We keep this code here as a - * reminder. - if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) { - struct cx25821_dev *dev = chan->dev; - - if (dev && chan->use_cif_resolution) { - u8 cam_id = *((char *)buf->vb.baddr + 3); - memcpy((char *)buf->vb.baddr, - (char *)buf->vb.baddr + (chan->width * 2), - (chan->width * 2)); - *((char *)buf->vb.baddr + 3) = cam_id; - } - } - */ + dmaq->count = 0; + cx25821_start_video_dma(dev, dmaq, buf, chan->sram_channels); + return 0; } -static int video_release(struct file *file) +static void cx25821_stop_streaming(struct vb2_queue *q) { - struct cx25821_channel *chan = video_drvdata(file); - struct v4l2_fh *fh = file->private_data; + struct cx25821_channel *chan = q->drv_priv; struct cx25821_dev *dev = chan->dev; - const struct sram_channel *sram_ch = - dev->channels[0].sram_channels; - - mutex_lock(&dev->lock); - /* stop the risc engine and fifo */ - cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */ + struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq; + unsigned long flags; - /* stop video capture */ - if (chan->streaming_fh == fh) { - videobuf_queue_cancel(&chan->vidq); - chan->streaming_fh = NULL; - } + cx_write(chan->sram_channels->dma_ctl, 0); /* FIFO and RISC disable */ + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx25821_buffer *buf = list_entry(dmaq->active.next, + struct cx25821_buffer, queue); - if (chan->vidq.read_buf) { - cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf); - kfree(chan->vidq.read_buf); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - - videobuf_mmap_free(&chan->vidq); - mutex_unlock(&dev->lock); - - return v4l2_fh_release(file); + spin_unlock_irqrestore(&dev->slock, flags); } +static struct vb2_ops cx25821_video_qops = { + .queue_setup = cx25821_queue_setup, + .buf_prepare = cx25821_buffer_prepare, + .buf_finish = cx25821_buffer_finish, + .buf_queue = cx25821_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx25821_start_streaming, + .stop_streaming = cx25821_stop_streaming, +}; + /* VIDEO IOCTLS */ static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, @@ -571,7 +333,7 @@ static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = chan->width; f->fmt.pix.height = chan->height; - f->fmt.pix.field = chan->vidq.field; + f->fmt.pix.field = chan->field; f->fmt.pix.pixelformat = chan->fmt->fourcc; f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3; f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline; @@ -632,7 +394,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return err; chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - chan->vidq.field = f->fmt.pix.field; + chan->field = f->fmt.pix.field; chan->width = f->fmt.pix.width; chan->height = f->fmt.pix.height; @@ -654,47 +416,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_channel *chan = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (chan->streaming_fh && chan->streaming_fh != priv) - return -EBUSY; - chan->streaming_fh = priv; - - return videobuf_streamon(&chan->vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_channel *chan = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (chan->streaming_fh && chan->streaming_fh != priv) - return -EBUSY; - if (chan->streaming_fh == NULL) - return 0; - - chan->streaming_fh = NULL; - return videobuf_streamoff(&chan->vidq); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int ret_val = 0; - struct cx25821_channel *chan = video_drvdata(file); - - ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK); - p->sequence = chan->dma_vidq.count; - - return ret_val; -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx25821_channel *chan = video_drvdata(file); @@ -729,29 +450,6 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, return 0; } -static int cx25821_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_reqbufs(&chan->vidq, p); -} - -static int cx25821_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_querybuf(&chan->vidq, p); -} - -static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_qbuf(&chan->vidq, p); -} - static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx25821_channel *chan = video_drvdata(file); @@ -880,7 +578,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return err; chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - chan->vidq.field = f->fmt.pix.field; + chan->field = f->fmt.pix.field; chan->width = f->fmt.pix.width; chan->height = f->fmt.pix.height; if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) @@ -890,52 +588,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static ssize_t video_write(struct file *file, const char __user *data, size_t count, - loff_t *ppos) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - struct v4l2_fh *fh = file->private_data; - int err = 0; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - if (chan->streaming_fh && chan->streaming_fh != fh) { - err = -EBUSY; - goto unlock; - } - if (!chan->streaming_fh) { - err = cx25821_vidupstream_init(chan, chan->pixel_formats); - if (err) - goto unlock; - chan->streaming_fh = fh; - } - - err = cx25821_write_frame(chan, data, count); - count -= err; - *ppos += err; - -unlock: - mutex_unlock(&dev->lock); - return err; -} - -static int video_out_release(struct file *file) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - struct v4l2_fh *fh = file->private_data; - - mutex_lock(&dev->lock); - if (chan->streaming_fh == fh) { - cx25821_stop_upstream_video(chan); - chan->streaming_fh = NULL; - } - mutex_unlock(&dev->lock); - - return v4l2_fh_release(file); -} - static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { .s_ctrl = cx25821_s_ctrl, }; @@ -943,11 +595,11 @@ static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = cx25821_video_mmap, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -956,17 +608,18 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = cx25821_vidioc_reqbufs, - .vidioc_querybuf = cx25821_vidioc_querybuf, - .vidioc_qbuf = cx25821_vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_std = cx25821_vidioc_g_std, .vidioc_s_std = cx25821_vidioc_s_std, .vidioc_enum_input = cx25821_vidioc_enum_input, .vidioc_g_input = cx25821_vidioc_g_input, .vidioc_s_input = cx25821_vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, @@ -984,9 +637,11 @@ static const struct video_device cx25821_video_device = { static const struct v4l2_file_operations video_out_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .write = video_write, - .release = video_out_release, + .release = vb2_fop_release, + .write = vb2_fop_write, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_out_ioctl_ops = { @@ -1017,13 +672,8 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) cx_clear(PCI_INT_MSK, 1); if (video_is_registered(&dev->channels[chan_num].vdev)) { - struct cx25821_riscmem *risc = - &dev->channels[chan_num].dma_vidq.stopper; - video_unregister_device(&dev->channels[chan_num].vdev); v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl); - - pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); } } @@ -1041,6 +691,7 @@ int cx25821_video_register(struct cx25821_dev *dev) struct cx25821_channel *chan = &dev->channels[i]; struct video_device *vdev = &chan->vdev; struct v4l2_ctrl_handler *hdl = &chan->hdl; + struct vb2_queue *q; bool is_output = i > SRAM_CH08; if (i == SRAM_CH08) /* audio channel */ @@ -1068,11 +719,9 @@ int cx25821_video_register(struct cx25821_dev *dev) chan->out->chan = chan; } - cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper, - chan->sram_channels->dma_ctl, 0x11, 0); - chan->sram_channels = &cx25821_sram_channels[i]; chan->width = 720; + chan->field = V4L2_FIELD_INTERLACED; if (dev->tvnorm & V4L2_STD_625_50) chan->height = 576; else @@ -1086,19 +735,27 @@ int cx25821_video_register(struct cx25821_dev *dev) cx_write(chan->sram_channels->int_stat, 0xffffffff); INIT_LIST_HEAD(&chan->dma_vidq.active); - INIT_LIST_HEAD(&chan->dma_vidq.queued); - chan->timeout_data.dev = dev; - chan->timeout_data.channel = &cx25821_sram_channels[i]; - chan->dma_vidq.timeout.function = cx25821_vid_timeout; - chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data; - init_timer(&chan->dma_vidq.timeout); + q = &chan->vidq; + + q->type = is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT : + V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->io_modes |= is_output ? VB2_WRITE : VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = chan; + q->buf_struct_size = sizeof(struct cx25821_buffer); + q->ops = &cx25821_video_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; - if (!is_output) - videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev, - &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), - chan, &dev->lock); + if (!is_output) { + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + } /* register v4l devices */ *vdev = is_output ? cx25821_video_out_device : cx25821_video_device; @@ -1108,6 +765,7 @@ int cx25821_video_register(struct cx25821_dev *dev) else vdev->vfl_dir = VFL_DIR_TX; vdev->lock = &dev->lock; + vdev->queue = q; snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); video_set_drvdata(vdev, chan); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 38beec2..34c5ff1 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "cx25821-reg.h" #include "cx25821-medusa-reg.h" @@ -120,13 +120,13 @@ struct cx25821_riscmem { /* buffer for one video frame */ struct cx25821_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head queue; /* cx25821 specific */ unsigned int bpl; struct cx25821_riscmem risc; const struct cx25821_fmt *fmt; - u32 count; }; enum port { @@ -165,17 +165,9 @@ struct cx25821_i2c { struct cx25821_dmaqueue { struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct cx25821_riscmem stopper; u32 count; }; -struct cx25821_data { - struct cx25821_dev *dev; - const struct sram_channel *channel; -}; - struct cx25821_dev; struct cx25821_channel; @@ -213,18 +205,17 @@ struct cx25821_video_out_data { struct cx25821_channel { unsigned id; struct cx25821_dev *dev; - struct v4l2_fh *streaming_fh; struct v4l2_ctrl_handler hdl; - struct cx25821_data timeout_data; struct video_device vdev; struct cx25821_dmaqueue dma_vidq; - struct videobuf_queue vidq; + struct vb2_queue vidq; const struct sram_channel *sram_channels; const struct cx25821_fmt *fmt; + unsigned field; unsigned int width, height; int pixel_formats; int use_cif_resolution; @@ -250,6 +241,7 @@ struct cx25821_dev { int hwrevision; /* used by cx25821-alsa */ struct snd_card *card; + void *alloc_ctx; u32 clk_freq; @@ -425,10 +417,8 @@ extern int cx25821_risc_databuffer_audio(struct pci_dev *pci, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi); -extern void cx25821_free_buffer(struct videobuf_queue *q, +extern void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf); -extern int cx25821_risc_stopper(struct pci_dev *pci, struct cx25821_riscmem *risc, - u32 reg, u32 mask, u32 value); extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch); extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, -- cgit v0.10.2 From 11c8a2df2cf8c213e1970d548aee067887971ef8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:27:59 -0300 Subject: [media] cx25821: add create_bufs support Add support for the VIDIOC_CREATE_BUFS ioctl. This was missing in this driver and in vb2 it's trivial to add. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 3497946..827c3c0 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -146,9 +146,13 @@ static int cx25821_queue_setup(struct vb2_queue *q, const struct v4l2_format *fm unsigned int sizes[], void *alloc_ctxs[]) { struct cx25821_channel *chan = q->drv_priv; + unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; + + if (fmt && fmt->fmt.pix.sizeimage < size) + return -EINVAL; *num_planes = 1; - sizes[0] = (chan->fmt->depth * chan->width * chan->height) >> 3; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; alloc_ctxs[0] = chan->dev->alloc_ctx; return 0; } @@ -610,6 +614,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_querybuf = vb2_ioctl_querybuf, .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, -- cgit v0.10.2 From b6f21dc3541a3660acfec1e789a011e6d4154173 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Dec 2014 10:28:00 -0300 Subject: [media] cx25821: remove video output support The video output functionality never worked for this driver. Now remove the creation of the output video nodes as well to prevent users from thinking that video output is available, when it isn't. To correctly implement this the video output should use vb2 as well, and that requires rewriting the output DMA setup. But without hardware to test I am not able to do that. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index 5872feb..c8f8598 100644 --- a/drivers/media/pci/cx25821/Makefile +++ b/drivers/media/pci/cx25821/Makefile @@ -1,6 +1,6 @@ cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ cx25821-gpio.o cx25821-medusa-video.o \ - cx25821-video.o cx25821-video-upstream.o + cx25821-video.o obj-$(CONFIG_VIDEO_CX25821) += cx25821.o obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index c1ea24e..559f829 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -965,11 +965,15 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { + for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; i++) { if (i == SRAM_CH08) /* audio channel */ continue; + /* + * TODO: enable when video output is properly + * supported. if (i == SRAM_CH09 || i == SRAM_CH10) cx25821_free_mem_upstream(&dev->channels[i]); + */ cx25821_video_unregister(dev, i); } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 827c3c0..7bc495e 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -692,7 +692,7 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { + for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; ++i) { struct cx25821_channel *chan = &dev->channels[i]; struct video_device *vdev = &chan->vdev; struct v4l2_ctrl_handler *hdl = &chan->hdl; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 34c5ff1..d81a08a 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -88,6 +88,13 @@ #define CX25821_BOARD_CONEXANT_ATHENA10 1 #define MAX_VID_CHANNEL_NUM 12 + +/* + * Maximum capture-only channels. This can go away once video/audio output + * is fully supported in this driver. + */ +#define MAX_VID_CAP_CHANNEL_NUM 10 + #define VID_CHANNEL_NUM 8 struct cx25821_fmt { -- cgit v0.10.2 From e476f4e15d859d1112872667983918bdfa4e663b Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Wed, 5 Nov 2014 17:11:14 -0300 Subject: [media] solo6x10: just pass frame motion flag from hardware, drop additional handling as complicated and unstable Dropping code (introduced in 316d9e84a72069e04e483de0d5934c1d75f6a44c) which intends to make raising of motion events more "smooth"(?). It made motion event never appear in my installation. That code is complicated, so I couldn't figure out quickly how to fix it, so dropping it seems better to me. Another justification is that anyway application would implement "motion signal stabilization" if required, it is not necessarily kernel driver's job. Signed-off-by: Andrey Utkin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 6e933d3..1c9688f 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -239,8 +239,6 @@ static int solo_enc_on(struct solo_enc_dev *solo_enc) if (solo_enc->bw_weight > solo_dev->enc_bw_remain) return -EBUSY; solo_enc->sequence = 0; - solo_enc->motion_last_state = false; - solo_enc->frames_since_last_motion = 0; solo_dev->enc_bw_remain -= solo_enc->bw_weight; if (solo_enc->type == SOLO_ENC_TYPE_EXT) @@ -529,36 +527,12 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, } if (!ret) { - bool send_event = false; - vb->v4l2_buf.sequence = solo_enc->sequence++; vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh); vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh); /* Check for motion flags */ - if (solo_is_motion_on(solo_enc)) { - /* It takes a few frames for the hardware to detect - * motion. Once it does it clears the motion detection - * register and it takes again a few frames before - * motion is seen. This means in practice that when the - * motion field is 1, it will go back to 0 for the next - * frame. This leads to motion detection event being - * sent all the time, which is not what we want. - * Instead wait a few frames before deciding that the - * motion has halted. After some experimentation it - * turns out that waiting for 5 frames works well. - */ - if (enc_buf->motion == 0 && - solo_enc->motion_last_state && - solo_enc->frames_since_last_motion++ > 5) - send_event = true; - else if (enc_buf->motion) { - solo_enc->frames_since_last_motion = 0; - send_event = !solo_enc->motion_last_state; - } - } - - if (send_event) { + if (solo_is_motion_on(solo_enc) && enc_buf->motion) { struct v4l2_event ev = { .type = V4L2_EVENT_MOTION_DET, .u.motion_det = { @@ -568,8 +542,6 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, }, }; - solo_enc->motion_last_state = enc_buf->motion; - solo_enc->frames_since_last_motion = 0; v4l2_event_queue(solo_enc->vfd, &ev); } } diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index bd8edfa..6c9bc70 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -159,8 +159,6 @@ struct solo_enc_dev { u16 motion_thresh; bool motion_global; bool motion_enabled; - bool motion_last_state; - u8 frames_since_last_motion; u16 width; u16 height; -- cgit v0.10.2 From 21a7e0596a63abdf12a9591c29359f7f15e18c16 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 1 Dec 2014 10:10:43 -0300 Subject: [media] media: drivers shouldn't touch debug field in video_device The debug field in struct video_device is for internal use only and drivers should mix that with their own debug module options. It is handled by the V4L2 core and users can set it using /sys/class/video4linux//debug. It has been deprecated for some time now, so it is time to remove it completely from the drivers. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 665e46d..6eed8f7 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3884,7 +3884,6 @@ static struct video_device *vdev_init(struct bttv *btv, *vfd = *template; vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->release = video_device_release; - vfd->debug = bttv_debug; video_set_drvdata(vfd, btv); snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index d3c79d9..b6be46e 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1234,6 +1234,3 @@ static void __exit blackbird_fini(void) module_init(blackbird_init); module_exit(blackbird_fini); - -module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [video]"); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 193373f..dd5b141 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1913,7 +1913,6 @@ int mccic_register(struct mcam_camera *cam) mutex_lock(&cam->s_mutex); cam->vdev = mcam_v4l_template; - cam->vdev.debug = 0; cam->vdev.v4l2_dev = &cam->v4l2_dev; video_set_drvdata(&cam->vdev, cam); ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 53ca12c..ecea76f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -2062,7 +2062,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - vfd->debug = video_debug; vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index cf7f58b..3691b39 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -2192,7 +2192,6 @@ static struct video_device *vfd = *template; vfd->v4l2_dev = &dev->v4l2->v4l2_dev; - vfd->debug = video_debug; vfd->lock = &dev->lock; if (dev->board.is_webcam) vfd->tvnorms = 0; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a4762910..65a326c 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -38,10 +38,6 @@ #include "stk1160.h" #include "stk1160-reg.h" -static unsigned int vidioc_debug; -module_param(vidioc_debug, int, 0644); -MODULE_PARM_DESC(vidioc_debug, "enable debug messages [vidioc]"); - static bool keep_buffers; module_param(keep_buffers, bool, 0644); MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming"); @@ -659,7 +655,6 @@ int stk1160_video_register(struct stk1160 *dev) /* Initialize video_device with a template structure */ dev->vdev = v4l_template; - dev->vdev.debug = vidioc_debug; dev->vdev.queue = &dev->vb_vidq; /* diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 3588dc3..e08fa58 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1262,7 +1262,6 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.lock = &dev->lock; - dev->vdev.debug = debug; dev->vdev.v4l2_dev = &dev->v4l2_dev; video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 793577f..0f14d3c 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -941,7 +941,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) { - dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)" + dprintk(dev, 2, "Fourcc format (0x%08x)" " invalid.\n", f->fmt.pix.pixelformat); return -EINVAL; } @@ -1622,7 +1622,6 @@ static struct video_device *vdev_init(struct tm6000_core *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - vfd->debug = tm6000_debug; vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 5c00627..ca85031 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1454,8 +1454,6 @@ static int zr364xx_probe(struct usb_interface *intf, cam->vdev.v4l2_dev = &cam->v4l2_dev; cam->vdev.ctrl_handler = &cam->ctrl_handler; video_set_drvdata(&cam->vdev, cam); - if (debug) - cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; cam->udev = udev; diff --git a/drivers/staging/media/tlg2300/pd-common.h b/drivers/staging/media/tlg2300/pd-common.h index 9e23ad32..04c5aac 100644 --- a/drivers/staging/media/tlg2300/pd-common.h +++ b/drivers/staging/media/tlg2300/pd-common.h @@ -250,7 +250,6 @@ void free_all_urb_generic(struct urb **urb_array, int num); /* misc */ void poseidon_delete(struct kref *kref); extern int debug_mode; -void set_debug_mode(struct video_device *vfd, int debug_mode); #ifdef CONFIG_PM #define in_hibernation(pd) (pd->msg.event == PM_EVENT_FREEZE) diff --git a/drivers/staging/media/tlg2300/pd-radio.c b/drivers/staging/media/tlg2300/pd-radio.c index b391194..c0567b5 100644 --- a/drivers/staging/media/tlg2300/pd-radio.c +++ b/drivers/staging/media/tlg2300/pd-radio.c @@ -98,12 +98,9 @@ static int poseidon_fm_open(struct file *filp) usb_autopm_get_interface(p->interface); if (0 == p->state) { - struct video_device *vfd = &p->radio_data.fm_dev; - /* default pre-emphasis */ if (p->radio_data.pre_emphasis == 0) p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR; - set_debug_mode(vfd, debug_mode); ret = poseidon_check_mode_radio(p); if (ret < 0) { diff --git a/drivers/staging/media/tlg2300/pd-video.c b/drivers/staging/media/tlg2300/pd-video.c index 8cd7f02..c0c3c1c 100644 --- a/drivers/staging/media/tlg2300/pd-video.c +++ b/drivers/staging/media/tlg2300/pd-video.c @@ -1299,15 +1299,6 @@ static int pm_video_resume(struct poseidon *pd) } #endif -void set_debug_mode(struct video_device *vfd, int debug_mode) -{ - vfd->debug = 0; - if (debug_mode & 0x1) - vfd->debug = V4L2_DEBUG_IOCTL; - if (debug_mode & 0x2) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; -} - static void init_video_context(struct running_context *context) { context->sig_index = 0; @@ -1354,7 +1345,6 @@ static int pd_video_open(struct file *file) front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; pd->video_data.users++; - set_debug_mode(vfd, debug_mode); videobuf_queue_vmalloc_init(&front->q, &pd_video_qops, NULL, &front->queue_lock, -- cgit v0.10.2 From 17028cdb74bf8bb593aebe5550bc90325fa9af88 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 1 Dec 2014 10:10:44 -0300 Subject: [media] v4l2 core: improve debug flag handling The old debug field is renamed to dev_debug to ensure that existing drivers (including out-of-tree drivers) that try to use the old name will no longer compile. A comment has also been added that makes it explicit that drivers shouldn't use this field. Additional bits have been added to the debug flag to be more fine-grained when debugging, especially when dealing with streaming ioctls and read, write and poll. You want to enable those explicitly to prevent flooding the log when streaming unless you actually want to do that. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index a13cc61..86bb93f 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -47,15 +47,15 @@ static ssize_t index_show(struct device *cd, } static DEVICE_ATTR_RO(index); -static ssize_t debug_show(struct device *cd, +static ssize_t dev_debug_show(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = to_video_device(cd); - return sprintf(buf, "%i\n", vdev->debug); + return sprintf(buf, "%i\n", vdev->dev_debug); } -static ssize_t debug_store(struct device *cd, struct device_attribute *attr, +static ssize_t dev_debug_store(struct device *cd, struct device_attribute *attr, const char *buf, size_t len) { struct video_device *vdev = to_video_device(cd); @@ -66,10 +66,10 @@ static ssize_t debug_store(struct device *cd, struct device_attribute *attr, if (res) return res; - vdev->debug = value; + vdev->dev_debug = value; return len; } -static DEVICE_ATTR_RW(debug); +static DEVICE_ATTR_RW(dev_debug); static ssize_t name_show(struct device *cd, struct device_attribute *attr, char *buf) @@ -82,7 +82,7 @@ static DEVICE_ATTR_RO(name); static struct attribute *video_device_attrs[] = { &dev_attr_name.attr, - &dev_attr_debug.attr, + &dev_attr_dev_debug.attr, &dev_attr_index.attr, NULL, }; @@ -304,7 +304,8 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, return -EINVAL; if (video_is_registered(vdev)) ret = vdev->fops->read(filp, buf, sz, off); - if (vdev->debug) + if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) && + (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING)) printk(KERN_DEBUG "%s: read: %zd (%d)\n", video_device_node_name(vdev), sz, ret); return ret; @@ -320,7 +321,8 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, return -EINVAL; if (video_is_registered(vdev)) ret = vdev->fops->write(filp, buf, sz, off); - if (vdev->debug) + if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) && + (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING)) printk(KERN_DEBUG "%s: write: %zd (%d)\n", video_device_node_name(vdev), sz, ret); return ret; @@ -335,7 +337,7 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) return DEFAULT_POLLMASK; if (video_is_registered(vdev)) res = vdev->fops->poll(filp, poll); - if (vdev->debug > 2) + if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL) printk(KERN_DEBUG "%s: poll: %08x\n", video_device_node_name(vdev), res); return res; @@ -404,7 +406,7 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp, if (!video_is_registered(vdev)) return -ENODEV; ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n", video_device_node_name(vdev), ret); return ret; @@ -420,7 +422,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) return -ENODEV; if (video_is_registered(vdev)) ret = vdev->fops->mmap(filp, vm); - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: mmap (%d)\n", video_device_node_name(vdev), ret); return ret; @@ -450,7 +452,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) ret = -ENODEV; } - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: open (%d)\n", video_device_node_name(vdev), ret); /* decrease the refcount in case of an error */ @@ -467,7 +469,7 @@ static int v4l2_release(struct inode *inode, struct file *filp) if (vdev->fops->release) ret = vdev->fops->release(filp); - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: release\n", video_device_node_name(vdev)); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index faac2f4..b084072 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2339,7 +2339,7 @@ static long __video_do_ioctl(struct file *file, const struct v4l2_ioctl_info *info; void *fh = file->private_data; struct v4l2_fh *vfh = NULL; - int debug = vfd->debug; + int dev_debug = vfd->dev_debug; long ret = -ENOTTY; if (ops == NULL) { @@ -2388,11 +2388,15 @@ static long __video_do_ioctl(struct file *file, } done: - if (debug) { + if (dev_debug & (V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG)) { + if (!(dev_debug & V4L2_DEV_DEBUG_STREAMING) && + (cmd == VIDIOC_QBUF || cmd == VIDIOC_DQBUF)) + return ret; + v4l_printk_ioctl(video_device_node_name(vfd), cmd); if (ret < 0) pr_cont(": error %ld", ret); - if (debug == V4L2_DEBUG_IOCTL) + if (!(dev_debug & V4L2_DEV_DEBUG_IOCTL_ARG)) pr_cont("\n"); else if (_IOC_DIR(cmd) == _IOC_NONE) info->debug(arg, write_only); diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index eb76cfd..3e4fddf 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -124,7 +124,8 @@ struct video_device spinlock_t fh_lock; /* Lock for all v4l2_fhs */ struct list_head fh_list; /* List of struct v4l2_fh */ - int debug; /* Activates debug level*/ + /* Internal device debug flags, not for use by drivers */ + int dev_debug; /* Video standard vars */ v4l2_std_id tvnorms; /* Supported tv norms */ diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 53605f0..8537983 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -291,9 +291,18 @@ struct v4l2_ioctl_ops { /* v4l debugging and diagnostics */ -/* Debug bitmask flags to be used on V4L2 */ -#define V4L2_DEBUG_IOCTL 0x01 -#define V4L2_DEBUG_IOCTL_ARG 0x02 +/* Device debug flags to be used with the video device debug attribute */ + +/* Just log the ioctl name + error code */ +#define V4L2_DEV_DEBUG_IOCTL 0x01 +/* Log the ioctl name arguments + error code */ +#define V4L2_DEV_DEBUG_IOCTL_ARG 0x02 +/* Log the file operations open, release, mmap and get_unmapped_area */ +#define V4L2_DEV_DEBUG_FOP 0x04 +/* Log the read and write file operations and the VIDIOC_(D)QBUF ioctls */ +#define V4L2_DEV_DEBUG_STREAMING 0x08 +/* Log poll() */ +#define V4L2_DEV_DEBUG_POLL 0x10 /* Video standard functions */ extern const char *v4l2_norm_to_name(v4l2_std_id id); -- cgit v0.10.2 From 88f414f476bdf9def8123fec49890a3c94b5fb53 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 1 Dec 2014 10:10:45 -0300 Subject: [media] v4l2-framework.txt: document debug attribute The debug attribute in /sys/class/video4linux//debug was never documented. Add this. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index a11dff0..f586e29 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -793,8 +793,10 @@ video_register_device_no_warn() instead. Whenever a device node is created some attributes are also created for you. If you look in /sys/class/video4linux you see the devices. Go into e.g. -video0 and you will see 'name' and 'index' attributes. The 'name' attribute -is the 'name' field of the video_device struct. +video0 and you will see 'name', 'debug' and 'index' attributes. The 'name' +attribute is the 'name' field of the video_device struct. The 'debug' attribute +can be used to enable core debugging. See the next section for more detailed +information on this. The 'index' attribute is the index of the device node: for each call to video_register_device() the index is just increased by 1. The first video @@ -816,6 +818,25 @@ video_device was embedded in it. The vdev->release() callback will never be called if the registration failed, nor should you ever attempt to unregister the device if the registration failed. +video device debugging +---------------------- + +The 'debug' attribute that is created for each video, vbi, radio or swradio +device in /sys/class/video4linux// allows you to enable logging of +file operations. + +It is a bitmask and the following bits can be set: + +0x01: Log the ioctl name and error code. VIDIOC_(D)QBUF ioctls are only logged + if bit 0x08 is also set. +0x02: Log the ioctl name arguments and error code. VIDIOC_(D)QBUF ioctls are + only logged if bit 0x08 is also set. +0x04: Log the file operations open, release, read, write, mmap and + get_unmapped_area. The read and write operations are only logged if + bit 0x08 is also set. +0x08: Log the read and write file operations and the VIDIOC_QBUF and + VIDIOC_DQBUF ioctls. +0x10: Log the poll file operation. video_device cleanup -------------------- -- cgit v0.10.2 From e5b30145e56a20caeffed553d1239e401e4fb4e2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:51 -0300 Subject: [media] av7110: fix sparse warning drivers/media/pci/ttpci/av7110.c:1226:15: warning: memset with byte count of 192512 Instead of memsetting this in one go, loop over each line and memset each line separately. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index c1f0617..45199a1 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -1219,11 +1219,14 @@ static int stop_ts_capture(struct av7110 *budget) static int start_ts_capture(struct av7110 *budget) { + unsigned y; + dprintk(2, "budget: %p\n", budget); if (budget->feeding1) return ++budget->feeding1; - memset(budget->grabbing, 0x00, TS_BUFLEN); + for (y = 0; y < TS_HEIGHT; y++) + memset(budget->grabbing + y * TS_WIDTH, 0x00, TS_WIDTH); budget->ttbp = 0; SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ -- cgit v0.10.2 From 65adb86d6142f1233e84c81112907f4caa6afffd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:52 -0300 Subject: [media] budget-core: fix sparse warnings Fixes these sparse warnings. drivers/media/pci/ttpci/budget-core.c:250:17: warning: context imbalance in 'ttpci_budget_debiread' - different lock contexts for basic block drivers/media/pci/ttpci/budget-core.c:289:17: warning: context imbalance in 'ttpci_budget_debiwrite' - different lock contexts for basic block To be honest, the new code does look better than the old. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index 37d02fe..23e0549 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c @@ -231,63 +231,59 @@ static void vpeirq(unsigned long data) } -int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop) +static int ttpci_budget_debiread_nolock(struct budget *budget, u32 config, + int addr, int count, int nobusyloop) { struct saa7146_dev *saa = budget->dev; - int result = 0; - unsigned long flags = 0; - - if (count > 4 || count <= 0) - return 0; - - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); + int result; - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + result = saa7146_wait_for_debi_done(saa, nobusyloop); + if (result < 0) return result; - } saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); saa7146_write(saa, DEBI_CONFIG, config); saa7146_write(saa, DEBI_PAGE, 0); saa7146_write(saa, MC2, (2 << 16) | 2); - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + result = saa7146_wait_for_debi_done(saa, nobusyloop); + if (result < 0) return result; - } result = saa7146_read(saa, DEBI_AD); result &= (0xffffffffUL >> ((4 - count) * 8)); - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; } -int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, - int count, u32 value, int uselocks, int nobusyloop) +int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop) { - struct saa7146_dev *saa = budget->dev; - unsigned long flags = 0; - int result; - if (count > 4 || count <= 0) return 0; - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); + if (uselocks) { + unsigned long flags; + int result; - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + spin_lock_irqsave(&budget->debilock, flags); + result = ttpci_budget_debiread_nolock(budget, config, addr, + count, nobusyloop); + spin_unlock_irqrestore(&budget->debilock, flags); return result; } + return ttpci_budget_debiread_nolock(budget, config, addr, + count, nobusyloop); +} + +static int ttpci_budget_debiwrite_nolock(struct budget *budget, u32 config, + int addr, int count, u32 value, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + int result; + + result = saa7146_wait_for_debi_done(saa, nobusyloop); + if (result < 0) + return result; saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); saa7146_write(saa, DEBI_CONFIG, config); @@ -295,15 +291,28 @@ int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, saa7146_write(saa, DEBI_AD, value); saa7146_write(saa, MC2, (2 << 16) | 2); - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } + result = saa7146_wait_for_debi_done(saa, nobusyloop); + return result < 0 ? result : 0; +} - if (uselocks) +int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, + int count, u32 value, int uselocks, int nobusyloop) +{ + if (count > 4 || count <= 0) + return 0; + + if (uselocks) { + unsigned long flags; + int result; + + spin_lock_irqsave(&budget->debilock, flags); + result = ttpci_budget_debiwrite_nolock(budget, config, addr, + count, value, nobusyloop); spin_unlock_irqrestore(&budget->debilock, flags); - return 0; + return result; + } + return ttpci_budget_debiwrite_nolock(budget, config, addr, + count, value, nobusyloop); } -- cgit v0.10.2 From d832672f2038d7b36dc08636468cbbed4afe625b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:53 -0300 Subject: [media] ivtv: fix sparse warning Fix this warning: drivers/media/pci/ivtv/ivtv-irq.c:418:9: warning: context imbalance in 'ivtv_dma_stream_dec_prepare' - different lock contexts for basic block sparse didn't quite understand the locking scheme, so rewrite it to keep sparse happy. Signed-off-by: Hans Verkuil Cc: Andy Walls Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index ab6d5d2..e7d7017 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -357,7 +357,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; int bytes_written = 0; - unsigned long flags = 0; int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); @@ -407,16 +406,21 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) /* Sync Hardware SG List of buffers */ ivtv_stream_sync_for_device(s); - if (lock) + if (lock) { + unsigned long flags = 0; + spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - ivtv_dma_dec_start(s); - } - else { - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } - if (lock) + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) + ivtv_dma_dec_start(s); + else + set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); spin_unlock_irqrestore(&itv->dma_reg_lock, flags); + } else { + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) + ivtv_dma_dec_start(s); + else + set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); + } } static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) -- cgit v0.10.2 From 7c424dd14fcf4c2905778ecd3f1ad10c5a097b5b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:54 -0300 Subject: [media] videobuf2-vmalloc: fix sparse warning Fix this warning: drivers/media/v4l2-core/videobuf2-vmalloc.c:98:28: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/videobuf2-vmalloc.c:158:28: warning: incorrect type in argument 1 (different address spaces) The warning is correct, but we have no other choice here to forcibly cast. At least it is now explicit that such a cast is needed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index fba944e..7f6d41b 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -95,7 +95,7 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, if (vb2_get_contig_userptr(vaddr, size, &vma, &physp)) goto fail_pages_array_alloc; buf->vma = vma; - buf->vaddr = ioremap_nocache(physp, size); + buf->vaddr = (__force void *)ioremap_nocache(physp, size); if (!buf->vaddr) goto fail_pages_array_alloc; } else { @@ -155,7 +155,7 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) kfree(buf->pages); } else { vb2_put_vma(buf->vma); - iounmap(buf->vaddr); + iounmap((__force void __iomem *)buf->vaddr); } kfree(buf); } -- cgit v0.10.2 From 50fd5e8c1e02ac471a0a4f3aaa87684a5152a0b4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:56 -0300 Subject: [media] hd29l2: fix sparse error and warnings drivers/media/dvb-frontends/hd29l2.c:29:18: warning: Variable length array is used. drivers/media/dvb-frontends/hd29l2.c:34:32: error: cannot size expression drivers/media/dvb-frontends/hd29l2.c:125:5: warning: symbol 'hd29l2_rd_reg_mask' was not declared. Should it be static? Variable length arrays are frowned upon, so replace with a fixed length and check that there won't be a buffer overrun. Signed-off-by: Hans Verkuil Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c index d7b9d54..67c8e6d 100644 --- a/drivers/media/dvb-frontends/hd29l2.c +++ b/drivers/media/dvb-frontends/hd29l2.c @@ -22,20 +22,24 @@ #include "hd29l2_priv.h" +#define HD29L2_MAX_LEN (3) + /* write multiple registers */ static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[2 + len]; + u8 buf[2 + HD29L2_MAX_LEN]; struct i2c_msg msg[1] = { { .addr = priv->cfg.i2c_addr, .flags = 0, - .len = sizeof(buf), + .len = 2 + len, .buf = buf, } }; + if (len > HD29L2_MAX_LEN) + return -EINVAL; buf[0] = 0x00; buf[1] = reg; memcpy(&buf[2], val, len); @@ -118,7 +122,7 @@ static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask) } /* read single register with mask */ -int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask) +static int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask) { int ret, i; u8 tmp; -- cgit v0.10.2 From d3acd83e6ea42146189c0b60de24fd89bcb92e4b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:57 -0300 Subject: [media] m5mols: fix sparse warnings drivers/media/i2c/m5mols/m5mols_core.c:128:24: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:128:24: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:128:24: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:128:24: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:130:24: warning: cast to restricted __be32 drivers/media/i2c/m5mols/m5mols_core.c:130:24: warning: cast to restricted __be32 drivers/media/i2c/m5mols/m5mols_core.c:130:24: warning: cast to restricted __be32 drivers/media/i2c/m5mols/m5mols_core.c:130:24: warning: cast to restricted __be32 drivers/media/i2c/m5mols/m5mols_core.c:130:24: warning: cast to restricted __be32 drivers/media/i2c/m5mols/m5mols_core.c:130:24: warning: cast to restricted __be32 drivers/media/i2c/m5mols/m5mols_core.c:457:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:457:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:457:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:457:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:458:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:458:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:458:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:458:19: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:459:22: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:459:22: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:459:22: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:459:22: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:460:20: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:460:20: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:460:20: warning: cast to restricted __be16 drivers/media/i2c/m5mols/m5mols_core.c:460:20: warning: cast to restricted __be16 The be16_to_cpu conversions in m5mols_get_version() are not needed since the data is already using cpu endianness. This was never noticed since these version fields are never used. Signed-off-by: Hans Verkuil Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 2820f7c..6ed16e5 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -125,9 +125,9 @@ static u32 m5mols_swap_byte(u8 *data, u8 length) if (length == 1) return *data; else if (length == 2) - return be16_to_cpu(*((u16 *)data)); + return be16_to_cpu(*((__be16 *)data)); else - return be32_to_cpu(*((u32 *)data)); + return be32_to_cpu(*((__be32 *)data)); } /** @@ -454,11 +454,6 @@ static int m5mols_get_version(struct v4l2_subdev *sd) return ret; } - ver->fw = be16_to_cpu(ver->fw); - ver->hw = be16_to_cpu(ver->hw); - ver->param = be16_to_cpu(ver->param); - ver->awb = be16_to_cpu(ver->awb); - v4l2_info(sd, "Manufacturer\t[%s]\n", is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? "Samsung Electro-Machanics" : -- cgit v0.10.2 From b75f2d16cb0d3f75104f8565dd5f713dbf4a074d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:58 -0300 Subject: [media] s5k4ecgx: fix sparse warnings drivers/media/i2c/s5k4ecgx.c:223:16: warning: cast to restricted __be16 drivers/media/i2c/s5k4ecgx.c:223:16: warning: cast to restricted __be16 drivers/media/i2c/s5k4ecgx.c:223:16: warning: cast to restricted __be16 drivers/media/i2c/s5k4ecgx.c:223:16: warning: cast to restricted __be16 drivers/media/i2c/s5k4ecgx.c:344:20: warning: cast to restricted __le32 drivers/media/i2c/s5k4ecgx.c:354:20: warning: cast to restricted __le32 drivers/media/i2c/s5k4ecgx.c:364:24: warning: cast to restricted __le32 drivers/media/i2c/s5k4ecgx.c:366:23: warning: cast to restricted __le16 The get_unaligned_le*() functions return the value using cpu endianness, so calling le*_to_cpu is wrong. It hasn't been not noticed because this code has only been run on little endian systems, so le*_to_cpu doesn't do anything. Signed-off-by: Hans Verkuil Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index d1c50c9..7007131 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -220,7 +220,7 @@ static int s5k4ecgx_i2c_read(struct i2c_client *client, u16 addr, u16 *val) msg[1].buf = rbuf; ret = i2c_transfer(client->adapter, msg, 2); - *val = be16_to_cpu(*((u16 *)rbuf)); + *val = be16_to_cpu(*((__be16 *)rbuf)); v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); @@ -341,7 +341,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE); return err; } - regs_num = le32_to_cpu(get_unaligned_le32(fw->data)); + regs_num = get_unaligned_le32(fw->data); v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n", S5K4ECGX_FIRMWARE, fw->size, regs_num); @@ -351,8 +351,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) err = -EINVAL; goto fw_out; } - crc_file = le32_to_cpu(get_unaligned_le32(fw->data + - regs_num * FW_RECORD_SIZE)); + crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE); crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE); if (crc != crc_file) { v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file); @@ -361,9 +360,9 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) } ptr = fw->data + FW_RECORD_SIZE; for (i = 1; i < regs_num; i++) { - addr = le32_to_cpu(get_unaligned_le32(ptr)); + addr = get_unaligned_le32(ptr); ptr += sizeof(u32); - val = le16_to_cpu(get_unaligned_le16(ptr)); + val = get_unaligned_le16(ptr); ptr += sizeof(u16); if (addr - addr_inc != 2) err = s5k4ecgx_write(client, addr, val); -- cgit v0.10.2 From 7c7586bb3c132f93b27148fe686dbd979f64d902 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:52:59 -0300 Subject: [media] s5k6aa: fix sparse warnings drivers/media/i2c/s5k6aa.c:351:16: warning: cast to restricted __be16 drivers/media/i2c/s5k6aa.c:351:16: warning: cast to restricted __be16 drivers/media/i2c/s5k6aa.c:351:16: warning: cast to restricted __be16 drivers/media/i2c/s5k6aa.c:351:16: warning: cast to restricted __be16 Signed-off-by: Hans Verkuil Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index 19edafb..b1c5832 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -348,7 +348,7 @@ static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) msg[1].buf = rbuf; ret = i2c_transfer(client->adapter, msg, 2); - *val = be16_to_cpu(*((u16 *)rbuf)); + *val = be16_to_cpu(*((__be16 *)rbuf)); v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); -- cgit v0.10.2 From 0348bb1a7aa6093e9aead41d50c792576839a3a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Dec 2014 08:53:00 -0300 Subject: [media] s5k5baf: fix sparse warnings drivers/media/i2c/s5k5baf.c:1796:33: warning: duplicate const drivers/media/i2c/s5k5baf.c:379:24: warning: cast to restricted __le16 drivers/media/i2c/s5k5baf.c:437:11: warning: incorrect type in assignment (different base types) drivers/media/i2c/s5k5baf.c:445:16: warning: incorrect type in return expression (different base types) Signed-off-by: Hans Verkuil Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 60a74d8..a3d7d03 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -353,7 +353,7 @@ static struct v4l2_rect s5k5baf_cis_rect = { * */ static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw, - size_t count, const u16 *data) + size_t count, const __le16 *data) { struct s5k5baf_fw *f; u16 *d, i, *end; @@ -421,6 +421,7 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr) { struct i2c_client *c = v4l2_get_subdevdata(&state->sd); __be16 w, r; + u16 res; struct i2c_msg msg[] = { { .addr = c->addr, .flags = 0, .len = 2, .buf = (u8 *)&w }, @@ -434,15 +435,15 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr) w = cpu_to_be16(addr); ret = i2c_transfer(c->adapter, msg, 2); - r = be16_to_cpu(r); + res = be16_to_cpu(r); - v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, r); + v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, res); if (ret != 2) { v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret); state->error = ret; } - return r; + return res; } static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val) @@ -1037,7 +1038,7 @@ static int s5k5baf_load_setfile(struct s5k5baf *state) } ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2, - (u16 *)fw->data); + (__le16 *)fw->data); release_firmware(fw); @@ -1793,7 +1794,7 @@ static const struct v4l2_subdev_ops s5k5baf_subdev_ops = { static int s5k5baf_configure_gpios(struct s5k5baf *state) { - static const char const *name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" }; + static const char * const name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" }; struct i2c_client *c = v4l2_get_subdevdata(&state->sd); struct s5k5baf_gpio *g = state->gpios; int ret, i; -- cgit v0.10.2 From 9571a17fc253e1b362217352d7faa815ba5b5a3e Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 16 Dec 2014 20:17:20 -0300 Subject: [media] media: au0828 VBI support comment cleanup This driver supports VBI and the comment "VBI support is not yet working" is inaccurate. Remove it. Signed-off-by: Shuah Khan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 5f337b1..8a7a547 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -22,7 +22,6 @@ /* Developer Notes: * - * VBI support is not yet working * The hardware scaler supported is unimplemented * AC97 audio support is unimplemented (only i2s audio mode) * -- cgit v0.10.2 From 94acbe12f589bfcb37ed8a12c5efd14140044642 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 15 Dec 2014 10:55:37 -0300 Subject: [media] VIDEO_CAFE_CCIC should select VIDEOBUF2_DMA_SG If VIDEO_CAFE_CCIC=y, but VIDEOBUF2_DMA_SG=m: drivers/built-in.o: In function `mcam_v4l_open': mcam-core.c:(.text+0x1c2e81): undefined reference to `vb2_dma_sg_memops' mcam-core.c:(.text+0x1c2eb0): undefined reference to `vb2_dma_sg_init_ctx' drivers/built-in.o: In function `mcam_v4l_release': mcam-core.c:(.text+0x1c34bf): undefined reference to `vb2_dma_sg_cleanup_ctx' Reported-by: Fengguang Wu Signed-off-by: Geert Uytterhoeven Acked-by: Jonathan Corbet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index 6265d36..3d16656 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -5,6 +5,7 @@ config VIDEO_CAFE_CCIC select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG ---help--- This is a video4linux2 driver for the Marvell 88ALP01 integrated CMOS camera controller. This is the controller found on first- -- cgit v0.10.2 From a2391a80fba2f4d9a12727e4dbd5d4cbde31469c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 7 Dec 2014 19:56:38 -0300 Subject: [media] DocBook: v4l: Fix raw bayer pixel format documentation wording The documentation began with "The following four pixel formats"... but the format definitions preceded this sentence. Replace it with "These four pixel formats". Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml index c1c62a9..f34d03e 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml @@ -17,7 +17,7 @@ Description - The following four pixel formats are raw sRGB / Bayer formats with + These four pixel formats are raw sRGB / Bayer formats with 10 bits per colour. Each colour component is stored in a 16-bit word, with 6 unused high bits filled with zeros. Each n-pixel row contains n/2 green samples and n/2 blue or red samples, with alternating red and blue rows. Bytes are diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml index 29acc20..d2e5845 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml @@ -25,7 +25,7 @@ Description - The following four pixel formats are raw sRGB / Bayer + These four pixel formats are raw sRGB / Bayer formats with 10 bits per color compressed to 8 bits each, using the A-LAW algorithm. Each color component consumes 8 bits of memory. In other respects this format is similar to diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml index 2d3f0b1a..bde8987 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml @@ -18,7 +18,7 @@ Description - The following four pixel formats are raw sRGB / Bayer formats + These four pixel formats are raw sRGB / Bayer formats with 10 bits per colour compressed to 8 bits each, using DPCM compression. DPCM, differential pulse-code modulation, is lossy. Each colour component consumes 8 bits of memory. In other respects diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml index 96947f1..0c8e4ad 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml @@ -17,7 +17,7 @@ Description - The following four pixel formats are raw sRGB / Bayer formats with + These four pixel formats are raw sRGB / Bayer formats with 12 bits per colour. Each colour component is stored in a 16-bit word, with 4 unused high bits filled with zeros. Each n-pixel row contains n/2 green samples and n/2 blue or red samples, with alternating red and blue rows. Bytes are -- cgit v0.10.2 From cbb77bc281d697764dbb035157b643a8cbc9df30 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 7 Dec 2014 20:17:49 -0300 Subject: [media] DocBook: v4l: Rearrange raw bayer format definitions, remove bad comment Rearrange 12-bit raw bayer format definitions after 10-bit ones. Also remove the comment related to 16-bit bayer formats, it was simply wrong. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index d279c1b..f0b94b8 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -463,10 +463,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ -#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ /* 10bit raw bayer a-law compressed to 8 bits */ #define V4L2_PIX_FMT_SBGGR10ALAW8 v4l2_fourcc('a', 'B', 'A', '8') #define V4L2_PIX_FMT_SGBRG10ALAW8 v4l2_fourcc('a', 'G', 'A', '8') @@ -477,10 +473,10 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8') #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') #define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8') - /* - * 10bit raw bayer, expanded to 16 bits - * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... - */ +#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */ +#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ +#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ /* compressed formats */ -- cgit v0.10.2 From 4353e36ee84d936859eb6d65ecd9d3076edd11bc Mon Sep 17 00:00:00 2001 From: Aviv Greenberg Date: Wed, 3 Dec 2014 08:14:09 -0300 Subject: [media] v4l: Add packed Bayer raw10 pixel formats These formats are just like 10-bit raw bayer formats that exist already, but the pixels are not padded to byte boundaries. Instead, the eight high order bits of four consecutive pixels are stored in four bytes, followed by a byte of two low order bits of each of the four pixels. Signed-off-by: Aviv Greenberg Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml new file mode 100644 index 0000000..30aa635 --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml @@ -0,0 +1,99 @@ + + + V4L2_PIX_FMT_SRGGB10P ('pRAA'), + V4L2_PIX_FMT_SGRBG10P ('pgAA'), + V4L2_PIX_FMT_SGBRG10P ('pGAA'), + V4L2_PIX_FMT_SBGGR10P ('pBAA'), + + &manvol; + + + V4L2_PIX_FMT_SRGGB10P + V4L2_PIX_FMT_SGRBG10P + V4L2_PIX_FMT_SGBRG10P + V4L2_PIX_FMT_SBGGR10P + 10-bit packed Bayer formats + + + Description + + These four pixel formats are packed raw sRGB / + Bayer formats with 10 bits per colour. Every four consecutive + colour components are packed into 5 bytes. Each of the first 4 + bytes contain the 8 high order bits of the pixels, and the + fifth byte contains the two least significants bits of each + pixel, in the same order. + + Each n-pixel row contains n/2 green samples and n/2 blue + or red samples, with alternating green-red and green-blue + rows. They are conventionally described as GRGR... BGBG..., + RGRG... GBGB..., etc. Below is an example of one of these + formats: + + + <constant>V4L2_PIX_FMT_SBGGR10P</constant> 4 × 4 + pixel image + + + Byte Order. + Each cell is one byte. + + + + + + start + 0: + B00high + G01high + B02high + G03high + B00low(bits 7--6) + G01low(bits 5--4) + B02low(bits 3--2) + G03low(bits 1--0) + + + + start + 5: + G10high + R11high + G12high + R13high + G10low(bits 7--6) + R11low(bits 5--4) + G12low(bits 3--2) + R13low(bits 1--0) + + + + start + 10: + B20high + G21high + B22high + G23high + B20low(bits 7--6) + G21low(bits 5--4) + B22low(bits 3--2) + G23low(bits 1--0) + + + + start + 15: + G30high + R31high + G32high + R33high + G30low(bits 7--6) + R31low(bits 5--4) + G32low(bits 3--2) + R33low(bits 1--0) + + + + + + + + + + diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index d5eca4b..5e0352c 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -1405,6 +1405,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.< &sub-srggb8; &sub-sbggr16; &sub-srggb10; + &sub-srggb10p; &sub-srggb10alaw8; &sub-srggb10dpcm8; &sub-srggb12; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index f0b94b8..fbdc360 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -463,6 +463,11 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ + /* 10bit raw bayer packed, 5 bytes for every 4 pixels */ +#define V4L2_PIX_FMT_SBGGR10P v4l2_fourcc('p', 'B', 'A', 'A') +#define V4L2_PIX_FMT_SGBRG10P v4l2_fourcc('p', 'G', 'A', 'A') +#define V4L2_PIX_FMT_SGRBG10P v4l2_fourcc('p', 'g', 'A', 'A') +#define V4L2_PIX_FMT_SRGGB10P v4l2_fourcc('p', 'R', 'A', 'A') /* 10bit raw bayer a-law compressed to 8 bits */ #define V4L2_PIX_FMT_SBGGR10ALAW8 v4l2_fourcc('a', 'B', 'A', '8') #define V4L2_PIX_FMT_SGBRG10ALAW8 v4l2_fourcc('a', 'G', 'A', '8') -- cgit v0.10.2 From 29867e2febad863fb3cef99ad894cd992df5e665 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 18 Oct 2014 06:11:19 -0300 Subject: [media] smiapp: Remove FSF's address from the license header Remove FSF's address information from the license header in the smiapp driver and the smiapp-pll PLL calculator. This should no longer be needed, and would be rendered outdated in case the FSF chooses to relocate its office. Signed-off-by: Sakari Ailus Cc: Timo Ahonen Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index e40d902..2b84d09 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h index e8f035a..77f7ff2f 100644 --- a/drivers/media/i2c/smiapp-pll.h +++ b/drivers/media/i2c/smiapp-pll.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #ifndef SMIAPP_PLL_H diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 0df5070e..cee1a9a 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -18,12 +18,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c index 847cb23..784b114 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.c +++ b/drivers/media/i2c/smiapp/smiapp-limits.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include "smiapp.h" diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h index 343e9c3..b201248 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.h +++ b/drivers/media/i2c/smiapp/smiapp-limits.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0 diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index e0bee87..dd4ae6f 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index 46e9ea8..3a3c3e5 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #ifndef __SMIAPP_QUIRK__ diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h index c488ef0..f928d4c 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r)) #define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r)) diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h index b0dcbb8..4c8b406 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg.h +++ b/drivers/media/i2c/smiapp/smiapp-reg.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #ifndef __SMIAPP_REG_H_ diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index a209800..6b6c20b 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index 3552112..6dd0e49 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #ifndef SMIAPP_REGS_H diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index f88f8ec..8fded46 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #ifndef __SMIAPP_PRIV_H_ -- cgit v0.10.2 From fd2bfdc863c7912e4865f9d993b2ab1108645fd5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 16 Nov 2014 12:08:44 -0300 Subject: [media] smiapp: List include/uapi/linux/smiapp.h in MAINTAINERS This is part of the smiapp driver. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8..f7d04bac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8826,6 +8826,7 @@ F: drivers/media/i2c/smiapp/ F: include/media/smiapp.h F: drivers/media/i2c/smiapp-pll.c F: drivers/media/i2c/smiapp-pll.h +F: include/uapi/linux/smiapp.h SMM665 HARDWARE MONITOR DRIVER M: Guenter Roeck -- cgit v0.10.2 From 8c20ee6e92e435609f8d7dd0c2b4b77c8dbb3f18 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 18 Oct 2014 06:16:20 -0300 Subject: [media] smiapp-pll: include linux/device.h in smiapp-pll.c, not in smiapp-pll.h struct device has a forward declaration in the header already. The header is only needed in the .c file. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index 2b84d09..e3348db 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -16,6 +16,7 @@ * General Public License for more details. */ +#include #include #include #include diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h index 77f7ff2f..b98d143 100644 --- a/drivers/media/i2c/smiapp-pll.h +++ b/drivers/media/i2c/smiapp-pll.h @@ -19,8 +19,6 @@ #ifndef SMIAPP_PLL_H #define SMIAPP_PLL_H -#include - /* CSI-2 or CCP-2 */ #define SMIAPP_PLL_BUS_TYPE_CSI2 0x00 #define SMIAPP_PLL_BUS_TYPE_PARALLEL 0x01 -- cgit v0.10.2 From ec176a6f142bb403b8a9b977a6919b556e80ea99 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 30 Nov 2013 16:35:48 -0300 Subject: [media] smiapp: Use types better suitable for DT Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/smiapp.h b/include/media/smiapp.h index 0b8f124..268a3cd 100644 --- a/include/media/smiapp.h +++ b/include/media/smiapp.h @@ -65,19 +65,19 @@ struct smiapp_platform_data { unsigned short i2c_addr_dfl; /* Default i2c addr */ unsigned short i2c_addr_alt; /* Alternate i2c addr */ - unsigned int nvm_size; /* bytes */ - unsigned int ext_clk; /* sensor external clk */ + uint32_t nvm_size; /* bytes */ + uint32_t ext_clk; /* sensor external clk */ unsigned int lanes; /* Number of CSI-2 lanes */ - u8 csi_signalling_mode; /* SMIAPP_CSI_SIGNALLING_MODE_* */ - const s64 *op_sys_clock; + uint32_t csi_signalling_mode; /* SMIAPP_CSI_SIGNALLING_MODE_* */ + uint64_t *op_sys_clock; enum smiapp_module_board_orient module_board_orient; struct smiapp_flash_strobe_parms *strobe_setup; int (*set_xclk)(struct v4l2_subdev *sd, int hz); - int xshutdown; /* gpio or SMIAPP_NO_XSHUTDOWN */ + int32_t xshutdown; /* gpio or SMIAPP_NO_XSHUTDOWN */ }; #endif /* __SMIAPP_H_ */ -- cgit v0.10.2 From 3d9bb7a620f061fd94da043bd9e69a65a9510981 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 8 Dec 2014 17:49:31 -0300 Subject: [media] smiapp: Don't give the source sub-device a temporary name The source sub-device's name will be overwritten shortly. Don't give it a name in the meantime. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index cee1a9a..3d5fba4 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2458,8 +2458,6 @@ static int smiapp_identify_module(struct v4l2_subdev *subdev) minfo->name, minfo->manufacturer_id, minfo->model_id, minfo->revision_number_major); - strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name)); - return 0; } -- cgit v0.10.2 From f73108eb8e804180cb7f834649c670ba8b892777 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 30 Nov 2013 17:51:15 -0300 Subject: [media] smiapp: Register async subdev Register and unregister async sub-device for DT. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 3d5fba4..2c65ff3 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2942,8 +2942,21 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->sensor = sensor; sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; - return media_entity_init(&sensor->src->sd.entity, 2, + rval = media_entity_init(&sensor->src->sd.entity, 2, sensor->src->pads, 0); + if (rval < 0) + return rval; + + rval = v4l2_async_register_subdev(&sensor->src->sd); + if (rval < 0) + goto out_media_entity_cleanup; + + return 0; + +out_media_entity_cleanup: + media_entity_cleanup(&sensor->src->sd.entity); + + return rval; } static int smiapp_remove(struct i2c_client *client) @@ -2952,6 +2965,8 @@ static int smiapp_remove(struct i2c_client *client) struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); unsigned int i; + v4l2_async_unregister_subdev(subdev); + if (sensor->power_count) { if (gpio_is_valid(sensor->platform_data->xshutdown)) gpio_set_value(sensor->platform_data->xshutdown, 0); -- cgit v0.10.2 From 575ea5b3a41c3facb6e7973fdce865d208bf89c9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 26 Jan 2014 21:13:13 -0300 Subject: [media] smiapp: The sensor only needs a single clock, name may be NULL The SMIA compatible sensors only need a single clock. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 2c65ff3..3dd32b1 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2482,7 +2482,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) } if (!sensor->platform_data->set_xclk) { - sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk"); + sensor->ext_clk = devm_clk_get(&client->dev, NULL); if (IS_ERR(sensor->ext_clk)) { dev_err(&client->dev, "could not get clock\n"); return PTR_ERR(sensor->ext_clk); -- cgit v0.10.2 From 0f8e2537852f39414e00093934cea154917d2ccf Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 8 Nov 2014 08:38:10 -0300 Subject: [media] of: v4l: Document link-frequencies property in video-interfaces.txt link-frequencies is a 64-bit unsigned integer array of allowed link frequencies. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index ce719f8..52a14cf 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -103,6 +103,9 @@ Optional endpoint properties array contains only one entry. - clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous clock mode. +- link-frequencies: Allowed data bus frequencies. For MIPI CSI-2, for + instance, this is the actual frequency of the bus, not bits per clock per + lane value. An array of 64-bit unsigned integers. Example -- cgit v0.10.2 From a2cec3c0199ab4d7c0d83dee7fc69bd22eef7e12 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 6 Nov 2014 18:16:13 -0300 Subject: [media] of: smiapp: Add documentation Document the smiapp device tree properties. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt new file mode 100644 index 0000000..855e1fa --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -0,0 +1,63 @@ +SMIA/SMIA++ sensor + +SMIA (Standard Mobile Imaging Architecture) is an image sensor standard +defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension +of that. These definitions are valid for both types of sensors. + +More detailed documentation can be found in +Documentation/devicetree/bindings/media/video-interfaces.txt . + + +Mandatory properties +-------------------- + +- compatible: "nokia,smia" +- reg: I2C address (0x10, or an alternative address) +- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor + dependent). +- clocks: External clock to the sensor +- clock-frequency: Frequency of the external clock to the sensor +- link-frequencies: List of allowed data link frequencies. An array of + 64-bit elements. + + +Optional properties +------------------- + +- nokia,nvm-size: The size of the NVM, in bytes. If the size is not given, + the NVM contents will not be read. +- reset-gpios: XSHUTDOWN GPIO + + +Endpoint node mandatory properties +---------------------------------- + +- clock-lanes: <0> +- data-lanes: <1..n> +- remote-endpoint: A phandle to the bus receiver's endpoint node. + + +Example +------- + +&i2c2 { + clock-frequency = <400000>; + + smiapp_1: camera@10 { + compatible = "nokia,smia"; + reg = <0x10>; + reset-gpios = <&gpio3 20 0>; + vana-supply = <&vaux3>; + clocks = <&omap3_isp 0>; + clock-frequency = <9600000>; + nokia,nvm-size = <512>; /* 8 * 64 */ + link-frequencies = /bits/ 64 <199200000 210000000 499200000>; + port { + smiapp_1_1: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&csi2a_ep>; + }; + }; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index f7d04bac..dc2d912 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8827,6 +8827,7 @@ F: include/media/smiapp.h F: drivers/media/i2c/smiapp-pll.c F: drivers/media/i2c/smiapp-pll.h F: include/uapi/linux/smiapp.h +F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt SMM665 HARDWARE MONITOR DRIVER M: Guenter Roeck -- cgit v0.10.2 From 390a5fa5bd07fd683f8f8a2b2959400242e0b76f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 30 Nov 2013 17:51:15 -0300 Subject: [media] smiapp: Obtain device information from the Device Tree if OF node exists Platform data support is retained. of_property_read_u64_array() isn't used yet as it's not in yet. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 3dd32b1..a6bc5ef 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -25,11 +25,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "smiapp.h" @@ -2919,19 +2921,121 @@ static int smiapp_resume(struct device *dev) #endif /* CONFIG_PM */ +static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) +{ + struct smiapp_platform_data *pdata; + struct v4l2_of_endpoint bus_cfg; + struct device_node *ep; + struct property *prop; + __be32 *val; + uint32_t asize; + unsigned int i; + int rval; + + if (!dev->of_node) + return dev->platform_data; + + ep = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!ep) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + rval = -ENOMEM; + goto out_err; + } + + v4l2_of_parse_endpoint(ep, &bus_cfg); + + switch (bus_cfg.bus_type) { + case V4L2_MBUS_CSI2: + pdata->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; + break; + /* FIXME: add CCP2 support. */ + default: + rval = -EINVAL; + goto out_err; + } + + pdata->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + dev_dbg(dev, "lanes %u\n", pdata->lanes); + + /* xshutdown GPIO is optional */ + pdata->xshutdown = of_get_named_gpio(dev->of_node, "reset-gpios", 0); + + /* NVM size is not mandatory */ + of_property_read_u32(dev->of_node, "nokia,nvm-size", + &pdata->nvm_size); + + rval = of_property_read_u32(dev->of_node, "clock-frequency", + &pdata->ext_clk); + if (rval) { + dev_warn(dev, "can't get clock-frequency\n"); + goto out_err; + } + + dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown, + pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode); + + rval = of_get_property( + dev->of_node, "link-frequencies", &asize) ? 0 : -ENOENT; + if (rval) { + dev_warn(dev, "can't get link-frequencies array size\n"); + goto out_err; + } + + pdata->op_sys_clock = devm_kzalloc(dev, asize, GFP_KERNEL); + if (!pdata->op_sys_clock) { + rval = -ENOMEM; + goto out_err; + } + + asize /= sizeof(*pdata->op_sys_clock); + /* + * Read a 64-bit array --- this will be replaced with a + * of_property_read_u64_array() once it's merged. + */ + prop = of_find_property(dev->of_node, "link-frequencies", NULL); + if (!prop) + goto out_err; + if (!prop->value) + goto out_err; + if (asize * sizeof(*pdata->op_sys_clock) > prop->length) + goto out_err; + val = prop->value; + if (IS_ERR(val)) + goto out_err; + + for (i = 0; i < asize; i++) + pdata->op_sys_clock[i] = of_read_number(val + i * 2, 2); + + for (; asize > 0; asize--) + dev_dbg(dev, "freq %d: %lld\n", asize - 1, + pdata->op_sys_clock[asize - 1]); + + of_node_put(ep); + return pdata; + +out_err: + of_node_put(ep); + return NULL; +} + static int smiapp_probe(struct i2c_client *client, const struct i2c_device_id *devid) { struct smiapp_sensor *sensor; + struct smiapp_platform_data *pdata = smiapp_get_pdata(&client->dev); + int rval; - if (client->dev.platform_data == NULL) + if (pdata == NULL) return -ENODEV; sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); if (sensor == NULL) return -ENOMEM; - sensor->platform_data = client->dev.platform_data; + sensor->platform_data = pdata; mutex_init(&sensor->mutex); mutex_init(&sensor->power_mutex); sensor->src = &sensor->ssds[sensor->ssds_used]; @@ -2990,6 +3094,11 @@ static int smiapp_remove(struct i2c_client *client) return 0; } +static const struct of_device_id smiapp_of_table[] = { + { .compatible = "nokia,smia" }, + { }, +}; + static const struct i2c_device_id smiapp_id_table[] = { { SMIAPP_NAME, 0 }, { }, @@ -3003,6 +3112,7 @@ static const struct dev_pm_ops smiapp_pm_ops = { static struct i2c_driver smiapp_i2c_driver = { .driver = { + .of_match_table = smiapp_of_table, .name = SMIAPP_NAME, .pm = &smiapp_pm_ops, }, -- cgit v0.10.2 From 7095108b1674d3e0fd02b3fb51c9b302346c0260 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 14 Sep 2014 17:59:00 -0300 Subject: [media] smiapp: Split sub-device initialisation off from the registered callback The registered callback is called by the V4L2 async framework after the bound callback. This allows separating the functionality in the registered callback so that on DT based systems only sub-device registration is done there. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index a6bc5ef..7b13617 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2467,6 +2467,56 @@ static const struct v4l2_subdev_ops smiapp_ops; static const struct v4l2_subdev_internal_ops smiapp_internal_ops; static const struct media_entity_operations smiapp_entity_ops; +static int smiapp_register_subdevs(struct smiapp_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct smiapp_subdev *ssds[] = { + sensor->scaler, + sensor->binner, + sensor->pixel_array, + }; + unsigned int i; + int rval; + + for (i = 0; i < SMIAPP_SUBDEVS - 1; i++) { + struct smiapp_subdev *this = ssds[i + 1]; + struct smiapp_subdev *last = ssds[i]; + + if (!last) + continue; + + rval = media_entity_init(&this->sd.entity, + this->npads, this->pads, 0); + if (rval) { + dev_err(&client->dev, + "media_entity_init failed\n"); + return rval; + } + + rval = media_entity_create_link(&this->sd.entity, + this->source_pad, + &last->sd.entity, + last->sink_pad, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (rval) { + dev_err(&client->dev, + "media_entity_create_link failed\n"); + return rval; + } + + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, + &this->sd); + if (rval) { + dev_err(&client->dev, + "v4l2_device_register_subdev failed\n"); + return rval; + } + } + + return 0; +} + static int smiapp_registered(struct v4l2_subdev *subdev) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2705,37 +2755,13 @@ static int smiapp_registered(struct v4l2_subdev *subdev) this->sd.owner = THIS_MODULE; v4l2_set_subdevdata(&this->sd, client); - rval = media_entity_init(&this->sd.entity, - this->npads, this->pads, 0); - if (rval) { - dev_err(&client->dev, - "media_entity_init failed\n"); - goto out_nvm_release; - } - - rval = media_entity_create_link(&this->sd.entity, - this->source_pad, - &last->sd.entity, - last->sink_pad, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (rval) { - dev_err(&client->dev, - "media_entity_create_link failed\n"); - goto out_nvm_release; - } - - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &this->sd); - if (rval) { - dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); - goto out_nvm_release; - } - last = this; } + rval = smiapp_register_subdevs(sensor); + if (rval) + goto out_nvm_release; + dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; -- cgit v0.10.2 From 4c94468459884f10834b436620d2bd591c4cb105 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 14 Sep 2014 18:53:06 -0300 Subject: [media] smiapp: Fully probe the device in probe In the case of platform data, ISPs that provide clocks to the sensor must probe before the sensor does. Accessing the sensor does require the clocks, and thus, probe cannot access the sensor in such a system. This limitation does not exist in the case of the DT. Perform all initialisation except Media entity initialisation, link creation and sub-device registration in probe. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 7b13617..91ab71c 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2334,10 +2334,9 @@ static DEVICE_ATTR(ident, S_IRUGO, smiapp_sysfs_ident_read, NULL); * V4L2 subdev core operations */ -static int smiapp_identify_module(struct v4l2_subdev *subdev) +static int smiapp_identify_module(struct smiapp_sensor *sensor) { - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_module_info *minfo = &sensor->minfo; unsigned int i; int rval = 0; @@ -2517,10 +2516,17 @@ static int smiapp_register_subdevs(struct smiapp_sensor *sensor) return 0; } -static int smiapp_registered(struct v4l2_subdev *subdev) +static void smiapp_cleanup(struct smiapp_sensor *sensor) { - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + device_remove_file(&client->dev, &dev_attr_nvm); + device_remove_file(&client->dev, &dev_attr_ident); +} + +static int smiapp_init(struct smiapp_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_pll *pll = &sensor->pll; struct smiapp_subdev *last = NULL; u32 tmp; @@ -2566,7 +2572,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) if (rval) return -ENODEV; - rval = smiapp_identify_module(subdev); + rval = smiapp_identify_module(sensor); if (rval) { rval = -ENODEV; goto out_power_off; @@ -2646,13 +2652,13 @@ static int smiapp_registered(struct v4l2_subdev *subdev) if (sensor->nvm == NULL) { dev_err(&client->dev, "nvm buf allocation failed\n"); rval = -ENOMEM; - goto out_ident_release; + goto out_cleanup; } if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { dev_err(&client->dev, "sysfs nvm entry failed\n"); rval = -EBUSY; - goto out_ident_release; + goto out_cleanup; } } @@ -2696,7 +2702,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) rval = smiapp_get_mbus_formats(sensor); if (rval) { rval = -ENODEV; - goto out_nvm_release; + goto out_cleanup; } for (i = 0; i < SMIAPP_SUBDEVS; i++) { @@ -2758,10 +2764,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev) last = this; } - rval = smiapp_register_subdevs(sensor); - if (rval) - goto out_nvm_release; - dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; @@ -2770,14 +2772,14 @@ static int smiapp_registered(struct v4l2_subdev *subdev) smiapp_read_frame_fmt(sensor); rval = smiapp_init_controls(sensor); if (rval < 0) - goto out_nvm_release; + goto out_cleanup; mutex_lock(&sensor->mutex); rval = smiapp_update_mode(sensor); mutex_unlock(&sensor->mutex); if (rval) { dev_err(&client->dev, "update mode failed\n"); - goto out_nvm_release; + goto out_cleanup; } sensor->streaming = false; @@ -2787,23 +2789,39 @@ static int smiapp_registered(struct v4l2_subdev *subdev) rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp); sensor->flash_capability = tmp; if (rval) - goto out_nvm_release; + goto out_cleanup; smiapp_power_off(sensor); return 0; -out_nvm_release: - device_remove_file(&client->dev, &dev_attr_nvm); - -out_ident_release: - device_remove_file(&client->dev, &dev_attr_ident); +out_cleanup: + smiapp_cleanup(sensor); out_power_off: smiapp_power_off(sensor); return rval; } +static int smiapp_registered(struct v4l2_subdev *subdev) +{ + struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + int rval; + + if (!client->dev.of_node) { + rval = smiapp_init(sensor); + if (rval) + return rval; + } + + rval = smiapp_register_subdevs(sensor); + if (rval) + smiapp_cleanup(sensor); + + return rval; +} + static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct smiapp_subdev *ssd = to_smiapp_subdev(sd); @@ -3077,6 +3095,12 @@ static int smiapp_probe(struct i2c_client *client, if (rval < 0) return rval; + if (client->dev.of_node) { + rval = smiapp_init(sensor); + if (rval) + goto out_media_entity_cleanup; + } + rval = v4l2_async_register_subdev(&sensor->src->sd); if (rval < 0) goto out_media_entity_cleanup; -- cgit v0.10.2 From 0691b40e88350cbfa686ca25f98ab614f1919d73 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Oct 2014 11:21:52 -0300 Subject: [media] smiapp: Access flash capabilities through limits The flash capability register is already read as part of the limit registers. Do no access it separately; instead use the value from the limits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 91ab71c..22eddd6 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1483,7 +1483,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) if (rval < 0) goto out; - if ((sensor->flash_capability & + if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] & (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && sensor->platform_data->strobe_setup != NULL && @@ -2529,7 +2529,6 @@ static int smiapp_init(struct smiapp_sensor *sensor) struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_pll *pll = &sensor->pll; struct smiapp_subdev *last = NULL; - u32 tmp; unsigned int i; int rval; @@ -2785,12 +2784,6 @@ static int smiapp_init(struct smiapp_sensor *sensor) sensor->streaming = false; sensor->dev_init_done = true; - /* check flash capability */ - rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp); - sensor->flash_capability = tmp; - if (rval) - goto out_cleanup; - smiapp_power_off(sensor); return 0; diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 8fded46..ed010a8 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -216,7 +216,6 @@ struct smiapp_sensor { u8 scaling_mode; u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ - u8 flash_capability; u8 frame_skip; int power_count; -- cgit v0.10.2 From f7350a034af4531f6df7e66cd5661f0f9a0ec4d6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Oct 2014 11:20:37 -0300 Subject: [media] smiapp: Free control handlers in sub-device cleanup Also call smiapp_cleanup() in smiapp_remove(), replacing code that did the same than the function. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 22eddd6..d0a55fb 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2522,6 +2522,8 @@ static void smiapp_cleanup(struct smiapp_sensor *sensor) device_remove_file(&client->dev, &dev_attr_nvm); device_remove_file(&client->dev, &dev_attr_ident); + + smiapp_free_controls(sensor); } static int smiapp_init(struct smiapp_sensor *sensor) @@ -3124,15 +3126,11 @@ static int smiapp_remove(struct i2c_client *client) sensor->power_count = 0; } - device_remove_file(&client->dev, &dev_attr_ident); - if (sensor->nvm) - device_remove_file(&client->dev, &dev_attr_nvm); - for (i = 0; i < sensor->ssds_used; i++) { v4l2_device_unregister_subdev(&sensor->ssds[i].sd); media_entity_cleanup(&sensor->ssds[i].sd.entity); } - smiapp_free_controls(sensor); + smiapp_cleanup(sensor); return 0; } -- cgit v0.10.2 From 6208aebd33d341d5068ab0ccbff8035ff4034c08 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 9 Dec 2014 14:35:43 -0300 Subject: [media] smiapp: Clean up smiapp_init_controls() Clean up smiapp_init_controls() by adding newlines to appropriate places and by removing superfluous error handling. The caller will clean up control handlers in any case if the function fails. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index d0a55fb..8361070 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -527,6 +527,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); if (rval) return rval; + sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; sensor->analog_gain = v4l2_ctrl_new_std( @@ -585,8 +586,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) dev_err(&client->dev, "pixel array controls initialization failed (%d)\n", sensor->pixel_array->ctrl_handler.error); - rval = sensor->pixel_array->ctrl_handler.error; - goto error; + return sensor->pixel_array->ctrl_handler.error; } sensor->pixel_array->sd.ctrl_handler = @@ -596,7 +596,8 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); if (rval) - goto error; + return rval; + sensor->src->ctrl_handler.lock = &sensor->mutex; for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); @@ -614,20 +615,12 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) dev_err(&client->dev, "src controls initialization failed (%d)\n", sensor->src->ctrl_handler.error); - rval = sensor->src->ctrl_handler.error; - goto error; + return sensor->src->ctrl_handler.error; } - sensor->src->sd.ctrl_handler = - &sensor->src->ctrl_handler; + sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler; return 0; - -error: - v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler); - v4l2_ctrl_handler_free(&sensor->src->ctrl_handler); - - return rval; } static void smiapp_free_controls(struct smiapp_sensor *sensor) -- cgit v0.10.2 From 2e9f3c1c4443b2e46ef15e021cdf693b16c5231d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 9 Dec 2014 13:48:58 -0300 Subject: [media] smiapp: Separate late controls from the rest The default values and limits for certain controls need the knowledge of available media bus codes or link frequencies. Create such controls later on, so that most of the initialisation of the sensor has already been done when the init quirk is called. [mchehab@osg.samsung.com: make checkpatch.pl happier] Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 8361070..fb8f8a8 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -519,9 +519,6 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { static int smiapp_init_controls(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ - sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE]; - unsigned int max, i; int rval; rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); @@ -573,15 +570,6 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) ARRAY_SIZE(smiapp_test_patterns) - 1, 0, 0, smiapp_test_patterns); - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { - int max_value = (1 << sensor->csi_format->width) - 1; - sensor->test_data[i] = - v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, - &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, - 0, max_value, 1, max_value); - } - if (sensor->pixel_array->ctrl_handler.error) { dev_err(&client->dev, "pixel array controls initialization failed (%d)\n", @@ -600,13 +588,6 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) sensor->src->ctrl_handler.lock = &sensor->mutex; - for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); - - sensor->link_freq = v4l2_ctrl_new_int_menu( - &sensor->src->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), - __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock); - sensor->pixel_rate_csi = v4l2_ctrl_new_std( &sensor->src->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); @@ -623,6 +604,35 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) return 0; } +/* + * For controls that require information on available media bus codes + * and linke frequencies. + */ +static int smiapp_init_late_controls(struct smiapp_sensor *sensor) +{ + unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ + sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE]; + unsigned int max, i; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + + sensor->test_data[i] = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + + for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); + + sensor->link_freq = v4l2_ctrl_new_int_menu( + &sensor->src->ctrl_handler, &smiapp_ctrl_ops, + V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), + __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock); + + return sensor->src->ctrl_handler.error; +} + static void smiapp_free_controls(struct smiapp_sensor *sensor) { unsigned int i; @@ -2768,6 +2778,12 @@ static int smiapp_init(struct smiapp_sensor *sensor) if (rval < 0) goto out_cleanup; + rval = smiapp_init_late_controls(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + mutex_lock(&sensor->mutex); rval = smiapp_update_mode(sensor); mutex_unlock(&sensor->mutex); -- cgit v0.10.2 From 5313c00266700d231d9b386d9c0e4faad710c729 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 9 Dec 2014 14:22:31 -0300 Subject: [media] smiapp: Move enumerating available media bus codes later As the controls creation is separated in two sections, the available media bus codes and link frequencies can be enumerated later on. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index fb8f8a8..aa27a1b 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2703,12 +2703,6 @@ static int smiapp_init(struct smiapp_sensor *sensor) if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - rval = smiapp_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - for (i = 0; i < SMIAPP_SUBDEVS; i++) { struct { struct smiapp_subdev *ssd; @@ -2778,6 +2772,12 @@ static int smiapp_init(struct smiapp_sensor *sensor) if (rval < 0) goto out_cleanup; + rval = smiapp_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + rval = smiapp_init_late_controls(sensor); if (rval) { rval = -ENODEV; -- cgit v0.10.2 From 0d825a1226466512f44d4a81ce11ad15ca9334b0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Oct 2014 11:38:32 -0300 Subject: [media] smiapp: Replace pll_flags quirk with more generic init quirk The pll_flags quirk just returned the extra PLL flags the sensor required, but the init quirk is far more versatile. It can be used to perform any extra initialisation needed by the sensor, including allocating memory for sensor specific struct and creating sensor specific new controls. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index aa27a1b..b3c8125 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2697,7 +2697,6 @@ static int smiapp_init(struct smiapp_sensor *sensor) pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; pll->csi2.lanes = sensor->platform_data->lanes; pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; - pll->flags = smiapp_call_quirk(sensor, pll_flags); pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; /* Profile 0 sensors have no separate OP clock branch. */ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) @@ -2772,6 +2771,10 @@ static int smiapp_init(struct smiapp_sensor *sensor) if (rval < 0) goto out_cleanup; + rval = smiapp_call_quirk(sensor, init); + if (rval) + goto out_cleanup; + rval = smiapp_get_mbus_formats(sensor); if (rval) { rval = -ENODEV; diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index dd4ae6f..abf9ea7 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -214,9 +214,11 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) return smiapp_write_8(sensor, 0x3328, 0x80); } -static unsigned long jt8ev1_pll_flags(struct smiapp_sensor *sensor) +static int jt8ev1_init(struct smiapp_sensor *sensor) { - return SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + + return 0; } const struct smiapp_quirk smiapp_jt8ev1_quirk = { @@ -224,7 +226,7 @@ const struct smiapp_quirk smiapp_jt8ev1_quirk = { .post_poweron = jt8ev1_post_poweron, .pre_streamon = jt8ev1_pre_streamon, .post_streamoff = jt8ev1_post_streamoff, - .pll_flags = jt8ev1_pll_flags, + .init = jt8ev1_init, }; static int tcm8500md_limits(struct smiapp_sensor *sensor) diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index 3a3c3e5..a24eb43 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -29,6 +29,9 @@ struct smiapp_sensor; * @post_poweron: Called always after the sensor has been fully powered on. * @pre_streamon: Called just before streaming is enabled. * @post_streamon: Called right after stopping streaming. + * @pll_flags: Return flags for the PLL calculator. + * @init: Quirk initialisation, called the last in probe(). This is + * also appropriate for adding sensor specific controls, for instance. * @reg_access: Register access quirk. The quirk may divert the access * to another register, or no register at all. * @@ -47,6 +50,7 @@ struct smiapp_quirk { int (*pre_streamon)(struct smiapp_sensor *sensor); int (*post_streamoff)(struct smiapp_sensor *sensor); unsigned long (*pll_flags)(struct smiapp_sensor *sensor); + int (*init)(struct smiapp_sensor *sensor); int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg, u32 *val); unsigned long flags; -- cgit v0.10.2 From 3b1635e02e524e2cc7bded4b998d35074b68065e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 9 Dec 2014 18:43:16 -0300 Subject: [media] smiapp: Add parentheses to macro arguments used in macros This makes the macros a little bit safer. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index a24eb43..dac5566 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -72,14 +72,14 @@ void smiapp_replace_limit(struct smiapp_sensor *sensor, .val = _val, \ } -#define smiapp_call_quirk(_sensor, _quirk, ...) \ - (_sensor->minfo.quirk && \ - _sensor->minfo.quirk->_quirk ? \ - _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0) +#define smiapp_call_quirk(sensor, _quirk, ...) \ + ((sensor)->minfo.quirk && \ + (sensor)->minfo.quirk->_quirk ? \ + (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0) -#define smiapp_needs_quirk(_sensor, _quirk) \ - (_sensor->minfo.quirk ? \ - _sensor->minfo.quirk->flags & _quirk : 0) +#define smiapp_needs_quirk(sensor, _quirk) \ + ((sensor)->minfo.quirk ? \ + (sensor)->minfo.quirk->flags & _quirk : 0) extern const struct smiapp_quirk smiapp_jt8ev1_quirk; extern const struct smiapp_quirk smiapp_imx125es_quirk; -- cgit v0.10.2 From 417d2e507edcb5cf15eb344f86bd3dd28737f24e Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Tue, 9 Dec 2014 16:43:44 -0300 Subject: [media] media: platform: add VPFE capture driver support for AM437X This patch adds Video Processing Front End (VPFE) driver for AM437X family of devices Driver supports the following: - V4L2 API using MMAP buffer access based on videobuf2 api - Asynchronous sensor/decoder sub device registration - DT support Signed-off-by: Benoit Parrot Signed-off-by: Darren Etheridge Signed-off-by: Lad, Prabhakar [hans.verkuil@cisco.com: swapped two lines to fix vpfe_release() & add pinctrl include] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt b/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt new file mode 100644 index 0000000..3932e76 --- /dev/null +++ b/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt @@ -0,0 +1,61 @@ +Texas Instruments AM437x CAMERA (VPFE) +-------------------------------------- + +The Video Processing Front End (VPFE) is a key component for image capture +applications. The capture module provides the system interface and the +processing capability to connect RAW image-sensor modules and video decoders +to the AM437x device. + +Required properties: +- compatible: must be "ti,am437x-vpfe" +- reg: physical base address and length of the registers set for the device; +- interrupts: should contain IRQ line for the VPFE; +- ti,am437x-vpfe-interface: can be one of the following, + 0 - Raw Bayer Interface. + 1 - 8 Bit BT656 Interface. + 2 - 10 Bit BT656 Interface. + 3 - YCbCr 8 Bit Interface. + 4 - YCbCr 16 Bit Interface. + +VPFE supports a single port node with parallel bus. It should contain one +'port' child node with child 'endpoint' node. Please refer to the bindings +defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + vpfe: vpfe@f0034000 { + compatible = "ti,am437x-vpfe"; + reg = <0x48328000 0x2000>; + interrupts = ; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&vpfe_pins_default>; + pinctrl-1 = <&vpfe_pins_sleep>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + vpfe0_ep: endpoint { + remote-endpoint = <&ov2659_1>; + ti,am437x-vpfe-interface = <0>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; + + i2c1: i2c@4802a000 { + + ov2659@30 { + compatible = "ti,ov2659"; + reg = <0x30>; + + port { + ov2659_1: endpoint { + remote-endpoint = <&vpfe0_ep>; + bus-width = <8>; + mclk-frequency = <12000000>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index dc2d912..4318f34 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8745,6 +8745,15 @@ S: Maintained F: drivers/media/platform/davinci/ F: include/media/davinci/ +TI AM437X VPFE DRIVER +M: Lad, Prabhakar +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git +S: Maintained +F: drivers/media/platform/am437x/ + SIS 190 ETHERNET DRIVER M: Francois Romieu L: netdev@vger.kernel.org diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 480a174..71e8873 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -118,6 +118,7 @@ config VIDEO_S3C_CAMIF source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" +source "drivers/media/platform/am437x/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index a49936b..3ec1547 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -46,4 +46,6 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ obj-y += omap/ +obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ + ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig new file mode 100644 index 0000000..7b023a76 --- /dev/null +++ b/drivers/media/platform/am437x/Kconfig @@ -0,0 +1,11 @@ +config VIDEO_AM437X_VPFE + tristate "TI AM437x VPFE video capture driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on SOC_AM43XX || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + help + Support for AM437x Video Processing Front End based Video + Capture Driver. + + To compile this driver as a module, choose M here. The module + will be called am437x-vpfe. diff --git a/drivers/media/platform/am437x/Makefile b/drivers/media/platform/am437x/Makefile new file mode 100644 index 0000000..d11fff1 --- /dev/null +++ b/drivers/media/platform/am437x/Makefile @@ -0,0 +1,3 @@ +# Makefile for AM437x VPFE driver + +obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x-vpfe.o diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c new file mode 100644 index 0000000..e01ac22 --- /dev/null +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -0,0 +1,2778 @@ +/* + * TI VPFE capture Driver + * + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "am437x-vpfe.h" + +#define VPFE_MODULE_NAME "vpfe" +#define VPFE_VERSION "0.1.0" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-8"); + +#define vpfe_dbg(level, dev, fmt, arg...) \ + v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ##arg) +#define vpfe_info(dev, fmt, arg...) \ + v4l2_info(&dev->v4l2_dev, fmt, ##arg) +#define vpfe_err(dev, fmt, arg...) \ + v4l2_err(&dev->v4l2_dev, fmt, ##arg) + +/* standard information */ +struct vpfe_standard { + v4l2_std_id std_id; + unsigned int width; + unsigned int height; + struct v4l2_fract pixelaspect; + int frame_format; +}; + +const struct vpfe_standard vpfe_standards[] = { + {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, + {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, +}; + +struct bus_format { + unsigned int width; + unsigned int bpp; +}; + +/* + * struct vpfe_fmt - VPFE media bus format information + * @name: V4L2 format description + * @code: V4L2 media bus format code + * @shifted: V4L2 media bus format code for the same pixel layout but + * shifted to be 8 bits per pixel. =0 if format is not shiftable. + * @pixelformat: V4L2 pixel format FCC identifier + * @width: Bits per pixel (when transferred over a bus) + * @bpp: Bytes per pixel (when stored in memory) + * @supported: Indicates format supported by subdev + */ +struct vpfe_fmt { + const char *name; + u32 fourcc; + u32 code; + struct bus_format l; + struct bus_format s; + bool supported; + u32 index; +}; + +static struct vpfe_fmt formats[] = { + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "YUV 4:2:2 packed, CbYCrY", + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "YUV 4:2:2 packed, YCrYCb", + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "YUV 4:2:2 packed, CrYCbY", + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "RAW8 BGGR", + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RAW8 GBRG", + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RAW8 GRBG", + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RAW8 RGGB", + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RGB565 (LE)", + .fourcc = V4L2_PIX_FMT_RGB565, + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "RGB565 (BE)", + .fourcc = V4L2_PIX_FMT_RGB565X, + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, +}; + +static int +__vpfe_get_format(struct vpfe_device *vpfe, + struct v4l2_format *format, unsigned int *bpp); + +static struct vpfe_fmt *find_format_by_code(unsigned int code) +{ + struct vpfe_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->code == code) + return fmt; + } + + return NULL; +} + +static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat) +{ + struct vpfe_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->fourcc == pixelformat) + return fmt; + } + + return NULL; +} + +static void +mbus_to_pix(struct vpfe_device *vpfe, + const struct v4l2_mbus_framefmt *mbus, + struct v4l2_pix_format *pix, unsigned int *bpp) +{ + struct vpfe_subdev_info *sdinfo = vpfe->current_subdev; + unsigned int bus_width = sdinfo->vpfe_param.bus_width; + struct vpfe_fmt *fmt; + + fmt = find_format_by_code(mbus->code); + if (WARN_ON(fmt == NULL)) { + pr_err("Invalid mbus code set\n"); + *bpp = 1; + return; + } + + memset(pix, 0, sizeof(*pix)); + v4l2_fill_pix_format(pix, mbus); + pix->pixelformat = fmt->fourcc; + *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp; + + /* pitch should be 32 bytes aligned */ + pix->bytesperline = ALIGN(pix->width * *bpp, 32); + pix->sizeimage = pix->bytesperline * pix->height; +} + +static void pix_to_mbus(struct vpfe_device *vpfe, + struct v4l2_pix_format *pix_fmt, + struct v4l2_mbus_framefmt *mbus_fmt) +{ + struct vpfe_fmt *fmt; + + fmt = find_format_by_pix(pix_fmt->pixelformat); + if (!fmt) { + /* default to first entry */ + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", + pix_fmt->pixelformat); + fmt = &formats[0]; + } + + memset(mbus_fmt, 0, sizeof(*mbus_fmt)); + v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code); +} + +/* Print Four-character-code (FOURCC) */ +static char *print_fourcc(u32 fmt) +{ + static char code[5]; + + code[0] = (unsigned char)(fmt & 0xff); + code[1] = (unsigned char)((fmt >> 8) & 0xff); + code[2] = (unsigned char)((fmt >> 16) & 0xff); + code[3] = (unsigned char)((fmt >> 24) & 0xff); + code[4] = '\0'; + + return code; +} + +static int +cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs) +{ + return lhs->type == rhs->type && + lhs->fmt.pix.width == rhs->fmt.pix.width && + lhs->fmt.pix.height == rhs->fmt.pix.height && + lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat && + lhs->fmt.pix.field == rhs->fmt.pix.field && + lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace && + lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc && + lhs->fmt.pix.quantization == rhs->fmt.pix.quantization; +} + +static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset) +{ + return ioread32(ccdc->ccdc_cfg.base_addr + offset); +} + +static inline void vpfe_reg_write(struct vpfe_ccdc *ccdc, u32 val, u32 offset) +{ + iowrite32(val, ccdc->ccdc_cfg.base_addr + offset); +} + +static inline struct vpfe_device *to_vpfe(struct vpfe_ccdc *ccdc) +{ + return container_of(ccdc, struct vpfe_device, ccdc); +} + +static inline struct vpfe_cap_buffer *to_vpfe_buffer(struct vb2_buffer *vb) +{ + return container_of(vb, struct vpfe_cap_buffer, vb); +} + +static inline void vpfe_pcr_enable(struct vpfe_ccdc *ccdc, int flag) +{ + vpfe_reg_write(ccdc, !!flag, VPFE_PCR); +} + +static void vpfe_config_enable(struct vpfe_ccdc *ccdc, int flag) +{ + unsigned int cfg; + + if (!flag) { + cfg = vpfe_reg_read(ccdc, VPFE_CONFIG); + cfg &= ~(VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT); + } else { + cfg = VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT; + } + + vpfe_reg_write(ccdc, cfg, VPFE_CONFIG); +} + +static void vpfe_ccdc_setwin(struct vpfe_ccdc *ccdc, + struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, + int bpp) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int val, mid_img; + + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left * bpp; + horz_nr_pixels = (image_win->width * bpp) - 1; + vpfe_reg_write(ccdc, (horz_start << VPFE_HORZ_INFO_SPH_SHIFT) | + horz_nr_pixels, VPFE_HORZ_INFO); + + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* Since first line doesn't have any data */ + vert_start += 1; + /* configure VDINT0 */ + val = (vert_start << VPFE_VDINT_VDINT0_SHIFT); + } else { + /* Since first line doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* + * configure VDINT0 and VDINT1. VDINT1 will be at half + * of image height + */ + mid_img = vert_start + (image_win->height / 2); + val = (vert_start << VPFE_VDINT_VDINT0_SHIFT) | + (mid_img & VPFE_VDINT_VDINT1_MASK); + } + + vpfe_reg_write(ccdc, val, VPFE_VDINT); + + vpfe_reg_write(ccdc, (vert_start << VPFE_VERT_START_SLV0_SHIFT) | + vert_start, VPFE_VERT_START); + vpfe_reg_write(ccdc, vert_nr_lines, VPFE_VERT_LINES); +} + +static void vpfe_reg_dump(struct vpfe_ccdc *ccdc) +{ + struct vpfe_device *vpfe = to_vpfe(ccdc); + + vpfe_dbg(3, vpfe, "ALAW: 0x%x\n", vpfe_reg_read(ccdc, VPFE_ALAW)); + vpfe_dbg(3, vpfe, "CLAMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_CLAMP)); + vpfe_dbg(3, vpfe, "DCSUB: 0x%x\n", vpfe_reg_read(ccdc, VPFE_DCSUB)); + vpfe_dbg(3, vpfe, "BLKCMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_BLKCMP)); + vpfe_dbg(3, vpfe, "COLPTN: 0x%x\n", vpfe_reg_read(ccdc, VPFE_COLPTN)); + vpfe_dbg(3, vpfe, "SDOFST: 0x%x\n", vpfe_reg_read(ccdc, VPFE_SDOFST)); + vpfe_dbg(3, vpfe, "SYN_MODE: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_SYNMODE)); + vpfe_dbg(3, vpfe, "HSIZE_OFF: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_HSIZE_OFF)); + vpfe_dbg(3, vpfe, "HORZ_INFO: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_HORZ_INFO)); + vpfe_dbg(3, vpfe, "VERT_START: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_VERT_START)); + vpfe_dbg(3, vpfe, "VERT_LINES: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_VERT_LINES)); +} + +static int +vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_config_params_raw *ccdcparam) +{ + struct vpfe_device *vpfe = to_vpfe(ccdc); + u8 max_gamma, max_data; + + if (!ccdcparam->alaw.enable) + return 0; + + max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd); + max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); + + if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 || + ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 || + max_gamma > max_data) { + vpfe_dbg(1, vpfe, "Invalid data line select\n"); + return -EINVAL; + } + + return 0; +} + +static void +vpfe_ccdc_update_raw_params(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_config_params_raw *raw_params) +{ + struct vpfe_ccdc_config_params_raw *config_params = + &ccdc->ccdc_cfg.bayer.config_params; + + config_params = raw_params; +} + +/* + * vpfe_ccdc_restore_defaults() + * This function will write defaults to all CCDC registers + */ +static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc) +{ + int i; + + /* Disable CCDC */ + vpfe_pcr_enable(ccdc, 0); + + /* set all registers to default value */ + for (i = 4; i <= 0x94; i += 4) + vpfe_reg_write(ccdc, 0, i); + + vpfe_reg_write(ccdc, VPFE_NO_CULLING, VPFE_CULLING); + vpfe_reg_write(ccdc, VPFE_CCDC_GAMMA_BITS_11_2, VPFE_ALAW); +} + +static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) +{ + int dma_cntl, i, pcr; + + /* If the CCDC module is still busy wait for it to be done */ + for (i = 0; i < 10; i++) { + usleep_range(5000, 6000); + pcr = vpfe_reg_read(ccdc, VPFE_PCR); + if (!pcr) + break; + + /* make sure it it is disabled */ + vpfe_pcr_enable(ccdc, 0); + } + + /* Disable CCDC by resetting all register to default POR values */ + vpfe_ccdc_restore_defaults(ccdc); + + /* if DMA_CNTL overflow bit is set. Clear it + * It appears to take a while for this to become quiescent ~20ms + */ + for (i = 0; i < 10; i++) { + dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); + if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) + break; + + /* Clear the overflow bit */ + vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL); + usleep_range(5000, 6000); + } + + /* Disabled the module at the CONFIG level */ + vpfe_config_enable(ccdc, 0); + + pm_runtime_put_sync(dev); + + return 0; +} + +static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + struct vpfe_ccdc_config_params_raw raw_params; + int x; + + if (ccdc->ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + x = copy_from_user(&raw_params, params, sizeof(raw_params)); + if (x) { + vpfe_dbg(1, vpfe, + "vpfe_ccdc_set_params: error in copying ccdc params, %d\n", + x); + return -EFAULT; + } + + if (!vpfe_ccdc_validate_param(ccdc, &raw_params)) { + vpfe_ccdc_update_raw_params(ccdc, &raw_params); + return 0; + } + + return -EINVAL; +} + +/* + * vpfe_ccdc_config_ycbcr() + * This function will configure CCDC for YCbCr video capture + */ +static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr; + u32 syn_mode; + + vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n"); + /* + * first restore the CCDC registers to default values + * This is important since we assume default values to be set in + * a lot of registers that we didn't touch + */ + vpfe_ccdc_restore_defaults(ccdc); + + /* + * configure pixel format, frame format, configure video frame + * format, enable output to SDRAM, enable internal timing generator + * and 8bit pack mode + */ + syn_mode = (((params->pix_fmt & VPFE_SYN_MODE_INPMOD_MASK) << + VPFE_SYN_MODE_INPMOD_SHIFT) | + ((params->frm_fmt & VPFE_SYN_FLDMODE_MASK) << + VPFE_SYN_FLDMODE_SHIFT) | VPFE_VDHDEN_ENABLE | + VPFE_WEN_ENABLE | VPFE_DATA_PACK_ENABLE); + + /* setup BT.656 sync mode */ + if (params->bt656_enable) { + vpfe_reg_write(ccdc, VPFE_REC656IF_BT656_EN, VPFE_REC656IF); + + /* + * configure the FID, VD, HD pin polarity, + * fld,hd pol positive, vd negative, 8-bit data + */ + syn_mode |= VPFE_SYN_MODE_VD_POL_NEGATIVE; + if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT) + syn_mode |= VPFE_SYN_MODE_10BITS; + else + syn_mode |= VPFE_SYN_MODE_8BITS; + } else { + /* y/c external sync mode */ + syn_mode |= (((params->fid_pol & VPFE_FID_POL_MASK) << + VPFE_FID_POL_SHIFT) | + ((params->hd_pol & VPFE_HD_POL_MASK) << + VPFE_HD_POL_SHIFT) | + ((params->vd_pol & VPFE_VD_POL_MASK) << + VPFE_VD_POL_SHIFT)); + } + vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE); + + /* configure video window */ + vpfe_ccdc_setwin(ccdc, ¶ms->win, + params->frm_fmt, params->bytesperpixel); + + /* + * configure the order of y cb cr in SDRAM, and disable latch + * internal register on vsync + */ + if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT) + vpfe_reg_write(ccdc, + (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) | + VPFE_LATCH_ON_VSYNC_DISABLE | + VPFE_CCDCFG_BW656_10BIT, VPFE_CCDCFG); + else + vpfe_reg_write(ccdc, + (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) | + VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG); + + /* + * configure the horizontal line offset. This should be a + * on 32 byte boundary. So clear LSB 5 bits + */ + vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF); + + /* configure the memory line offset */ + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) + /* two fields are interleaved in memory */ + vpfe_reg_write(ccdc, VPFE_SDOFST_FIELD_INTERLEAVED, + VPFE_SDOFST); +} + +static void +vpfe_ccdc_config_black_clamp(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_black_clamp *bclamp) +{ + u32 val; + + if (!bclamp->enable) { + /* configure DCSub */ + val = (bclamp->dc_sub) & VPFE_BLK_DC_SUB_MASK; + vpfe_reg_write(ccdc, val, VPFE_DCSUB); + vpfe_reg_write(ccdc, VPFE_CLAMP_DEFAULT_VAL, VPFE_CLAMP); + return; + } + /* + * Configure gain, Start pixel, No of line to be avg, + * No of pixel/line to be avg, & Enable the Black clamping + */ + val = ((bclamp->sgain & VPFE_BLK_SGAIN_MASK) | + ((bclamp->start_pixel & VPFE_BLK_ST_PXL_MASK) << + VPFE_BLK_ST_PXL_SHIFT) | + ((bclamp->sample_ln & VPFE_BLK_SAMPLE_LINE_MASK) << + VPFE_BLK_SAMPLE_LINE_SHIFT) | + ((bclamp->sample_pixel & VPFE_BLK_SAMPLE_LN_MASK) << + VPFE_BLK_SAMPLE_LN_SHIFT) | VPFE_BLK_CLAMP_ENABLE); + vpfe_reg_write(ccdc, val, VPFE_CLAMP); + /* If Black clamping is enable then make dcsub 0 */ + vpfe_reg_write(ccdc, VPFE_DCSUB_DEFAULT_VAL, VPFE_DCSUB); +} + +static void +vpfe_ccdc_config_black_compense(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_black_compensation *bcomp) +{ + u32 val; + + val = ((bcomp->b & VPFE_BLK_COMP_MASK) | + ((bcomp->gb & VPFE_BLK_COMP_MASK) << + VPFE_BLK_COMP_GB_COMP_SHIFT) | + ((bcomp->gr & VPFE_BLK_COMP_MASK) << + VPFE_BLK_COMP_GR_COMP_SHIFT) | + ((bcomp->r & VPFE_BLK_COMP_MASK) << + VPFE_BLK_COMP_R_COMP_SHIFT)); + vpfe_reg_write(ccdc, val, VPFE_BLKCMP); +} + +/* + * vpfe_ccdc_config_raw() + * This function will configure CCDC for Raw capture mode + */ +static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + struct vpfe_ccdc_config_params_raw *config_params = + &ccdc->ccdc_cfg.bayer.config_params; + struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer; + unsigned int syn_mode; + unsigned int val; + + vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n"); + + /* Reset CCDC */ + vpfe_ccdc_restore_defaults(ccdc); + + /* Disable latching function registers on VSYNC */ + vpfe_reg_write(ccdc, VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG); + + /* + * Configure the vertical sync polarity(SYN_MODE.VDPOL), + * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity + * (SYN_MODE.FLDPOL), frame format(progressive or interlace), + * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output + * SDRAM, enable internal timing generator + */ + syn_mode = (((params->vd_pol & VPFE_VD_POL_MASK) << VPFE_VD_POL_SHIFT) | + ((params->hd_pol & VPFE_HD_POL_MASK) << VPFE_HD_POL_SHIFT) | + ((params->fid_pol & VPFE_FID_POL_MASK) << + VPFE_FID_POL_SHIFT) | ((params->frm_fmt & + VPFE_FRM_FMT_MASK) << VPFE_FRM_FMT_SHIFT) | + ((config_params->data_sz & VPFE_DATA_SZ_MASK) << + VPFE_DATA_SZ_SHIFT) | ((params->pix_fmt & + VPFE_PIX_FMT_MASK) << VPFE_PIX_FMT_SHIFT) | + VPFE_WEN_ENABLE | VPFE_VDHDEN_ENABLE); + + /* Enable and configure aLaw register if needed */ + if (config_params->alaw.enable) { + val = ((config_params->alaw.gamma_wd & + VPFE_ALAW_GAMMA_WD_MASK) | VPFE_ALAW_ENABLE); + vpfe_reg_write(ccdc, val, VPFE_ALAW); + vpfe_dbg(3, vpfe, "\nWriting 0x%x to ALAW...\n", val); + } + + /* Configure video window */ + vpfe_ccdc_setwin(ccdc, ¶ms->win, params->frm_fmt, + params->bytesperpixel); + + /* Configure Black Clamp */ + vpfe_ccdc_config_black_clamp(ccdc, &config_params->blk_clamp); + + /* Configure Black level compensation */ + vpfe_ccdc_config_black_compense(ccdc, &config_params->blk_comp); + + /* If data size is 8 bit then pack the data */ + if ((config_params->data_sz == VPFE_CCDC_DATA_8BITS) || + config_params->alaw.enable) + syn_mode |= VPFE_DATA_PACK_ENABLE; + + /* + * Configure Horizontal offset register. If pack 8 is enabled then + * 1 pixel will take 1 byte + */ + vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF); + + vpfe_dbg(3, vpfe, "Writing %d (%x) to HSIZE_OFF\n", + params->bytesperline, params->bytesperline); + + /* Set value for SDOFST */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_enable) { + /* For interlace inverse mode */ + vpfe_reg_write(ccdc, VPFE_INTERLACED_IMAGE_INVERT, + VPFE_SDOFST); + } else { + /* For interlace non inverse mode */ + vpfe_reg_write(ccdc, VPFE_INTERLACED_NO_IMAGE_INVERT, + VPFE_SDOFST); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + vpfe_reg_write(ccdc, VPFE_PROGRESSIVE_NO_IMAGE_INVERT, + VPFE_SDOFST); + } + + vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE); + + vpfe_reg_dump(ccdc); +} + +static inline int +vpfe_ccdc_set_buftype(struct vpfe_ccdc *ccdc, + enum ccdc_buftype buf_type) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc->ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc->ccdc_cfg.ycbcr.buf_type = buf_type; + + return 0; +} + +static inline enum ccdc_buftype vpfe_ccdc_get_buftype(struct vpfe_ccdc *ccdc) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc->ccdc_cfg.bayer.buf_type; + + return ccdc->ccdc_cfg.ycbcr.buf_type; +} + +static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + + vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n", + ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); + + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + /* + * Need to clear it in case it was left on + * after the last capture. + */ + ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 0; + + switch (pixfmt) { + case V4L2_PIX_FMT_SBGGR8: + ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 1; + break; + + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_RGB565X: + break; + + case V4L2_PIX_FMT_SBGGR16: + default: + return -EINVAL; + } + } else { + switch (pixfmt) { + case V4L2_PIX_FMT_YUYV: + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + break; + + case V4L2_PIX_FMT_UYVY: + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + + default: + return -EINVAL; + } + } + + return 0; +} + +static u32 vpfe_ccdc_get_pixel_format(struct vpfe_ccdc *ccdc) +{ + u32 pixfmt; + + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { + pixfmt = V4L2_PIX_FMT_YUYV; + } else { + if (ccdc->ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + + return pixfmt; +} + +static int +vpfe_ccdc_set_image_window(struct vpfe_ccdc *ccdc, + struct v4l2_rect *win, unsigned int bpp) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc->ccdc_cfg.bayer.win = *win; + ccdc->ccdc_cfg.bayer.bytesperpixel = bpp; + ccdc->ccdc_cfg.bayer.bytesperline = ALIGN(win->width * bpp, 32); + } else { + ccdc->ccdc_cfg.ycbcr.win = *win; + ccdc->ccdc_cfg.ycbcr.bytesperpixel = bpp; + ccdc->ccdc_cfg.ycbcr.bytesperline = ALIGN(win->width * bpp, 32); + } + + return 0; +} + +static inline void +vpfe_ccdc_get_image_window(struct vpfe_ccdc *ccdc, + struct v4l2_rect *win) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc->ccdc_cfg.bayer.win; + else + *win = ccdc->ccdc_cfg.ycbcr.win; +} + +static inline unsigned int vpfe_ccdc_get_line_length(struct vpfe_ccdc *ccdc) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc->ccdc_cfg.bayer.bytesperline; + + return ccdc->ccdc_cfg.ycbcr.bytesperline; +} + +static inline int +vpfe_ccdc_set_frame_format(struct vpfe_ccdc *ccdc, + enum ccdc_frmfmt frm_fmt) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc->ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc->ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + + return 0; +} + +static inline enum ccdc_frmfmt +vpfe_ccdc_get_frame_format(struct vpfe_ccdc *ccdc) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc->ccdc_cfg.bayer.frm_fmt; + + return ccdc->ccdc_cfg.ycbcr.frm_fmt; +} + +static inline int vpfe_ccdc_getfid(struct vpfe_ccdc *ccdc) +{ + return (vpfe_reg_read(ccdc, VPFE_SYNMODE) >> 15) & 1; +} + +static inline void vpfe_set_sdr_addr(struct vpfe_ccdc *ccdc, unsigned long addr) +{ + vpfe_reg_write(ccdc, addr & 0xffffffe0, VPFE_SDR_ADDR); +} + +static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc, + struct vpfe_hw_if_param *params) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + + ccdc->ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_YCBCR_SYNC_16: + case VPFE_YCBCR_SYNC_8: + case VPFE_BT656_10BIT: + ccdc->ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc->ccdc_cfg.ycbcr.hd_pol = params->hdpol; + break; + + case VPFE_RAW_BAYER: + ccdc->ccdc_cfg.bayer.vd_pol = params->vdpol; + ccdc->ccdc_cfg.bayer.hd_pol = params->hdpol; + if (params->bus_width == 10) + ccdc->ccdc_cfg.bayer.config_params.data_sz = + VPFE_CCDC_DATA_10BITS; + else + ccdc->ccdc_cfg.bayer.config_params.data_sz = + VPFE_CCDC_DATA_8BITS; + vpfe_dbg(1, vpfe, "params.bus_width: %d\n", + params->bus_width); + vpfe_dbg(1, vpfe, "config_params.data_sz: %d\n", + ccdc->ccdc_cfg.bayer.config_params.data_sz); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static void vpfe_clear_intr(struct vpfe_ccdc *ccdc, int vdint) +{ + unsigned int vpfe_int_status; + + vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS); + + switch (vdint) { + /* VD0 interrupt */ + case VPFE_VDINT0: + vpfe_int_status &= ~VPFE_VDINT0; + vpfe_int_status |= VPFE_VDINT0; + break; + + /* VD1 interrupt */ + case VPFE_VDINT1: + vpfe_int_status &= ~VPFE_VDINT1; + vpfe_int_status |= VPFE_VDINT1; + break; + + /* VD2 interrupt */ + case VPFE_VDINT2: + vpfe_int_status &= ~VPFE_VDINT2; + vpfe_int_status |= VPFE_VDINT2; + break; + + /* Clear all interrupts */ + default: + vpfe_int_status &= ~(VPFE_VDINT0 | + VPFE_VDINT1 | + VPFE_VDINT2); + vpfe_int_status |= (VPFE_VDINT0 | + VPFE_VDINT1 | + VPFE_VDINT2); + break; + } + /* Clear specific VDINT from the status register */ + vpfe_reg_write(ccdc, vpfe_int_status, VPFE_IRQ_STS); + + vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS); + + /* Acknowledge that we are done with all interrupts */ + vpfe_reg_write(ccdc, 1, VPFE_IRQ_EOI); +} + +static void vpfe_ccdc_config_defaults(struct vpfe_ccdc *ccdc) +{ + ccdc->ccdc_cfg.if_type = VPFE_RAW_BAYER; + + ccdc->ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; + ccdc->ccdc_cfg.ycbcr.frm_fmt = CCDC_FRMFMT_INTERLACED; + ccdc->ccdc_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + ccdc->ccdc_cfg.ycbcr.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED; + + ccdc->ccdc_cfg.ycbcr.win.left = 0; + ccdc->ccdc_cfg.ycbcr.win.top = 0; + ccdc->ccdc_cfg.ycbcr.win.width = 720; + ccdc->ccdc_cfg.ycbcr.win.height = 576; + ccdc->ccdc_cfg.ycbcr.bt656_enable = 1; + + ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + ccdc->ccdc_cfg.bayer.frm_fmt = CCDC_FRMFMT_PROGRESSIVE; + ccdc->ccdc_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE; + + ccdc->ccdc_cfg.bayer.win.left = 0; + ccdc->ccdc_cfg.bayer.win.top = 0; + ccdc->ccdc_cfg.bayer.win.width = 800; + ccdc->ccdc_cfg.bayer.win.height = 600; + ccdc->ccdc_cfg.bayer.config_params.data_sz = VPFE_CCDC_DATA_8BITS; + ccdc->ccdc_cfg.bayer.config_params.alaw.gamma_wd = + VPFE_CCDC_GAMMA_BITS_09_0; +} + +/* + * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings + */ +static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe, + struct v4l2_format *f) +{ + struct v4l2_rect image_win; + enum ccdc_buftype buf_type; + enum ccdc_frmfmt frm_fmt; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); + f->fmt.pix.width = image_win.width; + f->fmt.pix.height = image_win.height; + f->fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; + buf_type = vpfe_ccdc_get_buftype(&vpfe->ccdc); + f->fmt.pix.pixelformat = vpfe_ccdc_get_pixel_format(&vpfe->ccdc); + frm_fmt = vpfe_ccdc_get_frame_format(&vpfe->ccdc); + + if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + f->fmt.pix.field = V4L2_FIELD_NONE; + } else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + } else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) { + f->fmt.pix.field = V4L2_FIELD_SEQ_TB; + } else { + vpfe_err(vpfe, "Invalid buf_type\n"); + return -EINVAL; + } + } else { + vpfe_err(vpfe, "Invalid frm_fmt\n"); + return -EINVAL; + } + return 0; +} + +static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) +{ + enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); + + vpfe_dbg(1, vpfe, "pixelformat: %s\n", + print_fourcc(vpfe->fmt.fmt.pix.pixelformat)); + + if (vpfe_ccdc_set_pixel_format(&vpfe->ccdc, + vpfe->fmt.fmt.pix.pixelformat) < 0) { + vpfe_err(vpfe, "couldn't set pix format in ccdc\n"); + return -EINVAL; + } + + /* configure the image window */ + vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp); + + switch (vpfe->fmt.fmt.pix.field) { + case V4L2_FIELD_INTERLACED: + /* do nothing, since it is default */ + ret = vpfe_ccdc_set_buftype( + &vpfe->ccdc, + CCDC_BUFTYPE_FLD_INTERLEAVED); + break; + + case V4L2_FIELD_NONE: + frm_fmt = CCDC_FRMFMT_PROGRESSIVE; + /* buffer type only applicable for interlaced scan */ + break; + + case V4L2_FIELD_SEQ_TB: + ret = vpfe_ccdc_set_buftype( + &vpfe->ccdc, + CCDC_BUFTYPE_FLD_SEPARATED); + break; + + default: + return -EINVAL; + } + + if (ret) + return ret; + + return vpfe_ccdc_set_frame_format(&vpfe->ccdc, frm_fmt); +} + +/* + * vpfe_config_image_format() + * For a given standard, this functions sets up the default + * pix format & crop values in the vpfe device and ccdc. It first + * starts with defaults based values from the standard table. + * It then checks if sub device support g_mbus_fmt and then override the + * values based on that.Sets crop values to match with scan resolution + * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the + * values in ccdc + */ +static int vpfe_config_image_format(struct vpfe_device *vpfe, + v4l2_std_id std_id) +{ + struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { + if (vpfe_standards[i].std_id & std_id) { + vpfe->std_info.active_pixels = + vpfe_standards[i].width; + vpfe->std_info.active_lines = + vpfe_standards[i].height; + vpfe->std_info.frame_format = + vpfe_standards[i].frame_format; + vpfe->std_index = i; + + break; + } + } + + if (i == ARRAY_SIZE(vpfe_standards)) { + vpfe_err(vpfe, "standard not supported\n"); + return -EINVAL; + } + + vpfe->crop.top = vpfe->crop.left = 0; + vpfe->crop.width = vpfe->std_info.active_pixels; + vpfe->crop.height = vpfe->std_info.active_lines; + pix->width = vpfe->crop.width; + pix->height = vpfe->crop.height; + pix->pixelformat = V4L2_PIX_FMT_YUYV; + + /* first field and frame format based on standard frame format */ + if (vpfe->std_info.frame_format) + pix->field = V4L2_FIELD_INTERLACED; + else + pix->field = V4L2_FIELD_NONE; + + ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp); + if (ret) + return ret; + + /* Update the crop window based on found values */ + vpfe->crop.width = pix->width; + vpfe->crop.height = pix->height; + + return vpfe_config_ccdc_image_format(vpfe); +} + +static int vpfe_initialize_device(struct vpfe_device *vpfe) +{ + struct vpfe_subdev_info *sdinfo; + int ret; + + sdinfo = &vpfe->cfg->sub_devs[0]; + sdinfo->sd = vpfe->sd[0]; + vpfe->current_input = 0; + vpfe->std_index = 0; + /* Configure the default format information */ + ret = vpfe_config_image_format(vpfe, + vpfe_standards[vpfe->std_index].std_id); + if (ret) + return ret; + + pm_runtime_get_sync(vpfe->pdev); + + vpfe_config_enable(&vpfe->ccdc, 1); + + vpfe_ccdc_restore_defaults(&vpfe->ccdc); + + /* Clear all VPFE interrupts */ + vpfe_clear_intr(&vpfe->ccdc, -1); + + return ret; +} + +/* + * vpfe_release : This function is based on the vb2_fop_release + * helper function. + * It has been augmented to handle module power management, + * by disabling/enabling h/w module fcntl clock when necessary. + */ +static int vpfe_release(struct file *file) +{ + struct vpfe_device *vpfe = video_drvdata(file); + int ret; + + mutex_lock(&vpfe->lock); + + if (v4l2_fh_is_singular_file(file)) + vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); + ret = _vb2_fop_release(file, NULL); + + mutex_unlock(&vpfe->lock); + + return ret; +} + +/* + * vpfe_open : This function is based on the v4l2_fh_open helper function. + * It has been augmented to handle module power management, + * by disabling/enabling h/w module fcntl clock when necessary. + */ +static int vpfe_open(struct file *file) +{ + struct vpfe_device *vpfe = video_drvdata(file); + int ret; + + mutex_lock(&vpfe->lock); + + ret = v4l2_fh_open(file); + if (ret) { + vpfe_err(vpfe, "v4l2_fh_open failed\n"); + goto unlock; + } + + if (!v4l2_fh_is_singular_file(file)) + goto unlock; + + if (vpfe_initialize_device(vpfe)) { + v4l2_fh_release(file); + ret = -ENODEV; + } + +unlock: + mutex_unlock(&vpfe->lock); + return ret; +} + +/** + * vpfe_schedule_next_buffer: set next buffer address for capture + * @vpfe : ptr to vpfe device + * + * This function will get next buffer from the dma queue and + * set the buffer address in the vpfe register for capture. + * the buffer is marked active + * + * Assumes caller is holding vpfe->dma_queue_lock already + */ +static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) +{ + vpfe->next_frm = list_entry(vpfe->dma_queue.next, + struct vpfe_cap_buffer, list); + list_del(&vpfe->next_frm->list); + + vpfe_set_sdr_addr(&vpfe->ccdc, + vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0)); +} + +static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe) +{ + unsigned long addr; + + addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0) + + vpfe->field_off; + + vpfe_set_sdr_addr(&vpfe->ccdc, addr); +} + +/* + * vpfe_process_buffer_complete: process a completed buffer + * @vpfe : ptr to vpfe device + * + * This function time stamp the buffer and mark it as DONE. It also + * wake up any process waiting on the QUEUE and set the next buffer + * as current + */ +static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe) +{ + v4l2_get_timestamp(&vpfe->cur_frm->vb.v4l2_buf.timestamp); + vpfe->cur_frm->vb.v4l2_buf.field = vpfe->fmt.fmt.pix.field; + vpfe->cur_frm->vb.v4l2_buf.sequence = vpfe->sequence++; + vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_DONE); + vpfe->cur_frm = vpfe->next_frm; +} + +/* + * vpfe_isr : ISR handler for vpfe capture (VINT0) + * @irq: irq number + * @dev_id: dev_id ptr + * + * It changes status of the captured buffer, takes next buffer from the queue + * and sets its address in VPFE registers + */ +static irqreturn_t vpfe_isr(int irq, void *dev) +{ + struct vpfe_device *vpfe = (struct vpfe_device *)dev; + enum v4l2_field field; + int intr_status; + int fid; + + intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS); + + if (intr_status & VPFE_VDINT0) { + field = vpfe->fmt.fmt.pix.field; + + if (field == V4L2_FIELD_NONE) { + /* handle progressive frame capture */ + if (vpfe->cur_frm != vpfe->next_frm) + vpfe_process_buffer_complete(vpfe); + goto next_intr; + } + + /* interlaced or TB capture check which field + we are in hardware */ + fid = vpfe_ccdc_getfid(&vpfe->ccdc); + + /* switch the software maintained field id */ + vpfe->field ^= 1; + if (fid == vpfe->field) { + /* we are in-sync here,continue */ + if (fid == 0) { + /* + * One frame is just being captured. If the + * next frame is available, release the + * current frame and move on + */ + if (vpfe->cur_frm != vpfe->next_frm) + vpfe_process_buffer_complete(vpfe); + /* + * based on whether the two fields are stored + * interleave or separately in memory, + * reconfigure the CCDC memory address + */ + if (field == V4L2_FIELD_SEQ_TB) + vpfe_schedule_bottom_field(vpfe); + + goto next_intr; + } + /* + * if one field is just being captured configure + * the next frame get the next frame from the empty + * queue if no frame is available hold on to the + * current buffer + */ + spin_lock(&vpfe->dma_queue_lock); + if (!list_empty(&vpfe->dma_queue) && + vpfe->cur_frm == vpfe->next_frm) + vpfe_schedule_next_buffer(vpfe); + spin_unlock(&vpfe->dma_queue_lock); + } else if (fid == 0) { + /* + * out of sync. Recover from any hardware out-of-sync. + * May loose one frame + */ + vpfe->field = fid; + } + } + +next_intr: + if (intr_status & VPFE_VDINT1) { + spin_lock(&vpfe->dma_queue_lock); + if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE && + !list_empty(&vpfe->dma_queue) && + vpfe->cur_frm == vpfe->next_frm) + vpfe_schedule_next_buffer(vpfe); + spin_unlock(&vpfe->dma_queue_lock); + } + + vpfe_clear_intr(&vpfe->ccdc, intr_status); + + return IRQ_HANDLED; +} + +static inline void vpfe_detach_irq(struct vpfe_device *vpfe) +{ + unsigned int intr = VPFE_VDINT0; + enum ccdc_frmfmt frame_format; + + frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) + intr |= VPFE_VDINT1; + + vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_CLR); +} + +static inline void vpfe_attach_irq(struct vpfe_device *vpfe) +{ + unsigned int intr = VPFE_VDINT0; + enum ccdc_frmfmt frame_format; + + frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) + intr |= VPFE_VDINT1; + + vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_SET); +} + +static int vpfe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_querycap\n"); + + strlcpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); + strlcpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", vpfe->v4l2_dev.name); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +/* get the format set at output pad of the adjacent subdev */ +static int __vpfe_get_format(struct vpfe_device *vpfe, + struct v4l2_format *format, unsigned int *bpp) +{ + struct v4l2_mbus_framefmt mbus_fmt; + struct vpfe_subdev_info *sdinfo; + struct v4l2_subdev_format fmt; + int ret; + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.pad = 0; + + ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + if (!ret) { + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); + } else { + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, + sdinfo->grp_id, + video, g_mbus_fmt, + &mbus_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); + mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); + } + + format->type = vpfe->fmt.type; + + vpfe_dbg(1, vpfe, + "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", + __func__, format->fmt.pix.width, format->fmt.pix.height, + print_fourcc(format->fmt.pix.pixelformat), + format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); + + return 0; +} + +/* set the format at output pad of the adjacent subdev */ +static int __vpfe_set_format(struct vpfe_device *vpfe, + struct v4l2_format *format, unsigned int *bpp) +{ + struct v4l2_mbus_framefmt mbus_fmt; + struct vpfe_subdev_info *sdinfo; + struct v4l2_subdev_format fmt; + int ret; + + vpfe_dbg(2, vpfe, "__vpfe_set_format\n"); + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.pad = 0; + + pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); + + ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + if (!ret) { + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); + } else { + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, + sdinfo->grp_id, + video, s_mbus_fmt, + &mbus_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); + mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); + } + + format->type = vpfe->fmt.type; + + vpfe_dbg(1, vpfe, + "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", + __func__, format->fmt.pix.width, format->fmt.pix.height, + print_fourcc(format->fmt.pix.pixelformat), + format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); + + return 0; +} + +static int vpfe_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_g_fmt\n"); + + *fmt = vpfe->fmt; + + return 0; +} + +static int vpfe_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + struct vpfe_fmt *fmt = NULL; + unsigned int k; + + vpfe_dbg(2, vpfe, "vpfe_enum_format index:%d\n", + f->index); + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + if (f->index > ARRAY_SIZE(formats)) + return -EINVAL; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + if (formats[k].index == f->index) { + fmt = &formats[k]; + break; + } + } + if (!fmt) + return -EINVAL; + + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + f->pixelformat = fmt->fourcc; + f->type = vpfe->fmt.type; + + vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n", + f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name); + + return 0; +} + +static int vpfe_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe = video_drvdata(file); + unsigned int bpp; + + vpfe_dbg(2, vpfe, "vpfe_try_fmt\n"); + + return __vpfe_get_format(vpfe, fmt, &bpp); +} + +static int vpfe_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct v4l2_format format; + unsigned int bpp; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_s_fmt\n"); + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + ret = vpfe_try_fmt(file, priv, fmt); + if (ret) + return ret; + + + if (!cmp_v4l2_format(fmt, &format)) { + /* Sensor format is different from the requested format + * so we need to change it + */ + ret = __vpfe_set_format(vpfe, fmt, &bpp); + if (ret) + return ret; + } else /* Just make sure all of the fields are consistent */ + *fmt = format; + + /* First detach any IRQ if currently attached */ + vpfe_detach_irq(vpfe); + vpfe->fmt = *fmt; + vpfe->bpp = bpp; + + /* Update the crop window based on found values */ + vpfe->crop.width = fmt->fmt.pix.width; + vpfe->crop.height = fmt->fmt.pix.height; + + /* set image capture parameters in the ccdc */ + return vpfe_config_ccdc_image_format(vpfe); +} + +static int vpfe_enum_size(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct v4l2_subdev_frame_size_enum fse; + struct vpfe_subdev_info *sdinfo; + struct v4l2_mbus_framefmt mbus; + struct v4l2_pix_format pix; + struct vpfe_fmt *fmt; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_enum_size\n"); + + /* check for valid format */ + fmt = find_format_by_pix(fsize->pixel_format); + if (!fmt) { + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", + fsize->pixel_format); + return -EINVAL; + } + + memset(fsize->reserved, 0x0, sizeof(fsize->reserved)); + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + memset(&pix, 0x0, sizeof(pix)); + /* Construct pix from parameter and use default for the rest */ + pix.pixelformat = fsize->pixel_format; + pix.width = 640; + pix.height = 480; + pix.colorspace = V4L2_COLORSPACE_SRGB; + pix.field = V4L2_FIELD_NONE; + pix_to_mbus(vpfe, &pix, &mbus); + + memset(&fse, 0x0, sizeof(fse)); + fse.index = fsize->index; + fse.pad = 0; + fse.code = mbus.code; + ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); + if (ret) + return -EINVAL; + + vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", + fse.index, fse.code, fse.min_width, fse.max_width, + fse.min_height, fse.max_height); + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; + + vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n", + fsize->index, print_fourcc(fsize->pixel_format), + fsize->discrete.width, fsize->discrete.height); + + return 0; +} + +/* + * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a + * given app input index + */ +static int +vpfe_get_subdev_input_index(struct vpfe_device *vpfe, + int *subdev_index, + int *subdev_input_index, + int app_input_index) +{ + struct vpfe_config *cfg = vpfe->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { + sdinfo = &cfg->sub_devs[i]; + if (app_input_index < (j + 1)) { + *subdev_index = i; + *subdev_input_index = app_input_index - j; + return 0; + } + j++; + } + return -EINVAL; +} + +/* + * vpfe_get_app_input - Get app input index for a given subdev input index + * driver stores the input index of the current sub device and translate it + * when application request the current input + */ +static int vpfe_get_app_input_index(struct vpfe_device *vpfe, + int *app_input_index) +{ + struct vpfe_config *cfg = vpfe->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { + sdinfo = &cfg->sub_devs[i]; + if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) { + if (vpfe->current_input >= 1) + return -1; + *app_input_index = j + vpfe->current_input; + return 0; + } + j++; + } + return -EINVAL; +} + +static int vpfe_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int subdev, index; + + vpfe_dbg(2, vpfe, "vpfe_enum_input\n"); + + if (vpfe_get_subdev_input_index(vpfe, &subdev, &index, + inp->index) < 0) { + vpfe_dbg(1, vpfe, + "input information not found for the subdev\n"); + return -EINVAL; + } + sdinfo = &vpfe->cfg->sub_devs[subdev]; + *inp = sdinfo->inputs[index]; + + return 0; +} + +static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_g_input\n"); + + return vpfe_get_app_input_index(vpfe, index); +} + +/* Assumes caller is holding vpfe_dev->lock */ +static int vpfe_set_input(struct vpfe_device *vpfe, unsigned int index) +{ + int subdev_index = 0, inp_index = 0; + struct vpfe_subdev_info *sdinfo; + struct vpfe_route *route; + u32 input, output; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index); + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + ret = vpfe_get_subdev_input_index(vpfe, + &subdev_index, + &inp_index, + index); + if (ret < 0) { + vpfe_err(vpfe, "invalid input index: %d\n", index); + goto get_out; + } + + sdinfo = &vpfe->cfg->sub_devs[subdev_index]; + sdinfo->sd = vpfe->sd[subdev_index]; + route = &sdinfo->routes[inp_index]; + if (route && sdinfo->can_route) { + input = route->input; + output = route->output; + if (sdinfo->sd) { + ret = v4l2_subdev_call(sdinfo->sd, video, + s_routing, input, output, 0); + if (ret) { + vpfe_err(vpfe, "s_routing failed\n"); + ret = -EINVAL; + goto get_out; + } + } + + } + + vpfe->current_subdev = sdinfo; + if (sdinfo->sd) + vpfe->v4l2_dev.ctrl_handler = sdinfo->sd->ctrl_handler; + vpfe->current_input = index; + vpfe->std_index = 0; + + /* set the bus/interface parameter for the sub device in ccdc */ + ret = vpfe_ccdc_set_hw_if_params(&vpfe->ccdc, &sdinfo->vpfe_param); + if (ret) + return ret; + + /* set the default image parameters in the device */ + return vpfe_config_image_format(vpfe, + vpfe_standards[vpfe->std_index].std_id); + +get_out: + return ret; +} + +static int vpfe_s_input(struct file *file, void *priv, unsigned int index) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, + "vpfe_s_input: index: %d\n", index); + + return vpfe_set_input(vpfe, index); +} + +static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + vpfe_dbg(2, vpfe, "vpfe_querystd\n"); + + sdinfo = vpfe->current_subdev; + if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; + + /* Call querystd function of decoder device */ + return v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, + video, querystd, std_id); +} + +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_s_std\n"); + + sdinfo = vpfe->current_subdev; + if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + ret = -EBUSY; + return ret; + } + + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, + video, s_std, std_id); + if (ret < 0) { + vpfe_err(vpfe, "Failed to set standard\n"); + return ret; + } + ret = vpfe_config_image_format(vpfe, std_id); + + return ret; +} + +static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + vpfe_dbg(2, vpfe, "vpfe_g_std\n"); + + sdinfo = vpfe->current_subdev; + if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD) + return -ENODATA; + + *std_id = vpfe_standards[vpfe->std_index].std_id; + + return 0; +} + +/* + * vpfe_calculate_offsets : This function calculates buffers offset + * for top and bottom field + */ +static void vpfe_calculate_offsets(struct vpfe_device *vpfe) +{ + struct v4l2_rect image_win; + + vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n"); + + vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); + vpfe->field_off = image_win.height * image_win.width; +} + +/* + * vpfe_queue_setup - Callback function for buffer setup. + * @vq: vb2_queue ptr + * @fmt: v4l2 format + * @nbuffers: ptr to number of buffers requested by application + * @nplanes:: contains number of distinct video planes needed to hold a frame + * @sizes[]: contains the size (in bytes) of each plane. + * @alloc_ctxs: ptr to allocation context + * + * This callback function is called when reqbuf() is called to adjust + * the buffer count and buffer size + */ +static int vpfe_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); + + if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage) + return -EINVAL; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; + + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage; + alloc_ctxs[0] = vpfe->alloc_ctx; + + vpfe_dbg(1, vpfe, + "nbuffers=%d, size=%u\n", *nbuffers, sizes[0]); + + /* Calculate field offset */ + vpfe_calculate_offsets(vpfe); + + return 0; +} + +/* + * vpfe_buffer_prepare : callback function for buffer prepare + * @vb: ptr to vb2_buffer + * + * This is the callback function for buffer prepare when vb2_qbuf() + * function is called. The buffer is prepared and user space virtual address + * or user address is converted into physical address + */ +static int vpfe_buffer_prepare(struct vb2_buffer *vb) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue); + + vb2_set_plane_payload(vb, 0, vpfe->fmt.fmt.pix.sizeimage); + + if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) + return -EINVAL; + + vb->v4l2_buf.field = vpfe->fmt.fmt.pix.field; + + return 0; +} + +/* + * vpfe_buffer_queue : Callback function to add buffer to DMA queue + * @vb: ptr to vb2_buffer + */ +static void vpfe_buffer_queue(struct vb2_buffer *vb) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue); + struct vpfe_cap_buffer *buf = to_vpfe_buffer(vb); + unsigned long flags = 0; + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + list_add_tail(&buf->list, &vpfe->dma_queue); + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); +} + +/* + * vpfe_start_streaming : Starts the DMA engine for streaming + * @vb: ptr to vb2_buffer + * @count: number of buffers + */ +static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); + struct vpfe_cap_buffer *buf, *tmp; + struct vpfe_subdev_info *sdinfo; + unsigned long flags; + unsigned long addr; + int ret; + + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + + vpfe->field = 0; + vpfe->sequence = 0; + + sdinfo = vpfe->current_subdev; + + vpfe_attach_irq(vpfe); + + if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER) + vpfe_ccdc_config_raw(&vpfe->ccdc); + else + vpfe_ccdc_config_ycbcr(&vpfe->ccdc); + + /* Get the next frame from the buffer queue */ + vpfe->next_frm = list_entry(vpfe->dma_queue.next, + struct vpfe_cap_buffer, list); + vpfe->cur_frm = vpfe->next_frm; + /* Remove buffer from the buffer queue */ + list_del(&vpfe->cur_frm->list); + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); + + addr = vb2_dma_contig_plane_dma_addr(&vpfe->cur_frm->vb, 0); + + vpfe_set_sdr_addr(&vpfe->ccdc, (unsigned long)(addr)); + + vpfe_pcr_enable(&vpfe->ccdc, 1); + + ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 1); + if (ret < 0) { + vpfe_err(vpfe, "Error in attaching interrupt handle\n"); + goto err; + } + + return 0; + +err: + list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); + + return ret; +} + +/* + * vpfe_stop_streaming : Stop the DMA engine + * @vq: ptr to vb2_queue + * + * This callback stops the DMA engine and any remaining buffers + * in the DMA queue are released. + */ +static void vpfe_stop_streaming(struct vb2_queue *vq) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); + struct vpfe_subdev_info *sdinfo; + unsigned long flags; + int ret; + + vpfe_pcr_enable(&vpfe->ccdc, 0); + + vpfe_detach_irq(vpfe); + + sdinfo = vpfe->current_subdev; + ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 0); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + vpfe_dbg(1, vpfe, "stream off failed in subdev\n"); + + /* release all active buffers */ + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + if (vpfe->cur_frm == vpfe->next_frm) { + vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_ERROR); + } else { + if (vpfe->cur_frm != NULL) + vb2_buffer_done(&vpfe->cur_frm->vb, + VB2_BUF_STATE_ERROR); + if (vpfe->next_frm != NULL) + vb2_buffer_done(&vpfe->next_frm->vb, + VB2_BUF_STATE_ERROR); + } + + while (!list_empty(&vpfe->dma_queue)) { + vpfe->next_frm = list_entry(vpfe->dma_queue.next, + struct vpfe_cap_buffer, list); + list_del(&vpfe->next_frm->list); + vb2_buffer_done(&vpfe->next_frm->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); +} + +static int vpfe_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_cropcap\n"); + + if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) + return -EINVAL; + + memset(crop, 0, sizeof(struct v4l2_cropcap)); + + crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop->defrect.width = vpfe_standards[vpfe->std_index].width; + crop->bounds.width = crop->defrect.width; + crop->defrect.height = vpfe_standards[vpfe->std_index].height; + crop->bounds.height = crop->defrect.height; + crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect; + + return 0; +} + +static int +vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.left = s->r.top = 0; + s->r.width = vpfe->crop.width; + s->r.height = vpfe->crop.height; + break; + + case V4L2_SEL_TGT_CROP: + s->r = vpfe->crop; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) +{ + if (a->left < b->left || a->top < b->top) + return 0; + + if (a->left + a->width > b->left + b->width) + return 0; + + if (a->top + a->height > b->top + b->height) + return 0; + + return 1; +} + +static int +vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct v4l2_rect cr = vpfe->crop; + struct v4l2_rect r = s->r; + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + v4l_bound_align_image(&r.width, 0, cr.width, 0, + &r.height, 0, cr.height, 0, 0); + + r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width); + r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height); + + if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r)) + return -ERANGE; + + if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r)) + return -ERANGE; + + s->r = vpfe->crop = r; + + vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp); + vpfe->fmt.fmt.pix.width = r.width; + vpfe->fmt.fmt.pix.height = r.height; + vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); + vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline * + vpfe->fmt.fmt.pix.height; + + vpfe_dbg(1, vpfe, "cropped (%d,%d)/%dx%d of %dx%d\n", + r.left, r.top, r.width, r.height, cr.width, cr.height); + + return 0; +} + +static long vpfe_ioctl_default(struct file *file, void *priv, + bool valid_prio, unsigned int cmd, void *param) +{ + struct vpfe_device *vpfe = video_drvdata(file); + int ret; + + vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n"); + + if (!valid_prio) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + switch (cmd) { + case VIDIOC_AM437X_CCDC_CFG: + ret = vpfe_ccdc_set_params(&vpfe->ccdc, param); + if (ret) { + vpfe_dbg(2, vpfe, + "Error setting parameters in CCDC\n"); + return ret; + } + ret = vpfe_get_ccdc_image_format(vpfe, + &vpfe->fmt); + if (ret < 0) { + vpfe_dbg(2, vpfe, + "Invalid image format at CCDC\n"); + return ret; + } + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static const struct vb2_ops vpfe_video_qops = { + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .queue_setup = vpfe_queue_setup, + .buf_prepare = vpfe_buffer_prepare, + .buf_queue = vpfe_buffer_queue, + .start_streaming = vpfe_start_streaming, + .stop_streaming = vpfe_stop_streaming, +}; + +/* vpfe capture driver file operations */ +static const struct v4l2_file_operations vpfe_fops = { + .owner = THIS_MODULE, + .open = vpfe_open, + .release = vpfe_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* vpfe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { + .vidioc_querycap = vpfe_querycap, + .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt, + .vidioc_g_fmt_vid_cap = vpfe_g_fmt, + .vidioc_s_fmt_vid_cap = vpfe_s_fmt, + .vidioc_try_fmt_vid_cap = vpfe_try_fmt, + + .vidioc_enum_framesizes = vpfe_enum_size, + + .vidioc_enum_input = vpfe_enum_input, + .vidioc_g_input = vpfe_g_input, + .vidioc_s_input = vpfe_s_input, + + .vidioc_querystd = vpfe_querystd, + .vidioc_s_std = vpfe_s_std, + .vidioc_g_std = vpfe_g_std, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_cropcap = vpfe_cropcap, + .vidioc_g_selection = vpfe_g_selection, + .vidioc_s_selection = vpfe_s_selection, + + .vidioc_default = vpfe_ioctl_default, +}; + +static int +vpfe_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, + struct vpfe_device, v4l2_dev); + struct v4l2_subdev_mbus_code_enum mbus_code; + struct vpfe_subdev_info *sdinfo; + bool found = false; + int i, j; + + vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); + + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { + sdinfo = &vpfe->cfg->sub_devs[i]; + + if (!strcmp(sdinfo->name, subdev->name)) { + vpfe->sd[i] = subdev; + vpfe_info(vpfe, + "v4l2 sub device %s registered\n", + subdev->name); + vpfe->sd[i]->grp_id = + sdinfo->grp_id; + /* update tvnorms from the sub devices */ + for (j = 0; j < 1; j++) + vpfe->video_dev->tvnorms |= + sdinfo->inputs[j].std; + + found = true; + break; + } + } + + if (!found) { + vpfe_info(vpfe, "sub device (%s) not matched\n", subdev->name); + return -EINVAL; + } + + /* setup the supported formats & indexes */ + for (j = 0, i = 0; ; ++j) { + struct vpfe_fmt *fmt; + int ret; + + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = j; + ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, + NULL, &mbus_code); + if (ret) + break; + + fmt = find_format_by_code(mbus_code.code); + if (!fmt) + continue; + + fmt->supported = true; + fmt->index = i++; + } + + return 0; +} + +static int vpfe_probe_complete(struct vpfe_device *vpfe) +{ + struct video_device *vdev; + struct vb2_queue *q; + int err; + + spin_lock_init(&vpfe->dma_queue_lock); + mutex_init(&vpfe->lock); + + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* set first sub device as current one */ + vpfe->current_subdev = &vpfe->cfg->sub_devs[0]; + vpfe->v4l2_dev.ctrl_handler = vpfe->sd[0]->ctrl_handler; + + err = vpfe_set_input(vpfe, 0); + if (err) + goto probe_out; + + /* Initialize videobuf2 queue as per the buffer type */ + vpfe->alloc_ctx = vb2_dma_contig_init_ctx(vpfe->pdev); + if (IS_ERR(vpfe->alloc_ctx)) { + vpfe_err(vpfe, "Failed to get the context\n"); + err = PTR_ERR(vpfe->alloc_ctx); + goto probe_out; + } + + q = &vpfe->buffer_queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = vpfe; + q->ops = &vpfe_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct vpfe_cap_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &vpfe->lock; + q->min_buffers_needed = 1; + + err = vb2_queue_init(q); + if (err) { + vpfe_err(vpfe, "vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx); + goto probe_out; + } + + INIT_LIST_HEAD(&vpfe->dma_queue); + + vdev = vpfe->video_dev; + strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); + vdev->release = video_device_release; + vdev->fops = &vpfe_fops; + vdev->ioctl_ops = &vpfe_ioctl_ops; + vdev->v4l2_dev = &vpfe->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; + vdev->lock = &vpfe->lock; + video_set_drvdata(vdev, vpfe); + err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1); + if (err) { + vpfe_err(vpfe, + "Unable to register video device.\n"); + goto probe_out; + } + + return 0; + +probe_out: + v4l2_device_unregister(&vpfe->v4l2_dev); + return err; +} + +static int vpfe_async_complete(struct v4l2_async_notifier *notifier) +{ + struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, + struct vpfe_device, v4l2_dev); + + return vpfe_probe_complete(vpfe); +} + +static struct vpfe_config * +vpfe_get_pdata(struct platform_device *pdev) +{ + struct device_node *endpoint = NULL, *rem = NULL; + struct v4l2_of_endpoint bus_cfg; + struct vpfe_subdev_info *sdinfo; + struct vpfe_config *pdata; + unsigned int flags; + unsigned int i; + int err; + + dev_dbg(&pdev->dev, "vpfe_get_pdata\n"); + + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) + return pdev->dev.platform_data; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + for (i = 0; ; i++) { + endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, + endpoint); + if (!endpoint) + break; + + sdinfo = &pdata->sub_devs[i]; + sdinfo->grp_id = 0; + + /* we only support camera */ + sdinfo->inputs[0].index = i; + strcpy(sdinfo->inputs[0].name, "Camera"); + sdinfo->inputs[0].type = V4L2_INPUT_TYPE_CAMERA; + sdinfo->inputs[0].std = V4L2_STD_ALL; + sdinfo->inputs[0].capabilities = V4L2_IN_CAP_STD; + + sdinfo->can_route = 0; + sdinfo->routes = NULL; + + of_property_read_u32(endpoint, "ti,am437x-vpfe-interface", + &sdinfo->vpfe_param.if_type); + if (sdinfo->vpfe_param.if_type < 0 || + sdinfo->vpfe_param.if_type > 4) { + sdinfo->vpfe_param.if_type = VPFE_RAW_BAYER; + } + + err = v4l2_of_parse_endpoint(endpoint, &bus_cfg); + if (err) { + dev_err(&pdev->dev, "Could not parse the endpoint\n"); + goto done; + } + + sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width; + + if (sdinfo->vpfe_param.bus_width < 8 || + sdinfo->vpfe_param.bus_width > 16) { + dev_err(&pdev->dev, "Invalid bus width.\n"); + goto done; + } + + flags = bus_cfg.bus.parallel.flags; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + sdinfo->vpfe_param.hdpol = 1; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + sdinfo->vpfe_param.vdpol = 1; + + rem = of_graph_get_remote_port_parent(endpoint); + if (!rem) { + dev_err(&pdev->dev, "Remote device at %s not found\n", + endpoint->full_name); + goto done; + } + + strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name)); + + pdata->asd[i] = devm_kzalloc(&pdev->dev, + sizeof(struct v4l2_async_subdev), + GFP_KERNEL); + pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF; + pdata->asd[i]->match.of.node = rem; + of_node_put(endpoint); + of_node_put(rem); + } + + of_node_put(endpoint); + return pdata; + +done: + of_node_put(endpoint); + of_node_put(rem); + return NULL; +} + +/* + * vpfe_probe : This function creates device entries by register + * itself to the V4L2 driver and initializes fields of each + * device objects + */ +static int vpfe_probe(struct platform_device *pdev) +{ + struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev); + struct vpfe_device *vpfe; + struct vpfe_ccdc *ccdc; + struct resource *res; + int ret; + + if (!vpfe_cfg) { + dev_err(&pdev->dev, "No platform data\n"); + return -EINVAL; + } + + vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL); + if (!vpfe) + return -ENOMEM; + + vpfe->pdev = &pdev->dev; + vpfe->cfg = vpfe_cfg; + ccdc = &vpfe->ccdc; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ccdc->ccdc_cfg.base_addr)) + return PTR_ERR(ccdc->ccdc_cfg.base_addr); + + vpfe->irq = platform_get_irq(pdev, 0); + if (vpfe->irq <= 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return -ENODEV; + } + + ret = devm_request_irq(vpfe->pdev, vpfe->irq, vpfe_isr, 0, + "vpfe_capture0", vpfe); + if (ret) { + dev_err(&pdev->dev, "Unable to request interrupt\n"); + return -EINVAL; + } + + vpfe->video_dev = video_device_alloc(); + if (!vpfe->video_dev) { + dev_err(&pdev->dev, "Unable to allocate video device\n"); + return -ENOMEM; + } + + ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); + if (ret) { + vpfe_err(vpfe, + "Unable to register v4l2 device.\n"); + goto probe_out_video_release; + } + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpfe); + /* Enabling module functional clock */ + pm_runtime_enable(&pdev->dev); + + /* for now just enable it here instead of waiting for the open */ + pm_runtime_get_sync(&pdev->dev); + + vpfe_ccdc_config_defaults(ccdc); + + pm_runtime_put_sync(&pdev->dev); + + vpfe->sd = devm_kzalloc(&pdev->dev, sizeof(struct v4l2_subdev *) * + ARRAY_SIZE(vpfe->cfg->asd), GFP_KERNEL); + if (!vpfe->sd) { + ret = -ENOMEM; + goto probe_out_v4l2_unregister; + } + + vpfe->notifier.subdevs = vpfe->cfg->asd; + vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd); + vpfe->notifier.bound = vpfe_async_bound; + vpfe->notifier.complete = vpfe_async_complete; + ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, + &vpfe->notifier); + if (ret) { + vpfe_err(vpfe, "Error registering async notifier\n"); + ret = -EINVAL; + goto probe_out_v4l2_unregister; + } + + return 0; + +probe_out_v4l2_unregister: + v4l2_device_unregister(&vpfe->v4l2_dev); +probe_out_video_release: + if (!video_is_registered(vpfe->video_dev)) + video_device_release(vpfe->video_dev); + return ret; +} + +/* + * vpfe_remove : It un-register device from V4L2 driver + */ +static int vpfe_remove(struct platform_device *pdev) +{ + struct vpfe_device *vpfe = platform_get_drvdata(pdev); + + vpfe_dbg(2, vpfe, "vpfe_remove\n"); + + pm_runtime_disable(&pdev->dev); + + v4l2_async_notifier_unregister(&vpfe->notifier); + v4l2_device_unregister(&vpfe->v4l2_dev); + video_unregister_device(vpfe->video_dev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static void vpfe_save_context(struct vpfe_ccdc *ccdc) +{ + ccdc->ccdc_ctx[VPFE_PCR >> 2] = vpfe_reg_read(ccdc, VPFE_PCR); + ccdc->ccdc_ctx[VPFE_SYNMODE >> 2] = vpfe_reg_read(ccdc, VPFE_SYNMODE); + ccdc->ccdc_ctx[VPFE_SDOFST >> 2] = vpfe_reg_read(ccdc, VPFE_SDOFST); + ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2] = vpfe_reg_read(ccdc, VPFE_SDR_ADDR); + ccdc->ccdc_ctx[VPFE_CLAMP >> 2] = vpfe_reg_read(ccdc, VPFE_CLAMP); + ccdc->ccdc_ctx[VPFE_DCSUB >> 2] = vpfe_reg_read(ccdc, VPFE_DCSUB); + ccdc->ccdc_ctx[VPFE_COLPTN >> 2] = vpfe_reg_read(ccdc, VPFE_COLPTN); + ccdc->ccdc_ctx[VPFE_BLKCMP >> 2] = vpfe_reg_read(ccdc, VPFE_BLKCMP); + ccdc->ccdc_ctx[VPFE_VDINT >> 2] = vpfe_reg_read(ccdc, VPFE_VDINT); + ccdc->ccdc_ctx[VPFE_ALAW >> 2] = vpfe_reg_read(ccdc, VPFE_ALAW); + ccdc->ccdc_ctx[VPFE_REC656IF >> 2] = vpfe_reg_read(ccdc, VPFE_REC656IF); + ccdc->ccdc_ctx[VPFE_CCDCFG >> 2] = vpfe_reg_read(ccdc, VPFE_CCDCFG); + ccdc->ccdc_ctx[VPFE_CULLING >> 2] = vpfe_reg_read(ccdc, VPFE_CULLING); + ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2] = vpfe_reg_read(ccdc, + VPFE_HD_VD_WID); + ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2] = vpfe_reg_read(ccdc, + VPFE_PIX_LINES); + ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2] = vpfe_reg_read(ccdc, + VPFE_HORZ_INFO); + ccdc->ccdc_ctx[VPFE_VERT_START >> 2] = vpfe_reg_read(ccdc, + VPFE_VERT_START); + ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2] = vpfe_reg_read(ccdc, + VPFE_VERT_LINES); + ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2] = vpfe_reg_read(ccdc, + VPFE_HSIZE_OFF); +} + +static int vpfe_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vpfe_device *vpfe = platform_get_drvdata(pdev); + struct vpfe_ccdc *ccdc = &vpfe->ccdc; + + /* if streaming has not started we don't care */ + if (!vb2_start_streaming_called(&vpfe->buffer_queue)) + return 0; + + pm_runtime_get_sync(dev); + vpfe_config_enable(ccdc, 1); + + /* Save VPFE context */ + vpfe_save_context(ccdc); + + /* Disable CCDC */ + vpfe_pcr_enable(ccdc, 0); + vpfe_config_enable(ccdc, 0); + + /* Disable both master and slave clock */ + pm_runtime_put_sync(dev); + + /* Select sleep pin state */ + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static void vpfe_restore_context(struct vpfe_ccdc *ccdc) +{ + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SYNMODE >> 2], VPFE_SYNMODE); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CULLING >> 2], VPFE_CULLING); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDOFST >> 2], VPFE_SDOFST); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2], VPFE_SDR_ADDR); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CLAMP >> 2], VPFE_CLAMP); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_DCSUB >> 2], VPFE_DCSUB); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_COLPTN >> 2], VPFE_COLPTN); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_BLKCMP >> 2], VPFE_BLKCMP); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VDINT >> 2], VPFE_VDINT); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_ALAW >> 2], VPFE_ALAW); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_REC656IF >> 2], VPFE_REC656IF); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CCDCFG >> 2], VPFE_CCDCFG); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PCR >> 2], VPFE_PCR); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2], + VPFE_HD_VD_WID); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2], + VPFE_PIX_LINES); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2], + VPFE_HORZ_INFO); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_START >> 2], + VPFE_VERT_START); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2], + VPFE_VERT_LINES); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2], + VPFE_HSIZE_OFF); +} + +static int vpfe_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vpfe_device *vpfe = platform_get_drvdata(pdev); + struct vpfe_ccdc *ccdc = &vpfe->ccdc; + + /* if streaming has not started we don't care */ + if (!vb2_start_streaming_called(&vpfe->buffer_queue)) + return 0; + + /* Enable both master and slave clock */ + pm_runtime_get_sync(dev); + vpfe_config_enable(ccdc, 1); + + /* Restore VPFE context */ + vpfe_restore_context(ccdc); + + vpfe_config_enable(ccdc, 0); + pm_runtime_put_sync(dev); + + /* Select default pin state */ + pinctrl_pm_select_default_state(dev); + + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(vpfe_pm_ops, vpfe_suspend, vpfe_resume); + +static const struct of_device_id vpfe_of_match[] = { + { .compatible = "ti,am437x-vpfe", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, vpfe_of_match); + +static struct platform_driver vpfe_driver = { + .probe = vpfe_probe, + .remove = vpfe_remove, + .driver = { + .name = VPFE_MODULE_NAME, + .owner = THIS_MODULE, + .pm = &vpfe_pm_ops, + .of_match_table = of_match_ptr(vpfe_of_match), + }, +}; + +module_platform_driver(vpfe_driver); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("TI AM437x VPFE driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VPFE_VERSION); diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h new file mode 100644 index 0000000..0f55735 --- /dev/null +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef AM437X_VPFE_H +#define AM437X_VPFE_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "am437x-vpfe_regs.h" + +enum vpfe_pin_pol { + VPFE_PINPOL_POSITIVE = 0, + VPFE_PINPOL_NEGATIVE, +}; + +enum vpfe_hw_if_type { + /* Raw Bayer */ + VPFE_RAW_BAYER = 0, + /* BT656 - 8 bit */ + VPFE_BT656, + /* BT656 - 10 bit */ + VPFE_BT656_10BIT, + /* YCbCr - 8 bit with external sync */ + VPFE_YCBCR_SYNC_8, + /* YCbCr - 16 bit with external sync */ + VPFE_YCBCR_SYNC_16, +}; + +/* interface description */ +struct vpfe_hw_if_param { + enum vpfe_hw_if_type if_type; + enum vpfe_pin_pol hdpol; + enum vpfe_pin_pol vdpol; + unsigned int bus_width; +}; + +#define VPFE_MAX_SUBDEV 1 +#define VPFE_MAX_INPUTS 1 + +struct vpfe_pixel_format { + struct v4l2_fmtdesc fmtdesc; + /* bytes per pixel */ + int bpp; +}; + +struct vpfe_std_info { + int active_pixels; + int active_lines; + /* current frame format */ + int frame_format; +}; + +struct vpfe_route { + u32 input; + u32 output; +}; + +struct vpfe_subdev_info { + char name[32]; + /* Sub device group id */ + int grp_id; + /* inputs available at the sub device */ + struct v4l2_input inputs[VPFE_MAX_INPUTS]; + /* Sub dev routing information for each input */ + struct vpfe_route *routes; + /* check if sub dev supports routing */ + int can_route; + /* ccdc bus/interface configuration */ + struct vpfe_hw_if_param vpfe_param; + struct v4l2_subdev *sd; +}; + +struct vpfe_config { + /* information about each subdev */ + struct vpfe_subdev_info sub_devs[VPFE_MAX_SUBDEV]; + /* Flat array, arranged in groups */ + struct v4l2_async_subdev *asd[VPFE_MAX_SUBDEV]; +}; + +struct vpfe_cap_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +enum ccdc_pixfmt { + CCDC_PIXFMT_RAW = 0, + CCDC_PIXFMT_YCBCR_16BIT, + CCDC_PIXFMT_YCBCR_8BIT, +}; + +enum ccdc_frmfmt { + CCDC_FRMFMT_PROGRESSIVE = 0, + CCDC_FRMFMT_INTERLACED, +}; + +/* PIXEL ORDER IN MEMORY from LSB to MSB */ +/* only applicable for 8-bit input mode */ +enum ccdc_pixorder { + CCDC_PIXORDER_YCBYCR, + CCDC_PIXORDER_CBYCRY, +}; + +enum ccdc_buftype { + CCDC_BUFTYPE_FLD_INTERLEAVED, + CCDC_BUFTYPE_FLD_SEPARATED +}; + + +/* returns the highest bit used for the gamma */ +static inline u8 ccdc_gamma_width_max_bit(enum vpfe_ccdc_gamma_width width) +{ + return 15 - width; +} + +/* returns the highest bit used for this data size */ +static inline u8 ccdc_data_size_max_bit(enum vpfe_ccdc_data_size sz) +{ + return sz == VPFE_CCDC_DATA_8BITS ? 7 : 15 - sz; +} + +/* Structure for CCDC configuration parameters for raw capture mode */ +struct ccdc_params_raw { + /* pixel format */ + enum ccdc_pixfmt pix_fmt; + /* progressive or interlaced frame */ + enum ccdc_frmfmt frm_fmt; + struct v4l2_rect win; + /* Current Format Bytes Per Pixels */ + unsigned int bytesperpixel; + /* Current Format Bytes per Lines + * (Aligned to 32 bytes) used for HORZ_INFO + */ + unsigned int bytesperline; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol hd_pol; + /* interleaved or separated fields */ + enum ccdc_buftype buf_type; + /* + * enable to store the image in inverse + * order in memory(bottom to top) + */ + unsigned char image_invert_enable; + /* configurable parameters */ + struct vpfe_ccdc_config_params_raw config_params; +}; + +struct ccdc_params_ycbcr { + /* pixel format */ + enum ccdc_pixfmt pix_fmt; + /* progressive or interlaced frame */ + enum ccdc_frmfmt frm_fmt; + struct v4l2_rect win; + /* Current Format Bytes Per Pixels */ + unsigned int bytesperpixel; + /* Current Format Bytes per Lines + * (Aligned to 32 bytes) used for HORZ_INFO + */ + unsigned int bytesperline; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol hd_pol; + /* enable BT.656 embedded sync mode */ + int bt656_enable; + /* cb:y:cr:y or y:cb:y:cr in memory */ + enum ccdc_pixorder pix_order; + /* interleaved or separated fields */ + enum ccdc_buftype buf_type; +}; + +/* + * CCDC operational configuration + */ +struct ccdc_config { + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* ccdc base address */ + void __iomem *base_addr; +}; + +struct vpfe_ccdc { + struct ccdc_config ccdc_cfg; + u32 ccdc_ctx[VPFE_REG_END / sizeof(u32)]; +}; + +struct vpfe_device { + /* V4l2 specific parameters */ + /* Identifies video device for this channel */ + struct video_device *video_dev; + /* sub devices */ + struct v4l2_subdev **sd; + /* vpfe cfg */ + struct vpfe_config *cfg; + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* parent device */ + struct device *pdev; + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + /* Indicates id of the field which is being displayed */ + unsigned field; + unsigned sequence; + /* current interface type */ + struct vpfe_hw_if_param vpfe_if_params; + /* ptr to currently selected sub device */ + struct vpfe_subdev_info *current_subdev; + /* current input at the sub device */ + int current_input; + /* Keeps track of the information about the standard */ + struct vpfe_std_info std_info; + /* std index into std table */ + int std_index; + /* IRQs used when CCDC output to SDRAM */ + unsigned int irq; + /* Pointer pointing to current v4l2_buffer */ + struct vpfe_cap_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct vpfe_cap_buffer *next_frm; + /* Used to store pixel format */ + struct v4l2_format fmt; + /* Used to store current bytes per pixel based on current format */ + unsigned int bpp; + /* + * used when IMP is chained to store the crop window which + * is different from the image window + */ + struct v4l2_rect crop; + /* Buffer queue used in video-buf */ + struct vb2_queue buffer_queue; + /* Allocator-specific contexts for each plane */ + struct vb2_alloc_ctx *alloc_ctx; + /* Queue of filled frames */ + struct list_head dma_queue; + /* IRQ lock for DMA queue */ + spinlock_t dma_queue_lock; + /* lock used to access this structure */ + struct mutex lock; + /* + * offset where second field starts from the starting of the + * buffer for field separated YCbCr formats + */ + u32 field_off; + struct vpfe_ccdc ccdc; +}; + +#endif /* AM437X_VPFE_H */ diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h new file mode 100644 index 0000000..4a0ed29 --- /dev/null +++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h @@ -0,0 +1,140 @@ +/* + * TI AM437x Image Sensor Interface Registers + * + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef AM437X_VPFE_REGS_H +#define AM437X_VPFE_REGS_H + +/* VPFE module register offset */ +#define VPFE_REVISION 0x0 +#define VPFE_PCR 0x4 +#define VPFE_SYNMODE 0x8 +#define VPFE_HD_VD_WID 0xc +#define VPFE_PIX_LINES 0x10 +#define VPFE_HORZ_INFO 0x14 +#define VPFE_VERT_START 0x18 +#define VPFE_VERT_LINES 0x1c +#define VPFE_CULLING 0x20 +#define VPFE_HSIZE_OFF 0x24 +#define VPFE_SDOFST 0x28 +#define VPFE_SDR_ADDR 0x2c +#define VPFE_CLAMP 0x30 +#define VPFE_DCSUB 0x34 +#define VPFE_COLPTN 0x38 +#define VPFE_BLKCMP 0x3c +#define VPFE_VDINT 0x48 +#define VPFE_ALAW 0x4c +#define VPFE_REC656IF 0x50 +#define VPFE_CCDCFG 0x54 +#define VPFE_DMA_CNTL 0x98 +#define VPFE_SYSCONFIG 0x104 +#define VPFE_CONFIG 0x108 +#define VPFE_IRQ_EOI 0x110 +#define VPFE_IRQ_STS_RAW 0x114 +#define VPFE_IRQ_STS 0x118 +#define VPFE_IRQ_EN_SET 0x11c +#define VPFE_IRQ_EN_CLR 0x120 +#define VPFE_REG_END 0x124 + +/* Define bit fields within selected registers */ +#define VPFE_FID_POL_MASK 1 +#define VPFE_FID_POL_SHIFT 4 +#define VPFE_HD_POL_MASK 1 +#define VPFE_HD_POL_SHIFT 3 +#define VPFE_VD_POL_MASK 1 +#define VPFE_VD_POL_SHIFT 2 +#define VPFE_HSIZE_OFF_MASK 0xffffffe0 +#define VPFE_32BYTE_ALIGN_VAL 31 +#define VPFE_FRM_FMT_MASK 0x1 +#define VPFE_FRM_FMT_SHIFT 7 +#define VPFE_DATA_SZ_MASK 7 +#define VPFE_DATA_SZ_SHIFT 8 +#define VPFE_PIX_FMT_MASK 3 +#define VPFE_PIX_FMT_SHIFT 12 +#define VPFE_VP2SDR_DISABLE 0xfffbffff +#define VPFE_WEN_ENABLE (1 << 17) +#define VPFE_SDR2RSZ_DISABLE 0xfff7ffff +#define VPFE_VDHDEN_ENABLE (1 << 16) +#define VPFE_LPF_ENABLE (1 << 14) +#define VPFE_ALAW_ENABLE (1 << 3) +#define VPFE_ALAW_GAMMA_WD_MASK 7 +#define VPFE_BLK_CLAMP_ENABLE (1 << 31) +#define VPFE_BLK_SGAIN_MASK 0x1f +#define VPFE_BLK_ST_PXL_MASK 0x7fff +#define VPFE_BLK_ST_PXL_SHIFT 10 +#define VPFE_BLK_SAMPLE_LN_MASK 7 +#define VPFE_BLK_SAMPLE_LN_SHIFT 28 +#define VPFE_BLK_SAMPLE_LINE_MASK 7 +#define VPFE_BLK_SAMPLE_LINE_SHIFT 25 +#define VPFE_BLK_DC_SUB_MASK 0x03fff +#define VPFE_BLK_COMP_MASK 0xff +#define VPFE_BLK_COMP_GB_COMP_SHIFT 8 +#define VPFE_BLK_COMP_GR_COMP_SHIFT 16 +#define VPFE_BLK_COMP_R_COMP_SHIFT 24 +#define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15) +#define VPFE_DATA_PACK_ENABLE (1 << 11) +#define VPFE_HORZ_INFO_SPH_SHIFT 16 +#define VPFE_VERT_START_SLV0_SHIFT 16 +#define VPFE_VDINT_VDINT0_SHIFT 16 +#define VPFE_VDINT_VDINT1_MASK 0xffff +#define VPFE_PPC_RAW 1 +#define VPFE_DCSUB_DEFAULT_VAL 0 +#define VPFE_CLAMP_DEFAULT_VAL 0 +#define VPFE_COLPTN_VAL 0xbb11bb11 +#define VPFE_TWO_BYTES_PER_PIXEL 2 +#define VPFE_INTERLACED_IMAGE_INVERT 0x4b6d +#define VPFE_INTERLACED_NO_IMAGE_INVERT 0x0249 +#define VPFE_PROGRESSIVE_IMAGE_INVERT 0x4000 +#define VPFE_PROGRESSIVE_NO_IMAGE_INVERT 0 +#define VPFE_INTERLACED_HEIGHT_SHIFT 1 +#define VPFE_SYN_MODE_INPMOD_SHIFT 12 +#define VPFE_SYN_MODE_INPMOD_MASK 3 +#define VPFE_SYN_MODE_8BITS (7 << 8) +#define VPFE_SYN_MODE_10BITS (6 << 8) +#define VPFE_SYN_MODE_11BITS (5 << 8) +#define VPFE_SYN_MODE_12BITS (4 << 8) +#define VPFE_SYN_MODE_13BITS (3 << 8) +#define VPFE_SYN_MODE_14BITS (2 << 8) +#define VPFE_SYN_MODE_15BITS (1 << 8) +#define VPFE_SYN_MODE_16BITS (0 << 8) +#define VPFE_SYN_FLDMODE_MASK 1 +#define VPFE_SYN_FLDMODE_SHIFT 7 +#define VPFE_REC656IF_BT656_EN 3 +#define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define VPFE_CCDCFG_Y8POS_SHIFT 11 +#define VPFE_CCDCFG_BW656_10BIT (1 << 5) +#define VPFE_SDOFST_FIELD_INTERLEAVED 0x249 +#define VPFE_NO_CULLING 0xffff00ff +#define VPFE_VDINT0 (1 << 0) +#define VPFE_VDINT1 (1 << 1) +#define VPFE_VDINT2 (1 << 2) +#define VPFE_DMA_CNTL_OVERFLOW (1 << 31) + +#define VPFE_CONFIG_PCLK_INV_SHIFT 0 +#define VPFE_CONFIG_PCLK_INV_MASK 1 +#define VPFE_CONFIG_PCLK_INV_NOT_INV 0 +#define VPFE_CONFIG_PCLK_INV_INV 1 +#define VPFE_CONFIG_EN_SHIFT 1 +#define VPFE_CONFIG_EN_MASK 2 +#define VPFE_CONFIG_EN_DISABLE 0 +#define VPFE_CONFIG_EN_ENABLE 1 +#define VPFE_CONFIG_ST_SHIFT 2 +#define VPFE_CONFIG_ST_MASK 4 +#define VPFE_CONFIG_ST_OCP_ACTIVE 0 +#define VPFE_CONFIG_ST_OCP_STANDBY 1 + +#endif /* AM437X_VPFE_REGS_H */ diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 00b10002..9312d58 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -35,6 +35,7 @@ header-y += adfs_fs.h header-y += affs_hardblocks.h header-y += agpgart.h header-y += aio_abi.h +header-y += am437x-vpfe.h header-y += apm_bios.h header-y += arcfb.h header-y += atalk.h diff --git a/include/uapi/linux/am437x-vpfe.h b/include/uapi/linux/am437x-vpfe.h new file mode 100644 index 0000000..9b03033f --- /dev/null +++ b/include/uapi/linux/am437x-vpfe.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef AM437X_VPFE_USER_H +#define AM437X_VPFE_USER_H + +enum vpfe_ccdc_data_size { + VPFE_CCDC_DATA_16BITS = 0, + VPFE_CCDC_DATA_15BITS, + VPFE_CCDC_DATA_14BITS, + VPFE_CCDC_DATA_13BITS, + VPFE_CCDC_DATA_12BITS, + VPFE_CCDC_DATA_11BITS, + VPFE_CCDC_DATA_10BITS, + VPFE_CCDC_DATA_8BITS, +}; + +/* enum for No of pixel per line to be avg. in Black Clamping*/ +enum vpfe_ccdc_sample_length { + VPFE_CCDC_SAMPLE_1PIXELS = 0, + VPFE_CCDC_SAMPLE_2PIXELS, + VPFE_CCDC_SAMPLE_4PIXELS, + VPFE_CCDC_SAMPLE_8PIXELS, + VPFE_CCDC_SAMPLE_16PIXELS, +}; + +/* enum for No of lines in Black Clamping */ +enum vpfe_ccdc_sample_line { + VPFE_CCDC_SAMPLE_1LINES = 0, + VPFE_CCDC_SAMPLE_2LINES, + VPFE_CCDC_SAMPLE_4LINES, + VPFE_CCDC_SAMPLE_8LINES, + VPFE_CCDC_SAMPLE_16LINES, +}; + +/* enum for Alaw gamma width */ +enum vpfe_ccdc_gamma_width { + VPFE_CCDC_GAMMA_BITS_15_6 = 0, /* use bits 15-6 for gamma */ + VPFE_CCDC_GAMMA_BITS_14_5, + VPFE_CCDC_GAMMA_BITS_13_4, + VPFE_CCDC_GAMMA_BITS_12_3, + VPFE_CCDC_GAMMA_BITS_11_2, + VPFE_CCDC_GAMMA_BITS_10_1, + VPFE_CCDC_GAMMA_BITS_09_0, /* use bits 9-0 for gamma */ +}; + +/* structure for ALaw */ +struct vpfe_ccdc_a_law { + /* Enable/disable A-Law */ + unsigned char enable; + /* Gamma Width Input */ + enum vpfe_ccdc_gamma_width gamma_wd; +}; + +/* structure for Black Clamping */ +struct vpfe_ccdc_black_clamp { + unsigned char enable; + /* only if bClampEnable is TRUE */ + enum vpfe_ccdc_sample_length sample_pixel; + /* only if bClampEnable is TRUE */ + enum vpfe_ccdc_sample_line sample_ln; + /* only if bClampEnable is TRUE */ + unsigned short start_pixel; + /* only if bClampEnable is TRUE */ + unsigned short sgain; + /* only if bClampEnable is FALSE */ + unsigned short dc_sub; +}; + +/* structure for Black Level Compensation */ +struct vpfe_ccdc_black_compensation { + /* Constant value to subtract from Red component */ + char r; + /* Constant value to subtract from Gr component */ + char gr; + /* Constant value to subtract from Blue component */ + char b; + /* Constant value to subtract from Gb component */ + char gb; +}; + +/* Structure for CCDC configuration parameters for raw capture mode passed + * by application + */ +struct vpfe_ccdc_config_params_raw { + /* data size value from 8 to 16 bits */ + enum vpfe_ccdc_data_size data_sz; + /* Structure for Optional A-Law */ + struct vpfe_ccdc_a_law alaw; + /* Structure for Optical Black Clamp */ + struct vpfe_ccdc_black_clamp blk_clamp; + /* Structure for Black Compensation */ + struct vpfe_ccdc_black_compensation blk_comp; +}; + +/* + * Private IOCTL + * VIDIOC_AM437X_CCDC_CFG - Set CCDC configuration for raw capture + * This is an experimental ioctl that will change in future kernels. So use + * this ioctl with care ! + **/ +#define VIDIOC_AM437X_CCDC_CFG \ + _IOW('V', BASE_VIDIOC_PRIVATE + 1, void *) + +#endif /* AM437X_VPFE_USER_H */ -- cgit v0.10.2 From 6de16eba62b3b4d01b2b232ea7724d5450a19e30 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 08:38:24 -0700 Subject: Docs: Remove "tips and tricks" from SubmittingPatches This section was just a weird collection of stuff that is better found elsewhere. The "coding style" section somewhat duplicated the previous coding style section; the useful information there has been collected into a single place. Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 1fa1caa..8f416a2 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -193,17 +193,33 @@ then only post say 15 or so at a time and wait for review and integration. -4) Style check your changes. +4) Style-check your changes. +---------------------------- Check your patch for basic style violations, details of which can be found in Documentation/CodingStyle. Failure to do so simply wastes the reviewers time and will get your patch rejected, probably without even being read. -At a minimum you should check your patches with the patch style -checker prior to submission (scripts/checkpatch.pl). You should -be able to justify all violations that remain in your patch. +One significant exception is when moving code from one file to +another -- in this case you should not modify the moved code at all in +the same patch which moves it. This clearly delineates the act of +moving the code and your changes. This greatly aids review of the +actual differences and allows tools to better track the history of +the code itself. + +Check your patches with the patch style checker prior to submission +(scripts/checkpatch.pl). Note, though, that the style checker should be +viewed as a guide, not as a replacement for human judgment. If your code +looks better with a violation then its probably best left alone. +The checker reports at three levels: + - ERROR: things that are very likely to be wrong + - WARNING: things requiring careful review + - CHECK: things requiring thought + +You should be able to justify all violations that remain in your +patch. 5) Select e-mail destination. @@ -684,100 +700,9 @@ new/deleted or renamed files. With rename detection, the statistics are rather different [...] because git will notice that a fair number of the changes are renames. ------------------------------------ -SECTION 2 - HINTS, TIPS, AND TRICKS ------------------------------------ - -This section lists many of the common "rules" associated with code -submitted to the kernel. There are always exceptions... but you must -have a really good reason for doing so. You could probably call this -section Linus Computer Science 101. - - - -1) Read Documentation/CodingStyle - -Nuff said. If your code deviates too much from this, it is likely -to be rejected without further review, and without comment. - -One significant exception is when moving code from one file to -another -- in this case you should not modify the moved code at all in -the same patch which moves it. This clearly delineates the act of -moving the code and your changes. This greatly aids review of the -actual differences and allows tools to better track the history of -the code itself. - -Check your patches with the patch style checker prior to submission -(scripts/checkpatch.pl). The style checker should be viewed as -a guide not as the final word. If your code looks better with -a violation then its probably best left alone. - -The checker reports at three levels: - - ERROR: things that are very likely to be wrong - - WARNING: things requiring careful review - - CHECK: things requiring thought - -You should be able to justify all violations that remain in your -patch. - - - -2) #ifdefs are ugly - -Code cluttered with ifdefs is difficult to read and maintain. Don't do -it. Instead, put your ifdefs in a header, and conditionally define -'static inline' functions, or macros, which are used in the code. -Let the compiler optimize away the "no-op" case. - -Simple example, of poor code: - - dev = alloc_etherdev (sizeof(struct funky_private)); - if (!dev) - return -ENODEV; - #ifdef CONFIG_NET_FUNKINESS - init_funky_net(dev); - #endif - -Cleaned-up example: - -(in header) - #ifndef CONFIG_NET_FUNKINESS - static inline void init_funky_net (struct net_device *d) {} - #endif - -(in the code itself) - dev = alloc_etherdev (sizeof(struct funky_private)); - if (!dev) - return -ENODEV; - init_funky_net(dev); - - - -3) 'static inline' is better than a macro - -Static inline functions are greatly preferred over macros. -They provide type safety, have no length limitations, no formatting -limitations, and under gcc they are as cheap as macros. - -Macros should only be used for cases where a static inline is clearly -suboptimal [there are a few, isolated cases of this in fast paths], -or where it is impossible to use a static inline function [such as -string-izing]. - -'static inline' is preferred over 'static __inline__', 'extern inline', -and 'extern __inline__'. - - - -4) Don't over-design. - -Don't try to anticipate nebulous future cases which may or may not -be useful: "Make it as simple as you can, and no simpler." - - ---------------------- -SECTION 3 - REFERENCES +SECTION 2 - REFERENCES ---------------------- Andrew Morton, "The perfect patch" (tpp). -- cgit v0.10.2 From 7994cc15d83c6188a77516f4c8400d3a4965b0a5 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 08:43:41 -0700 Subject: Docs: Bring SubmittingPatches more into the git era Much of the information in SubmittingPatches shows its pre-git history. Clean that up a bit and rephrase things with the assumption that developers will be using git. Also rewrite the "pull requests" section and include information on using signed tags. Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 8f416a2..230a3b8 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -24,13 +24,30 @@ SECTION 1 - CREATING AND SENDING YOUR CHANGE -------------------------------------------- +0) Obtain a current source tree +------------------------------- + +If you do not have a repository with the current kernel source handy, use +git to obtain one. You'll want to start with the mainline repository, +which can be grabbed with: + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + +Note, however, that you may not want to develop against the mainline tree +directly. Most subsystem maintainers run their own trees and want to see +patches prepared against those trees. See the "T:" entry for the subsystem +in the MAINTAINERS file to find that tree, or simply ask the maintainer if +the tree is not listed there. + +It is still possible to download kernel releases via tarballs (as described +in the next section), but that is the hard way to do kernel development. 1) "diff -up" ------------ -Use "diff -up" or "diff -uprN" to create patches. git generates patches -in this form by default; if you're using git, you can skip this section -entirely. +If you must generate your patches by hand, use "diff -up" or "diff -uprN" +to create patches. Git generates patches in this form by default; if +you're using git, you can skip this section entirely. All changes to the Linux kernel occur in the form of patches, as generated by diff(1). When creating your patch, make sure to create it @@ -156,10 +173,15 @@ Example: platform_set_drvdata(), but left the variable "dev" unused, delete it. +You should also be sure to use at least the first twelve characters of the +SHA-1 ID. The kernel repository holds a *lot* of objects, making +collisions with shorter IDs a real possibility. Bear in mind that, even if +there is no collision with your six-character ID now, that condition may +change five years from now. + If your patch fixes a bug in a specific commit, e.g. you found an issue using git-bisect, please use the 'Fixes:' tag with the first 12 characters of the -SHA-1 ID, and the one line summary. -Example: +SHA-1 ID, and the one line summary. For example: Fixes: e21d2170f366 ("video: remove unnecessary platform_set_drvdata()") @@ -188,6 +210,12 @@ If one patch depends on another patch in order for a change to be complete, that is OK. Simply note "this patch depends on patch X" in your patch description. +When dividing your change into a series of patches, take special care to +ensure that the kernel builds and runs properly after each patch in the +series. Developers using "git bisect" to track down a problem can end up +splitting your patch series at any point; they will not thank you if you +introduce bugs in the middle. + If you cannot condense your patch set into a smaller set of patches, then only post say 15 or so at a time and wait for review and integration. @@ -445,15 +473,15 @@ which appears in the changelog. Special note to back-porters: It seems to be a common and useful practice to insert an indication of the origin of a patch at the top of the commit message (just after the subject line) to facilitate tracking. For instance, -here's what we see in 2.6-stable : +here's what we see in a 3.x-stable release: - Date: Tue May 13 19:10:30 2008 +0000 +Date: Tue Oct 7 07:26:38 2014 -0400 - SCSI: libiscsi regression in 2.6.25: fix nop timer handling + libata: Un-break ATA blacklist - commit 4cf1043593db6a337f10e006c23c69e5fc93e722 upstream + commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream. -And here's what appears in 2.4 : +And here's what might appear in an older kernel once a patch is backported: Date: Tue May 13 22:12:27 2008 +0200 @@ -462,7 +490,7 @@ And here's what appears in 2.4 : [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a] Whatever the format, this information provides a valuable help to people -tracking your trees, and to people trying to trouble-shoot bugs in your +tracking your trees, and to people trying to troubleshoot bugs in your tree. @@ -558,6 +586,12 @@ method for indicating a bug fixed by the patch. See #2 above for more details. 15) The canonical patch format +------------------------------ + +This section describes how the patch itself should be formatted. Note +that, if you have your patches stored in a git repository, proper patch +formatting can be had with "git format-patch". The tools cannot create +the necessary text, though, so read the instructions below anyway. The canonical patch subject line is: @@ -672,33 +706,57 @@ See more details on the proper patch format in the following references. -16) Sending "git pull" requests (from Linus emails) +16) Sending "git pull" requests +------------------------------- + +If you have a series of patches, it may be most convenient to have the +maintainer pull them directly into the subsystem repository with a +"git pull" operation. Note, however, that pulling patches from a developer +requires a higher degree of trust than taking patches from a mailing list. +As a result, many subsystem maintainers are reluctant to take pull +requests, especially from new, unknown developers. + +A pull request should have [GIT] or [PULL] in the subject line. The +request itself should include the repository name and the branch of +interest on a single line; it should look something like: + + Please pull from -Please write the git repo address and branch name alone on the same line -so that I can't even by mistake pull from the wrong branch, and so -that a triple-click just selects the whole thing. + git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus -So the proper format is something along the lines of: + to get these changes:" - "Please pull from +A pull request should also include an overall message saying what will be +included in the request, a "git shortlog" listing of the patches +themselves, and a diffstat showing the overall effect of the patch series. +The easiest way to get all this information together is, of course, to let +git do it for you with the "git request-pull" command. - git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus +Some maintainers (including Linus) want to see pull requests from signed +commits; that increases their confidence that the request actually came +from you. Linus, in particular, will not pull from public hosting sites +like GitHub in the absence of a signed tag. - to get these changes:" +The first step toward creating such tags is to make a GNUPG key and get it +signed by one or more core kernel developers. This step can be hard for +new developers, but there is no way around it. Attending conferences can +be a good way to find developers who can sign your key. -so that I don't have to hunt-and-peck for the address and inevitably -get it wrong (actually, I've only gotten it wrong a few times, and -checking against the diffstat tells me when I get it wrong, but I'm -just a lot more comfortable when I don't have to "look for" the right -thing to pull, and double-check that I have the right branch-name). +Once you have prepared a patch series in git that you wish to have somebody +pull, create a signed tag with "git tag -s". This will create a new tag +identifying the last commit in the series and containing a signature +created with your private key. You will also have the opportunity to add a +changelog-style message to the tag; this is an ideal place to describe the +effects of the pull request as a whole. +If the tree the maintainer will be pulling from is not the repository you +are working from, don't forget to push the signed tag explicitly to the +public tree. -Please use "git diff -M --stat --summary" to generate the diffstat: -the -M enables rename detection, and the summary enables a summary of -new/deleted or renamed files. +When generating your pull request, use the signed tag as the target. A +command like this will do the trick: -With rename detection, the statistics are rather different [...] -because git will notice that a fair number of the changes are renames. + git request-pull master git://my.public.tree/linux.git my-signed-tag ---------------------- -- cgit v0.10.2 From ccae8616ecfb9506e7060f77c6cff2b782772fa0 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 08:49:18 -0700 Subject: Docs: Update recipient information in SubmittingPatches SubmittingPatches had two sections on selecting recipients; both were showing their age. Unify them into a single section that more closely reflects how we do things now. Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 230a3b8..e169c6c 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -250,68 +250,68 @@ You should be able to justify all violations that remain in your patch. -5) Select e-mail destination. - -Look through the MAINTAINERS file and the source code, and determine -if your change applies to a specific subsystem of the kernel, with -an assigned maintainer. If so, e-mail that person. The script -scripts/get_maintainer.pl can be very useful at this step. - -If no maintainer is listed, or the maintainer does not respond, send -your patch to the primary Linux kernel developer's mailing list, -linux-kernel@vger.kernel.org. Most kernel developers monitor this -e-mail list, and can comment on your changes. - +5) Select the recipients for your patch. +---------------------------------------- + +You should always copy the appropriate subsystem maintainer(s) on any patch +to code that they maintain; look through the MAINTAINERS file and the +source code revision history to see who those maintainers are. The +script scripts/get_maintainer.pl can be very useful at this step. If you +cannot find a maintainer for the subsystem your are working on, Andrew +Morton (akpm@linux-foundation.org) serves as a maintainer of last resort. + +You should also normally choose at least one mailing list to receive a copy +of your patch set. linux-kernel@vger.kernel.org functions as a list of +last resort, but the volume on that list has caused a number of developers +to tune it out. Look in the MAINTAINERS file for a subsystem-specific +list; your patch will probably get more attention there. Please do not +spam unrelated lists, though. + +Many kernel-related lists are hosted on vger.kernel.org; you can find a +list of them at http://vger.kernel.org/vger-lists.html. There are +kernel-related lists hosted elsewhere as well, though. Do not send more than 15 patches at once to the vger mailing lists!!! - Linus Torvalds is the final arbiter of all changes accepted into the Linux kernel. His e-mail address is . -He gets a lot of e-mail, so typically you should do your best to -avoid- -sending him e-mail. - -Patches which are bug fixes, are "obvious" changes, or similarly -require little discussion should be sent or CC'd to Linus. Patches -which require discussion or do not have a clear advantage should -usually be sent first to linux-kernel. Only after the patch is -discussed should the patch then be submitted to Linus. - - +He gets a lot of e-mail, and, at this point, very few patches go through +Linus directly, so typically you should do your best to -avoid- +sending him e-mail. -6) Select your CC (e-mail carbon copy) list. +If you have a patch that fixes an exploitable security bug, send that patch +to security@kernel.org. For severe bugs, a short embargo may be considered +to allow distrbutors to get the patch out to users; in such cases, +obviously, the patch should not be sent to any public lists. -Unless you have a reason NOT to do so, CC linux-kernel@vger.kernel.org. +Patches that fix a severe bug in a released kernel should be directed +toward the stable maintainers by putting a line like this: -Other kernel developers besides Linus need to be aware of your change, -so that they may comment on it and offer code review and suggestions. -linux-kernel is the primary Linux kernel developer mailing list. -Other mailing lists are available for specific subsystems, such as -USB, framebuffer devices, the VFS, the SCSI subsystem, etc. See the -MAINTAINERS file for a mailing list that relates specifically to -your change. + Cc: stable@vger.kernel.org -Majordomo lists of VGER.KERNEL.ORG at: - +into your patch. -If changes affect userland-kernel interfaces, please send -the MAN-PAGES maintainer (as listed in the MAINTAINERS file) -a man-pages patch, or at least a notification of the change, -so that some information makes its way into the manual pages. +Note, however, that some subsystem maintainers want to come to their own +conclusions on which patches should go to the stable trees. The networking +maintainer, in particular, would rather not see individual developers +adding lines like the above to their patches. -Even if the maintainer did not respond in step #5, make sure to ALWAYS -copy the maintainer when you change their code. +If changes affect userland-kernel interfaces, please send the MAN-PAGES +maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at +least a notification of the change, so that some information makes its way +into the manual pages. User-space API changes should also be copied to +linux-api@vger.kernel.org. For small patches you may want to CC the Trivial Patch Monkey trivial@kernel.org which collects "trivial" patches. Have a look into the MAINTAINERS file for its current manager. Trivial patches must qualify for one of the following rules: Spelling fixes in documentation - Spelling fixes which could break grep(1) + Spelling fixes for errors which could break grep(1) Warning fixes (cluttering with useless warnings is bad) Compilation fixes (only if they are actually correct) Runtime fixes (only if they actually fix things) - Removing use of deprecated functions/macros (eg. check_region) + Removing use of deprecated functions/macros Contact detail and documentation fixes Non-portable code replaced by portable code (even in arch-specific, since people copy, as long as it's trivial) @@ -320,7 +320,7 @@ Trivial patches must qualify for one of the following rules: -7) No MIME, no links, no compression, no attachments. Just plain text. +6) No MIME, no links, no compression, no attachments. Just plain text. Linus and other kernel developers need to be able to read and comment on the changes you are submitting. It is important for a kernel @@ -343,7 +343,7 @@ you to re-send them using MIME. See Documentation/email-clients.txt for hints about configuring your e-mail client so that it sends your patches untouched. -8) E-mail size. +7) E-mail size. When sending patches to Linus, always follow step #7. @@ -354,7 +354,7 @@ server, and provide instead a URL (link) pointing to your patch. -9) Name your kernel version. +8) Name your kernel version. It is important to note, either in the subject line or in the patch description, the kernel version to which this patch applies. @@ -364,7 +364,7 @@ Linus will not apply it. -10) Don't get discouraged. Re-submit. +9) Don't get discouraged. Re-submit. After you have submitted your change, be patient and wait. If Linus likes your change and applies it, it will appear in the next version @@ -390,7 +390,7 @@ When in doubt, solicit comments on linux-kernel mailing list. -11) Include PATCH in the subject +10) Include PATCH in the subject Due to high e-mail traffic to Linus, and to linux-kernel, it is common convention to prefix your subject line with [PATCH]. This lets Linus @@ -399,7 +399,7 @@ e-mail discussions. -12) Sign your work +11) Sign your work To improve tracking of who did what, especially with patches that can percolate to their final resting place in the kernel through several @@ -494,7 +494,7 @@ tracking your trees, and to people trying to troubleshoot bugs in your tree. -13) When to use Acked-by: and Cc: +12) When to use Acked-by: and Cc: The Signed-off-by: tag indicates that the signer was involved in the development of the patch, or that he/she was in the patch's delivery path. @@ -525,7 +525,7 @@ person it names. This tag documents that potentially interested parties have been included in the discussion -14) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: +13) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: The Reported-by tag gives credit to people who find bugs and report them and it hopefully inspires them to help us again in the future. Please note that if @@ -585,7 +585,7 @@ which stable kernel versions should receive your fix. This is the preferred method for indicating a bug fixed by the patch. See #2 above for more details. -15) The canonical patch format +14) The canonical patch format ------------------------------ This section describes how the patch itself should be formatted. Note @@ -599,7 +599,8 @@ The canonical patch subject line is: The canonical patch message body contains the following: - - A "from" line specifying the patch author. + - A "from" line specifying the patch author (only needed if the person + sending the patch is not the author). - An empty line. @@ -706,7 +707,7 @@ See more details on the proper patch format in the following references. -16) Sending "git pull" requests +15) Sending "git pull" requests ------------------------------- If you have a series of patches, it may be most convenient to have the -- cgit v0.10.2 From 0eea2314377146767273eadfc5b34b4f017777b2 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 08:52:01 -0700 Subject: Docs: SubmittingPatches: update follow-through instructions SubmittingPatches was written in the "keep sending to Linus until something shows up in a release" era. Given that we don't do things that way anymore and the system is far less lossy, update this information and add some hints on responding to reviewer comments. Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index e169c6c..a830840 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -354,40 +354,34 @@ server, and provide instead a URL (link) pointing to your patch. -8) Name your kernel version. - -It is important to note, either in the subject line or in the patch -description, the kernel version to which this patch applies. - -If the patch does not apply cleanly to the latest kernel version, -Linus will not apply it. - - +8) Respond to review comments. +------------------------------ -9) Don't get discouraged. Re-submit. +Your patch will almost certainly get comments from reviewers on ways in +which the patch can be improved. You must respond to those comments; +ignoring reviewers is a good way to get ignored in return. Review comments +or questions that do not lead to a code change should almost certainly +bring about a comment or changelog entry so that the next reviewer better +understands what is going on. -After you have submitted your change, be patient and wait. If Linus -likes your change and applies it, it will appear in the next version -of the kernel that he releases. +Be sure to tell the reviewers what changes you are making and to thank them +for their time. Code review is a tiring and time-consuming process, and +reviewers sometimes get grumpy. Even in that case, though, respond +politely and address the problems they have pointed out. -However, if your change doesn't appear in the next version of the -kernel, there could be any number of reasons. It's YOUR job to -narrow down those reasons, correct what was wrong, and submit your -updated change. -It is quite common for Linus to "drop" your patch without comment. -That's the nature of the system. If he drops your patch, it could be -due to -* Your patch did not apply cleanly to the latest kernel version. -* Your patch was not sufficiently discussed on linux-kernel. -* A style issue (see section 2). -* An e-mail formatting issue (re-read this section). -* A technical problem with your change. -* He gets tons of e-mail, and yours got lost in the shuffle. -* You are being annoying. +9) Don't get discouraged - or impatient. +---------------------------------------- -When in doubt, solicit comments on linux-kernel mailing list. +After you have submitted your change, be patient and wait. Reviewers are +busy people and may not get to your patch right away. +Once upon a time, patches used to disappear into the void without comment, +but the development process works more smoothly than that now. You should +receive comments within a week or so; if that does not happen, make sure +that you have sent your patches to the right place. Wait for a minimum of +one week before resubmitting or pinging reviewers - possibly longer during +busy times like merge windows. 10) Include PATCH in the subject -- cgit v0.10.2 From d00c455964002a8e7f126b16051e846a9f9877c6 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 08:54:36 -0700 Subject: Docs: SubmittingPatches: miscellaneous cleanups Changes to make the formatting a bit more consistent and fix up wording in various places. Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index a830840..e6cbe59 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -10,14 +10,18 @@ kernel, the process can sometimes be daunting if you're not familiar with "the system." This text is a collection of suggestions which can greatly increase the chances of your change being accepted. -Read Documentation/SubmitChecklist for a list of items to check -before submitting code. If you are submitting a driver, also read +This document contains a large number of suggestions in a relatively terse +format. For detailed information on how the kernel development process +works, see Documentation/development-process. Also, read +Documentation/SubmitChecklist for a list of items to check before +submitting code. If you are submitting a driver, also read Documentation/SubmittingDrivers. Many of these steps describe the default behavior of the git version control system; if you use git to prepare your patches, you'll find much of the mechanical work done for you, though you'll still need to prepare -and document a sensible set of patches. +and document a sensible set of patches. In general, use of git will make +your life as a kernel developer easier. -------------------------------------------- SECTION 1 - CREATING AND SENDING YOUR CHANGE @@ -59,7 +63,7 @@ not in any lower subdirectory. To create a patch for a single file, it is often sufficient to do: - SRCTREE= linux-2.6 + SRCTREE= linux MYFILE= drivers/net/mydriver.c cd $SRCTREE @@ -72,17 +76,16 @@ To create a patch for multiple files, you should unpack a "vanilla", or unmodified kernel source tree, and generate a diff against your own source tree. For example: - MYSRC= /devel/linux-2.6 + MYSRC= /devel/linux - tar xvfz linux-2.6.12.tar.gz - mv linux-2.6.12 linux-2.6.12-vanilla - diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \ - linux-2.6.12-vanilla $MYSRC > /tmp/patch + tar xvfz linux-3.19.tar.gz + mv linux-3.19 linux-3.19-vanilla + diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \ + linux-3.19-vanilla $MYSRC > /tmp/patch "dontdiff" is a list of files which are generated by the kernel during the build process, and should be ignored in any diff(1)-generated -patch. The "dontdiff" file is included in the kernel tree in -2.6.12 and later. +patch. Make sure your patch does not include any extra files which do not belong in a patch submission. Make sure to review your patch -after- @@ -100,6 +103,7 @@ is another popular alternative. 2) Describe your changes. +------------------------- Describe your problem. Whether your patch is a one-line bug fix or 5000 lines of a new feature, there must be an underlying problem that @@ -141,10 +145,10 @@ See #3, next. When you submit or resubmit a patch or patch series, include the complete patch description and justification for it. Don't just say that this is version N of the patch (series). Don't expect the -patch merger to refer back to earlier patch versions or referenced +subsystem maintainer to refer back to earlier patch versions or referenced URLs to find the patch description and put that into the patch. I.e., the patch (series) and its description should be self-contained. -This benefits both the patch merger(s) and reviewers. Some reviewers +This benefits both the maintainers and reviewers. Some reviewers probably didn't even receive earlier versions of the patch. Describe your changes in imperative mood, e.g. "make xyzzy do frotz" @@ -194,8 +198,9 @@ outputting the above style in the git log or git show commands fixes = Fixes: %h (\"%s\") 3) Separate your changes. +------------------------- -Separate _logical changes_ into a single patch file. +Separate each _logical change_ into a separate patch. For example, if your changes include both bug fixes and performance enhancements for a single driver, separate those changes into two @@ -206,6 +211,10 @@ On the other hand, if you make a single change to numerous files, group those changes into a single patch. Thus a single logical change is contained within a single patch. +The point to remember is that each patch should make an easily understood +change that can be verified by reviewers. Each patch should be justifiable +on its own merits. + If one patch depends on another patch in order for a change to be complete, that is OK. Simply note "this patch depends on patch X" in your patch description. @@ -321,6 +330,7 @@ Trivial patches must qualify for one of the following rules: 6) No MIME, no links, no compression, no attachments. Just plain text. +----------------------------------------------------------------------- Linus and other kernel developers need to be able to read and comment on the changes you are submitting. It is important for a kernel @@ -344,15 +354,14 @@ See Documentation/email-clients.txt for hints about configuring your e-mail client so that it sends your patches untouched. 7) E-mail size. - -When sending patches to Linus, always follow step #7. +--------------- Large changes are not appropriate for mailing lists, and some maintainers. If your patch, uncompressed, exceeds 300 kB in size, it is preferred that you store your patch on an Internet-accessible -server, and provide instead a URL (link) pointing to your patch. - - +server, and provide instead a URL (link) pointing to your patch. But note +that if your patch exceeds 300 kB, it almost certainly needs to be broken up +anyway. 8) Respond to review comments. ------------------------------ @@ -385,6 +394,7 @@ busy times like merge windows. 10) Include PATCH in the subject +-------------------------------- Due to high e-mail traffic to Linus, and to linux-kernel, it is common convention to prefix your subject line with [PATCH]. This lets Linus @@ -394,6 +404,7 @@ e-mail discussions. 11) Sign your work +------------------ To improve tracking of who did what, especially with patches that can percolate to their final resting place in the kernel through several @@ -489,13 +500,14 @@ tree. 12) When to use Acked-by: and Cc: +--------------------------------- The Signed-off-by: tag indicates that the signer was involved in the development of the patch, or that he/she was in the patch's delivery path. If a person was not directly involved in the preparation or handling of a patch but wishes to signify and record their approval of it then they can -arrange to have an Acked-by: line added to the patch's changelog. +ask to have an Acked-by: line added to the patch's changelog. Acked-by: is often used by the maintainer of the affected code when that maintainer neither contributed to nor forwarded the patch. @@ -503,7 +515,8 @@ maintainer neither contributed to nor forwarded the patch. Acked-by: is not as formal as Signed-off-by:. It is a record that the acker has at least reviewed the patch and has indicated acceptance. Hence patch mergers will sometimes manually convert an acker's "yep, looks good to me" -into an Acked-by:. +into an Acked-by: (but note that it is usually better to ask for an +explicit ack). Acked-by: does not necessarily indicate acknowledgement of the entire patch. For example, if a patch affects multiple subsystems and has an Acked-by: from @@ -515,11 +528,13 @@ list archives. If a person has had the opportunity to comment on a patch, but has not provided such comments, you may optionally add a "Cc:" tag to the patch. This is the only tag which might be added without an explicit action by the -person it names. This tag documents that potentially interested parties -have been included in the discussion +person it names - but it should indicate that this person was copied on the +patch. This tag documents that potentially interested parties +have been included in the discussion. 13) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: +-------------------------------------------------------------------------- The Reported-by tag gives credit to people who find bugs and report them and it hopefully inspires them to help us again in the future. Please note that if -- cgit v0.10.2 From 082bd1ca9a7eaf28695d8bab9adcff54f77c040c Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 09:27:04 -0700 Subject: Docs: Mention device tree binding info Suggested-by: Frank Rowand Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index e6cbe59..1f4e8c8 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -15,7 +15,8 @@ format. For detailed information on how the kernel development process works, see Documentation/development-process. Also, read Documentation/SubmitChecklist for a list of items to check before submitting code. If you are submitting a driver, also read -Documentation/SubmittingDrivers. +Documentation/SubmittingDrivers; for device tree binding patches, read +Documentation/devicetree/bindings/submitting-patches.txt. Many of these steps describe the default behavior of the git version control system; if you use git to prepare your patches, you'll find much -- cgit v0.10.2 From b792ffe464f64c84c48d51e01c0fecabc4b39579 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 23 Dec 2014 09:28:40 -0700 Subject: Docs: SubmittingPatches: mention using pull requests as a cover letter Suggested-by: Mark Brown Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 1f4e8c8..40b619e 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -725,7 +725,9 @@ maintainer pull them directly into the subsystem repository with a "git pull" operation. Note, however, that pulling patches from a developer requires a higher degree of trust than taking patches from a mailing list. As a result, many subsystem maintainers are reluctant to take pull -requests, especially from new, unknown developers. +requests, especially from new, unknown developers. If in doubt you can use +the pull request as the cover letter for a normal posting of the patch +series, giving the maintainer the option of using either. A pull request should have [GIT] or [PULL] in the subject line. The request itself should include the repository name and the branch of -- cgit v0.10.2 From d2fb785227c03443b5df4ea8e4b6f6d8bd2b2d13 Mon Sep 17 00:00:00 2001 From: Benjamin Larsson Date: Wed, 26 Nov 2014 18:51:46 -0300 Subject: [media] mn88472: calculate the IF register values Add xtal as a configuration parameter so it can be used in the IF register value calculation. Signed-off-by: Benjamin Larsson Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h index da4558b..e4e0b80 100644 --- a/drivers/media/dvb-frontends/mn88472.h +++ b/drivers/media/dvb-frontends/mn88472.h @@ -33,6 +33,12 @@ struct mn88472_config { * DVB frontend. */ struct dvb_frontend **fe; + + /* + * Xtal frequency. + * Hz + */ + u32 xtal; }; #endif diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 896a225..73580f8 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -852,6 +852,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) mn88472_config.fe = &adap->fe[1]; mn88472_config.i2c_wr_max = 22, strlcpy(info.type, "mn88472", I2C_NAME_SIZE); + mn88472_config.xtal = 20500000; info.addr = 0x18; info.platform_data = &mn88472_config; request_module(info.type); diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c index 52de8f8..f648b58 100644 --- a/drivers/staging/media/mn88472/mn88472.c +++ b/drivers/staging/media/mn88472/mn88472.c @@ -30,6 +30,7 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_frequency = 0; + u64 tmp; u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; dev_dbg(&client->dev, @@ -62,17 +63,14 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) case SYS_DVBT2: if (c->bandwidth_hz <= 6000000) { /* IF 3570000 Hz, BW 6000000 Hz */ - memcpy(if_val, "\x2c\x94\xdb", 3); memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); bw_val2 = 0x02; } else if (c->bandwidth_hz <= 7000000) { /* IF 4570000 Hz, BW 7000000 Hz */ - memcpy(if_val, "\x39\x11\xbc", 3); memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); bw_val2 = 0x01; } else if (c->bandwidth_hz <= 8000000) { /* IF 4570000 Hz, BW 8000000 Hz */ - memcpy(if_val, "\x39\x11\xbc", 3); memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); bw_val2 = 0x00; } else { @@ -82,7 +80,6 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) break; case SYS_DVBC_ANNEX_A: /* IF 5070000 Hz, BW 8000000 Hz */ - memcpy(if_val, "\x3f\x50\x2c", 3); memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); bw_val2 = 0x00; break; @@ -106,17 +103,12 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); } - switch (if_frequency) { - case 3570000: - case 4570000: - case 5070000: - break; - default: - dev_err(&client->dev, "IF frequency %d not supported\n", - if_frequency); - ret = -EINVAL; - goto err; - } + /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ + tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), + dev->xtal); + if_val[0] = ((tmp >> 16) & 0xff); + if_val[1] = ((tmp >> 8) & 0xff); + if_val[2] = ((tmp >> 0) & 0xff); ret = regmap_write(dev->regmap[2], 0xfb, 0x13); ret = regmap_write(dev->regmap[2], 0xef, 0x13); @@ -411,6 +403,7 @@ static int mn88472_probe(struct i2c_client *client, } dev->i2c_wr_max = config->i2c_wr_max; + dev->xtal = config->xtal; dev->client[0] = client; dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); if (IS_ERR(dev->regmap[0])) { diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h index 1095949..b12b731 100644 --- a/drivers/staging/media/mn88472/mn88472_priv.h +++ b/drivers/staging/media/mn88472/mn88472_priv.h @@ -31,6 +31,7 @@ struct mn88472_dev { u16 i2c_wr_max; fe_delivery_system_t delivery_system; bool warm; /* FW running */ + u32 xtal; }; #endif -- cgit v0.10.2 From 645c7cea71a9b519cd9f98e45cbb923ef845b1b2 Mon Sep 17 00:00:00 2001 From: Benjamin Larsson Date: Wed, 26 Nov 2014 18:51:47 -0300 Subject: [media] mn88472: document demod reset Signed-off-by: Benjamin Larsson Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c index f648b58..36ef39b 100644 --- a/drivers/staging/media/mn88472/mn88472.c +++ b/drivers/staging/media/mn88472/mn88472.c @@ -190,6 +190,8 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) ret = regmap_write(dev->regmap[0], 0xae, 0x00); ret = regmap_write(dev->regmap[2], 0x08, 0x1d); ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); + + /* Reset demod */ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); if (ret) goto err; -- cgit v0.10.2 From bbfebeea7640973613c484f0281bdd15d68fd873 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:15 -0300 Subject: [media] em28xx: fix em28xx-input removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing the em28xx-rc module results in the following lockdep splat, which is caused by trying to call cancel_delayed_work_sync() on an uninitialised delayed work. Fix this by ensuring we always initialise the work. INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 0 PID: 2183 Comm: rmmod Not tainted 3.18.0+ #1464 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) Backtrace: [] (dump_backtrace) from [] (show_stack+0x18/0x1c) r6:c1419d2c r5:00000000 r4:00000000 r3:00000000 [] (show_stack) from [] (dump_stack+0x7c/0x98) [] (dump_stack) from [] (__lock_acquire+0x16d4/0x1bb0) r4:edf19f74 r3:df049380 [] (__lock_acquire) from [] (lock_acquire+0xb0/0x124) r10:00000000 r9:c003ba90 r8:00000000 r7:00000000 r6:00000000 r5:edf19f74 r4:00000000 [] (lock_acquire) from [] (flush_work+0x44/0x264) r10:00000000 r9:eaa86000 r8:edf190b0 r7:edf19f74 r6:00000001 r5:edf19f64 r4:00000000 [] (flush_work) from [] (__cancel_work_timer+0x8c/0x124) r7:00000000 r6:00000001 r5:00000000 r4:edf19f64 [] (__cancel_work_timer) from [] (cancel_delayed_work_sync+0x14/0x18) r7:00000000 r6:eccc3600 r5:00000000 r4:edf19000 [] (cancel_delayed_work_sync) from [] (em28xx_ir_fini+0x48/0xd8 [em28xx_rc]) [] (em28xx_ir_fini [em28xx_rc]) from [] (em28xx_unregister_extension+0x40/0x94 [em28xx]) r8:c000edc4 r7:00000081 r6:bf092bf4 r5:bf0b6a2c r4:edf19000 r3:bf0b5bc8 [] (em28xx_unregister_extension [em28xx]) from [] (em28xx_rc_unregister+0x14/0x1c [em28xx_rc]) r6:00000800 r5:00000000 r4:bf0b6a50 r3:bf0b64c8 [] (em28xx_rc_unregister [em28xx_rc]) from [] (SyS_delete_module+0x11c/0x180) [] (SyS_delete_module) from [] (ret_fast_syscall+0x0/0x48) r6:00000001 r5:beb0f813 r4:b8b17d00 Fixes: f52226099382 ("[media] em28xx: extend the support for device buttons") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index d8dc03a..ef36c49 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -654,8 +654,6 @@ next_button: if (dev->num_button_polling_addresses) { memset(dev->button_polling_last_values, 0, EM28XX_NUM_BUTTON_ADDRESSES_MAX); - INIT_DELAYED_WORK(&dev->buttons_query_work, - em28xx_query_buttons); schedule_delayed_work(&dev->buttons_query_work, msecs_to_jiffies(dev->button_polling_interval)); } @@ -689,6 +687,7 @@ static int em28xx_ir_init(struct em28xx *dev) } kref_get(&dev->ref); + INIT_DELAYED_WORK(&dev->buttons_query_work, em28xx_query_buttons); if (dev->board.buttons) em28xx_init_buttons(dev); -- cgit v0.10.2 From 0418ca6073478f54f1da2e4013fa50d36838de75 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:20 -0300 Subject: [media] em28xx: ensure "closing" messages terminate with a newline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lockdep splat addressed in a previous commit revealed that at least one message in em28xx-input.c was missing a new line: em28178 #0: Closing input extensionINFO: trying to register non-static key. Further inspection shows several other messages also miss a new line. These will be fixed in a subsequent patch. Fixes: aa929ad783c0 ("[media] em28xx: print a message at disconnect") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 44ae1e0..52dc9d7 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -981,7 +981,7 @@ static int em28xx_audio_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing audio extension"); + em28xx_info("Closing audio extension\n"); if (dev->adev.sndcard) { snd_card_disconnect(dev->adev.sndcard); diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9877b69..80c384c 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1724,7 +1724,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) if (!dev->dvb) return 0; - em28xx_info("Closing DVB extension"); + em28xx_info("Closing DVB extension\n"); dvb = dev->dvb; client = dvb->i2c_client_tuner; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index ef36c49..aea22de 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -832,7 +832,7 @@ static int em28xx_ir_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing input extension"); + em28xx_info("Closing input extension\n"); em28xx_shutdown_buttons(dev); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3691b39..eeb4ad5 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1958,7 +1958,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (v4l2 == NULL) return 0; - em28xx_info("Closing video extension"); + em28xx_info("Closing video extension\n"); mutex_lock(&dev->lock); -- cgit v0.10.2 From ebfd59cf549899a166d595bf1eab7eec3299ebe7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:26 -0300 Subject: [media] em28xx-input: fix missing newlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspection shows that newlines are missing from several kernel messages in em28xx-input. Fix these. Fixes: 5025076aadfe ("[media] em28xx-input: implement em28xx_ops: suspend/resume hooks") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index aea22de..4007356 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -861,7 +861,7 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (dev->is_audio_only) return 0; - em28xx_info("Suspending input extension"); + em28xx_info("Suspending input extension\n"); if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); @@ -878,7 +878,7 @@ static int em28xx_ir_resume(struct em28xx *dev) if (dev->is_audio_only) return 0; - em28xx_info("Resuming input extension"); + em28xx_info("Resuming input extension\n"); /* if suspend calls ir_raw_event_unregister(), the should call ir_raw_event_register() */ if (ir) -- cgit v0.10.2 From 522adc7c1f70d302155bb07f7fdf5a7fe4ff9094 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:31 -0300 Subject: [media] em28xx-core: fix missing newlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspection shows that newlines are missing from several kernel messages in em28xx-core. Fix these. Fixes: 9c669b731470 ("[media] em28xx: add suspend/resume to em28xx_ops") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 86461a7..3745607 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -1125,7 +1125,7 @@ int em28xx_suspend_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - em28xx_info("Suspending extensions"); + em28xx_info("Suspending extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) @@ -1139,7 +1139,7 @@ int em28xx_resume_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - em28xx_info("Resuming extensions"); + em28xx_info("Resuming extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) -- cgit v0.10.2 From 7818b0aab87b680fb10f68eccebeeb6cd8283c73 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:36 -0300 Subject: [media] em28xx-audio: fix missing newlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspection shows that newlines are missing from several kernel messages in em28xx-audio. Fix these. Fixes: 1b3fd2d34266 ("[media] em28xx-audio: don't hardcode audio URB calculus") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 52dc9d7..82d58eb 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -820,7 +820,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (urb_size > ep_size * npackets) npackets = DIV_ROUND_UP(urb_size, ep_size); - em28xx_info("Number of URBs: %d, with %d packets and %d size", + em28xx_info("Number of URBs: %d, with %d packets and %d size\n", num_urb, npackets, urb_size); /* Estimate the bytes per period */ -- cgit v0.10.2 From fbaa48d1853002c2e7bcf12c1fdc0f6fb16d1525 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:41 -0300 Subject: [media] em28xx-audio: fix missing newlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspection shows that newlines are missing from several kernel messages in em28xx-audio. Fix these. Fixes: 6d746f91f230 ("[media] em28xx-audio: implement em28xx_ops: suspend/resume hooks") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 82d58eb..49a5f95 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -1005,7 +1005,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - em28xx_info("Suspending audio extension"); + em28xx_info("Suspending audio extension\n"); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); return 0; @@ -1019,7 +1019,7 @@ static int em28xx_audio_resume(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - em28xx_info("Resuming audio extension"); + em28xx_info("Resuming audio extension\n"); /* Nothing to do other than schedule_work() ?? */ schedule_work(&dev->adev.wq_trigger); return 0; -- cgit v0.10.2 From a084c57fc1ccd24ef8e6ca41e75afa745d5dbb98 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:46 -0300 Subject: [media] em28xx-dvb: fix missing newlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspection shows that newlines are missing from several kernel messages in em28xx-dvb. Fix these. Fixes: ca2b46dacbf5 ("[media] em28xx-dvb: implement em28xx_ops: suspend/resume hooks") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 80c384c..aee70d4 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1775,17 +1775,17 @@ static int em28xx_dvb_suspend(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - em28xx_info("Suspending DVB extension"); + em28xx_info("Suspending DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_suspend(dvb->fe[0]); - em28xx_info("fe0 suspend %d", ret); + em28xx_info("fe0 suspend %d\n", ret); } if (dvb->fe[1]) { dvb_frontend_suspend(dvb->fe[1]); - em28xx_info("fe1 suspend %d", ret); + em28xx_info("fe1 suspend %d\n", ret); } } @@ -1802,18 +1802,18 @@ static int em28xx_dvb_resume(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - em28xx_info("Resuming DVB extension"); + em28xx_info("Resuming DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_resume(dvb->fe[0]); - em28xx_info("fe0 resume %d", ret); + em28xx_info("fe0 resume %d\n", ret); } if (dvb->fe[1]) { ret = dvb_frontend_resume(dvb->fe[1]); - em28xx_info("fe1 resume %d", ret); + em28xx_info("fe1 resume %d\n", ret); } } -- cgit v0.10.2 From 32e63f0368ed16e5ac417dc0bc2a5f8acbfb1511 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Dec 2014 09:45:51 -0300 Subject: [media] em28xx-video: fix missing newlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspection shows that newlines are missing from several kernel messages in em28xx-video. Fix these. Fixes: a61f68119af3 ("[media] em28xx-video: implement em28xx_ops: suspend/resume hooks") Cc: Signed-off-by: Russell King Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index eeb4ad5..9ecf656 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -2007,7 +2007,7 @@ static int em28xx_v4l2_suspend(struct em28xx *dev) if (!dev->has_video) return 0; - em28xx_info("Suspending video extension"); + em28xx_info("Suspending video extension\n"); em28xx_stop_urbs(dev); return 0; } @@ -2020,7 +2020,7 @@ static int em28xx_v4l2_resume(struct em28xx *dev) if (!dev->has_video) return 0; - em28xx_info("Resuming video extension"); + em28xx_info("Resuming video extension\n"); /* what do we do here */ return 0; } -- cgit v0.10.2 From ab93ce06eef556cc85a016e12ff7c7a763f04c91 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 11 Dec 2014 17:06:22 -0300 Subject: [media] rc: img-ir: add scancode requests to a struct The information being requested of hardware decode callbacks through the img-ir-hw scancode API is mounting up, so combine it into a struct which can be passed in with a single pointer rather than multiple pointer arguments. This allows it to be extended more easily without touching all the hardware decode callbacks. Signed-off-by: Sifan Naeem Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 2fd47c9..88fada5 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -806,20 +806,22 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) struct img_ir_priv_hw *hw = &priv->hw; const struct img_ir_decoder *dec = hw->decoder; int ret = IMG_IR_SCANCODE; - u32 scancode; - enum rc_type protocol = RC_TYPE_UNKNOWN; + struct img_ir_scancode_req request; + + request.protocol = RC_TYPE_UNKNOWN; if (dec->scancode) - ret = dec->scancode(len, raw, &protocol, &scancode, hw->enabled_protocols); + ret = dec->scancode(len, raw, hw->enabled_protocols, &request); else if (len >= 32) - scancode = (u32)raw; + request.scancode = (u32)raw; else if (len < 32) - scancode = (u32)raw & ((1 << len)-1); + request.scancode = (u32)raw & ((1 << len)-1); dev_dbg(priv->dev, "data (%u bits) = %#llx\n", len, (unsigned long long)raw); if (ret == IMG_IR_SCANCODE) { - dev_dbg(priv->dev, "decoded scan code %#x\n", scancode); - rc_keydown(hw->rdev, protocol, scancode, 0); + dev_dbg(priv->dev, "decoded scan code %#x\n", + request.scancode); + rc_keydown(hw->rdev, request.protocol, request.scancode, 0); img_ir_end_repeat(priv); } else if (ret == IMG_IR_REPEATCODE) { if (hw->mode == IMG_IR_M_REPEATING) { diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index 5c2b216..aeef3d1 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -133,6 +133,18 @@ struct img_ir_timing_regvals { #define IMG_IR_REPEATCODE 1 /* repeat the previous code */ /** + * struct img_ir_scancode_req - Scancode request data. + * @protocol: Protocol code of received message (defaults to + * RC_TYPE_UNKNOWN). + * @scancode: Scan code of received message (must be written by + * handler if IMG_IR_SCANCODE is returned). + */ +struct img_ir_scancode_req { + enum rc_type protocol; + u32 scancode; +}; + +/** * struct img_ir_decoder - Decoder settings for an IR protocol. * @type: Protocol types bitmap. * @tolerance: Timing tolerance as a percentage (default 10%). @@ -162,8 +174,8 @@ struct img_ir_decoder { struct img_ir_control control; /* scancode logic */ - int (*scancode)(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols); + int (*scancode)(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request); int (*filter)(const struct rc_scancode_filter *in, struct img_ir_filter *out, u64 protocols); }; diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c index a60dda8..d3e2fc0 100644 --- a/drivers/media/rc/img-ir/img-ir-jvc.c +++ b/drivers/media/rc/img-ir/img-ir-jvc.c @@ -12,8 +12,8 @@ #include "img-ir-hw.h" /* Convert JVC data to a scancode */ -static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int cust, data; @@ -23,8 +23,8 @@ static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol, cust = (raw >> 0) & 0xff; data = (raw >> 8) & 0xff; - *protocol = RC_TYPE_JVC; - *scancode = cust << 8 | data; + request->protocol = RC_TYPE_JVC; + request->scancode = cust << 8 | data; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c index 7398975..27a7ea8 100644 --- a/drivers/media/rc/img-ir/img-ir-nec.c +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -13,8 +13,8 @@ #include /* Convert NEC data to a scancode */ -static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int addr, addr_inv, data, data_inv; /* a repeat code has no data */ @@ -30,23 +30,23 @@ static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol, if ((data_inv ^ data) != 0xff) { /* 32-bit NEC (used by Apple and TiVo remotes) */ /* scan encoding: as transmitted, MSBit = first received bit */ - *scancode = bitrev8(addr) << 24 | - bitrev8(addr_inv) << 16 | - bitrev8(data) << 8 | - bitrev8(data_inv); + request->scancode = bitrev8(addr) << 24 | + bitrev8(addr_inv) << 16 | + bitrev8(data) << 8 | + bitrev8(data_inv); } else if ((addr_inv ^ addr) != 0xff) { /* Extended NEC */ /* scan encoding: AAaaDD */ - *scancode = addr << 16 | - addr_inv << 8 | - data; + request->scancode = addr << 16 | + addr_inv << 8 | + data; } else { /* Normal NEC */ /* scan encoding: AADD */ - *scancode = addr << 8 | - data; + request->scancode = addr << 8 | + data; } - *protocol = RC_TYPE_NEC; + request->protocol = RC_TYPE_NEC; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c index 6b0653e..f394994 100644 --- a/drivers/media/rc/img-ir/img-ir-sanyo.c +++ b/drivers/media/rc/img-ir/img-ir-sanyo.c @@ -23,8 +23,8 @@ #include "img-ir-hw.h" /* Convert Sanyo data to a scancode */ -static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int addr, addr_inv, data, data_inv; /* a repeat code has no data */ @@ -44,8 +44,8 @@ static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol, return -EINVAL; /* Normal Sanyo */ - *protocol = RC_TYPE_SANYO; - *scancode = addr << 8 | data; + request->protocol = RC_TYPE_SANYO; + request->scancode = addr << 8 | data; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c index 3300a38..fe5acc4 100644 --- a/drivers/media/rc/img-ir/img-ir-sharp.c +++ b/drivers/media/rc/img-ir/img-ir-sharp.c @@ -12,8 +12,8 @@ #include "img-ir-hw.h" /* Convert Sharp data to a scancode */ -static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int addr, cmd, exp, chk; @@ -32,8 +32,8 @@ static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol, /* probably the second half of the message */ return -EINVAL; - *protocol = RC_TYPE_SHARP; - *scancode = addr << 8 | cmd; + request->protocol = RC_TYPE_SHARP; + request->scancode = addr << 8 | cmd; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c index 3a0f17b..7f7375f 100644 --- a/drivers/media/rc/img-ir/img-ir-sony.c +++ b/drivers/media/rc/img-ir/img-ir-sony.c @@ -12,8 +12,8 @@ #include "img-ir-hw.h" /* Convert Sony data to a scancode */ -static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int dev, subdev, func; @@ -25,7 +25,7 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, raw >>= 7; dev = raw & 0x1f; /* next 5 bits */ subdev = 0; - *protocol = RC_TYPE_SONY12; + request->protocol = RC_TYPE_SONY12; break; case 15: if (!(enabled_protocols & RC_BIT_SONY15)) @@ -34,7 +34,7 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, raw >>= 7; dev = raw & 0xff; /* next 8 bits */ subdev = 0; - *protocol = RC_TYPE_SONY15; + request->protocol = RC_TYPE_SONY15; break; case 20: if (!(enabled_protocols & RC_BIT_SONY20)) @@ -44,12 +44,12 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, dev = raw & 0x1f; /* next 5 bits */ raw >>= 5; subdev = raw & 0xff; /* next 8 bits */ - *protocol = RC_TYPE_SONY20; + request->protocol = RC_TYPE_SONY20; break; default: return -EINVAL; } - *scancode = dev << 16 | subdev << 8 | func; + request->scancode = dev << 16 | subdev << 8 | func; return IMG_IR_SCANCODE; } -- cgit v0.10.2 From 33e01833268d2f006e599b863a21d4e219f96bd7 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 11 Dec 2014 17:06:23 -0300 Subject: [media] rc: img-ir: pass toggle bit to the rc driver Add toggle bit to struct img_ir_scancode_req so that protocols can provide it to img_ir_handle_data(), and pass that toggle bit up to rc_keydown instead of 0. This is needed for the upcoming rc-5 and rc-6 patches. Signed-off-by: Sifan Naeem Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 88fada5..9cecda7 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -809,6 +809,7 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) struct img_ir_scancode_req request; request.protocol = RC_TYPE_UNKNOWN; + request.toggle = 0; if (dec->scancode) ret = dec->scancode(len, raw, hw->enabled_protocols, &request); @@ -819,9 +820,10 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) dev_dbg(priv->dev, "data (%u bits) = %#llx\n", len, (unsigned long long)raw); if (ret == IMG_IR_SCANCODE) { - dev_dbg(priv->dev, "decoded scan code %#x\n", - request.scancode); - rc_keydown(hw->rdev, request.protocol, request.scancode, 0); + dev_dbg(priv->dev, "decoded scan code %#x, toggle %u\n", + request.scancode, request.toggle); + rc_keydown(hw->rdev, request.protocol, request.scancode, + request.toggle); img_ir_end_repeat(priv); } else if (ret == IMG_IR_REPEATCODE) { if (hw->mode == IMG_IR_M_REPEATING) { diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index aeef3d1..beac3a6 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -138,10 +138,12 @@ struct img_ir_timing_regvals { * RC_TYPE_UNKNOWN). * @scancode: Scan code of received message (must be written by * handler if IMG_IR_SCANCODE is returned). + * @toggle: Toggle bit (defaults to 0). */ struct img_ir_scancode_req { enum rc_type protocol; u32 scancode; + u8 toggle; }; /** -- cgit v0.10.2 From 02744c8c9a11a64bce740528077cf5223ab60e31 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 11 Dec 2014 17:06:24 -0300 Subject: [media] rc: img-ir: biphase enabled with workaround Biphase decoding in the current img-ir has got a quirk, where multiple Interrupts are generated when an incomplete IR code is received by the decoder. Patch adds a work around for the quirk and enables biphase decoding. Signed-off-by: Sifan Naeem Acked-by: James Hogan Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 9cecda7..5c32f05 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -52,6 +52,11 @@ static struct img_ir_decoder *img_ir_decoders[] = { #define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */ #define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */ +/* + * The decoder generates rapid interrupts without actually having + * received any new data after an incomplete IR code is decoded. + */ +#define IMG_IR_QUIRK_CODE_IRQ 0x4 /* functions for preprocessing timings, ensuring max is set */ @@ -542,6 +547,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, */ spin_unlock_irq(&priv->lock); del_timer_sync(&hw->end_timer); + del_timer_sync(&hw->suspend_timer); spin_lock_irq(&priv->lock); hw->stopping = false; @@ -861,6 +867,29 @@ static void img_ir_end_timer(unsigned long arg) spin_unlock_irq(&priv->lock); } +/* + * Timer function to re-enable the current protocol after it had been + * cleared when invalid interrupts were generated due to a quirk in the + * img-ir decoder. + */ +static void img_ir_suspend_timer(unsigned long arg) +{ + struct img_ir_priv *priv = (struct img_ir_priv *)arg; + + spin_lock_irq(&priv->lock); + /* + * Don't overwrite enabled valid/match IRQs if they have already been + * changed by e.g. a filter change. + */ + if ((priv->hw.quirk_suspend_irq & IMG_IR_IRQ_EDGE) == + img_ir_read(priv, IMG_IR_IRQ_ENABLE)) + img_ir_write(priv, IMG_IR_IRQ_ENABLE, + priv->hw.quirk_suspend_irq); + /* enable */ + img_ir_write(priv, IMG_IR_CONTROL, priv->hw.reg_timings.ctrl); + spin_unlock_irq(&priv->lock); +} + #ifdef CONFIG_COMMON_CLK static void img_ir_change_frequency(struct img_ir_priv *priv, struct clk_notifier_data *change) @@ -926,15 +955,38 @@ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status) if (!hw->decoder) return; + ct = hw->decoder->control.code_type; + ir_status = img_ir_read(priv, IMG_IR_STATUS); - if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) + if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) { + if (!(priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_IRQ) || + hw->stopping) + return; + /* + * The below functionality is added as a work around to stop + * multiple Interrupts generated when an incomplete IR code is + * received by the decoder. + * The decoder generates rapid interrupts without actually + * having received any new data. After a single interrupt it's + * expected to clear up, but instead multiple interrupts are + * rapidly generated. only way to get out of this loop is to + * reset the control register after a short delay. + */ + img_ir_write(priv, IMG_IR_CONTROL, 0); + hw->quirk_suspend_irq = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + img_ir_write(priv, IMG_IR_IRQ_ENABLE, + hw->quirk_suspend_irq & IMG_IR_IRQ_EDGE); + + /* Timer activated to re-enable the protocol. */ + mod_timer(&hw->suspend_timer, + jiffies + msecs_to_jiffies(5)); return; + } ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); img_ir_write(priv, IMG_IR_STATUS, ir_status); len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT; /* some versions report wrong length for certain code types */ - ct = hw->decoder->control.code_type; if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR) ++len; @@ -976,7 +1028,7 @@ static void img_ir_probe_hw_caps(struct img_ir_priv *priv) hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN] |= IMG_IR_QUIRK_CODE_LEN_INCR; hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE] - |= IMG_IR_QUIRK_CODE_BROKEN; + |= IMG_IR_QUIRK_CODE_IRQ; hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS] |= IMG_IR_QUIRK_CODE_BROKEN; } @@ -995,6 +1047,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv) /* Set up the end timer */ setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv); + setup_timer(&hw->suspend_timer, img_ir_suspend_timer, + (unsigned long)priv); /* Register a clock notifier */ if (!IS_ERR(priv->clk)) { diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index beac3a6..b31ffc9 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -218,6 +218,7 @@ enum img_ir_mode { * @rdev: Remote control device * @clk_nb: Notifier block for clock notify events. * @end_timer: Timer until repeat timeout. + * @suspend_timer: Timer to re-enable protocol. * @decoder: Current decoder settings. * @enabled_protocols: Currently enabled protocols. * @clk_hz: Current core clock rate in Hz. @@ -228,12 +229,14 @@ enum img_ir_mode { * @stopping: Indicates that decoder is being taken down and timers * should not be restarted. * @suspend_irqen: Saved IRQ enable mask over suspend. + * @quirk_suspend_irq: Saved IRQ enable mask over quirk suspend timer. */ struct img_ir_priv_hw { unsigned int ct_quirks[4]; struct rc_dev *rdev; struct notifier_block clk_nb; struct timer_list end_timer; + struct timer_list suspend_timer; const struct img_ir_decoder *decoder; u64 enabled_protocols; unsigned long clk_hz; @@ -244,6 +247,7 @@ struct img_ir_priv_hw { enum img_ir_mode mode; bool stopping; u32 suspend_irqen; + u32 quirk_suspend_irq; }; static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw) -- cgit v0.10.2 From aa7383db35aec23906868a632a964b5783a5254d Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 11 Dec 2014 17:06:25 -0300 Subject: [media] rc: img-ir: add philips rc5 decoder module Add img-ir module for decoding Philips rc5 protocol. Signed-off-by: Sifan Naeem Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 580715c..b20b3e9 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -60,3 +60,10 @@ config IR_IMG_SANYO help Say Y here to enable support for the Sanyo protocol (used by Sanyo, Aiwa, Chinon remotes) in the ImgTec infrared decoder block. + +config IR_IMG_RC5 + bool "Philips RC5 protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the RC5 protocol in the ImgTec + infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 92a459d..898b1b8 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -6,6 +6,7 @@ img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o +img-ir-$(CONFIG_IR_IMG_RC5) += img-ir-rc5.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 5c32f05..13f0b1e 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -42,6 +42,9 @@ static struct img_ir_decoder *img_ir_decoders[] = { #ifdef CONFIG_IR_IMG_SANYO &img_ir_sanyo, #endif +#ifdef CONFIG_IR_IMG_RC5 + &img_ir_rc5, +#endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index b31ffc9..b9e799d5 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -187,6 +187,7 @@ extern struct img_ir_decoder img_ir_jvc; extern struct img_ir_decoder img_ir_sony; extern struct img_ir_decoder img_ir_sharp; extern struct img_ir_decoder img_ir_sanyo; +extern struct img_ir_decoder img_ir_rc5; /** * struct img_ir_reg_timings - Reg values for decoder timings at clock rate. diff --git a/drivers/media/rc/img-ir/img-ir-rc5.c b/drivers/media/rc/img-ir/img-ir-rc5.c new file mode 100644 index 0000000..a8a28a3 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-rc5.c @@ -0,0 +1,88 @@ +/* + * ImgTec IR Decoder setup for Philips RC-5 protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "img-ir-hw.h" + +/* Convert RC5 data to a scancode */ +static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) +{ + unsigned int addr, cmd, tgl, start; + + /* Quirk in the decoder shifts everything by 2 to the left. */ + raw >>= 2; + + start = (raw >> 13) & 0x01; + tgl = (raw >> 11) & 0x01; + addr = (raw >> 6) & 0x1f; + cmd = raw & 0x3f; + /* + * 12th bit is used to extend the command in extended RC5 and has + * no effect on standard RC5. + */ + cmd += ((raw >> 12) & 0x01) ? 0 : 0x40; + + if (!start) + return -EINVAL; + + request->protocol = RC_TYPE_RC5; + request->scancode = addr << 8 | cmd; + request->toggle = tgl; + return IMG_IR_SCANCODE; +} + +/* Convert RC5 scancode to RC5 data filter */ +static int img_ir_rc5_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + /* Not supported by the hw. */ + return -EINVAL; +} + +/* + * RC-5 decoder + * see http://www.sbprojects.com/knowledge/ir/rc5.php + */ +struct img_ir_decoder img_ir_rc5 = { + .type = RC_BIT_RC5, + .control = { + .bitoriend2 = 1, + .code_type = IMG_IR_CODETYPE_BIPHASE, + .decodend2 = 1, + }, + /* main timings */ + .tolerance = 16, + .unit = 888888, /* 1/36k*32=888.888microseconds */ + .timings = { + /* 10 symbol */ + .s10 = { + .pulse = { 1 }, + .space = { 1 }, + }, + + /* 11 symbol */ + .s11 = { + .pulse = { 1 }, + .space = { 1 }, + }, + + /* free time */ + .ft = { + .minlen = 14, + .maxlen = 14, + .ft_min = 5, + }, + }, + + /* scancode logic */ + .scancode = img_ir_rc5_scancode, + .filter = img_ir_rc5_filter, +}; -- cgit v0.10.2 From cb9564e133f4f790920d715714790512085bb2e3 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 11 Dec 2014 17:06:26 -0300 Subject: [media] rc: img-ir: add philips rc6 decoder module Add img-ir module for decoding Philips rc6 protocol. Signed-off-by: Sifan Naeem Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index b20b3e9..a896d3c 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -67,3 +67,11 @@ config IR_IMG_RC5 help Say Y here to enable support for the RC5 protocol in the ImgTec infrared decoder block. + +config IR_IMG_RC6 + bool "Philips RC6 protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the RC6 protocol in the ImgTec + infrared decoder block. + Note: This version only supports mode 0. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 898b1b8..8e6d458 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -7,6 +7,7 @@ img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o img-ir-$(CONFIG_IR_IMG_RC5) += img-ir-rc5.o +img-ir-$(CONFIG_IR_IMG_RC6) += img-ir-rc6.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 13f0b1e..7bb71bc 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -45,6 +45,9 @@ static struct img_ir_decoder *img_ir_decoders[] = { #ifdef CONFIG_IR_IMG_RC5 &img_ir_rc5, #endif +#ifdef CONFIG_IR_IMG_RC6 + &img_ir_rc6, +#endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index b9e799d5..91a2977 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -188,6 +188,7 @@ extern struct img_ir_decoder img_ir_sony; extern struct img_ir_decoder img_ir_sharp; extern struct img_ir_decoder img_ir_sanyo; extern struct img_ir_decoder img_ir_rc5; +extern struct img_ir_decoder img_ir_rc6; /** * struct img_ir_reg_timings - Reg values for decoder timings at clock rate. diff --git a/drivers/media/rc/img-ir/img-ir-rc6.c b/drivers/media/rc/img-ir/img-ir-rc6.c new file mode 100644 index 0000000..de1e275 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-rc6.c @@ -0,0 +1,117 @@ +/* + * ImgTec IR Decoder setup for Philips RC-6 protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "img-ir-hw.h" + +/* Convert RC6 data to a scancode */ +static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) +{ + unsigned int addr, cmd, mode, trl1, trl2; + + /* + * Due to a side effect of the decoder handling the double length + * Trailer bit, the header information is a bit scrambled, and the + * raw data is shifted incorrectly. + * This workaround effectively recovers the header bits. + * + * The Header field should look like this: + * + * StartBit ModeBit2 ModeBit1 ModeBit0 TrailerBit + * + * But what we get is: + * + * ModeBit2 ModeBit1 ModeBit0 TrailerBit1 TrailerBit2 + * + * The start bit is not important to recover the scancode. + */ + + raw >>= 27; + + trl1 = (raw >> 17) & 0x01; + trl2 = (raw >> 16) & 0x01; + + mode = (raw >> 18) & 0x07; + addr = (raw >> 8) & 0xff; + cmd = raw & 0xff; + + /* + * Due to the above explained irregularity the trailer bits cannot + * have the same value. + */ + if (trl1 == trl2) + return -EINVAL; + + /* Only mode 0 supported for now */ + if (mode) + return -EINVAL; + + request->protocol = RC_TYPE_RC6_0; + request->scancode = addr << 8 | cmd; + request->toggle = trl2; + return IMG_IR_SCANCODE; +} + +/* Convert RC6 scancode to RC6 data filter */ +static int img_ir_rc6_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + /* Not supported by the hw. */ + return -EINVAL; +} + +/* + * RC-6 decoder + * see http://www.sbprojects.com/knowledge/ir/rc6.php + */ +struct img_ir_decoder img_ir_rc6 = { + .type = RC_BIT_RC6_0, + .control = { + .bitorien = 1, + .code_type = IMG_IR_CODETYPE_BIPHASE, + .decoden = 1, + .decodinpol = 1, + }, + /* main timings */ + .tolerance = 20, + /* + * Due to a quirk in the img-ir decoder, default header values do + * not work, the values described below were extracted from + * successful RTL test cases. + */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 650 }, + .space = { 660 }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 370 }, + .space = { 370 }, + }, + /* 01 symbol */ + .s01 = { + .pulse = { 370 }, + .space = { 370 }, + }, + /* free time */ + .ft = { + .minlen = 21, + .maxlen = 21, + .ft_min = 2666, /* 2.666 ms */ + }, + }, + + /* scancode logic */ + .scancode = img_ir_rc6_scancode, + .filter = img_ir_rc6_filter, +}; -- cgit v0.10.2 From 221ca91220a9a9efe27cde2ae4ef16e7dd44db69 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 10 Dec 2014 21:22:01 -0300 Subject: [media] staging: media: lirc: lirc_zilog.c: fix quoted strings split across lines checkpatch makes an exception to the 80-colum rule for quotes strings, and Documentation/CodingStyle recommends not splitting quotes strings across lines because it breaks the ability to grep for the string. Fixing these. WARNING: quoted string split across lines Signed-off-by: Luis de Bethencourt Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index cc872fb..0d29c8e 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -372,14 +372,14 @@ static int add_to_buf(struct IR *ir) ret); if (failures >= 3) { mutex_unlock(&ir->ir_lock); - dev_err(ir->l.dev, "unable to read from the IR chip " - "after 3 resets, giving up\n"); + dev_err(ir->l.dev, + "unable to read from the IR chip after 3 resets, giving up\n"); break; } /* Looks like the chip crashed, reset it */ - dev_err(ir->l.dev, "polling the IR receiver chip failed, " - "trying reset\n"); + dev_err(ir->l.dev, + "polling the IR receiver chip failed, trying reset\n"); set_current_state(TASK_UNINTERRUPTIBLE); if (kthread_should_stop()) { @@ -405,8 +405,9 @@ static int add_to_buf(struct IR *ir) ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); if (ret != sizeof(keybuf)) { - dev_err(ir->l.dev, "i2c_master_recv failed with %d -- " - "keeping last read buffer\n", ret); + dev_err(ir->l.dev, + "i2c_master_recv failed with %d -- keeping last read buffer\n", + ret); } else { rx->b[0] = keybuf[3]; rx->b[1] = keybuf[4]; @@ -713,8 +714,9 @@ static int send_boot_data(struct IR_tx *tx) buf[0]); return 0; } - dev_notice(tx->ir->l.dev, "Zilog/Hauppauge IR blaster firmware version " - "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); + dev_notice(tx->ir->l.dev, + "Zilog/Hauppauge IR blaster firmware version %d.%d.%d loaded\n", + buf[1], buf[2], buf[3]); return 0; } @@ -792,9 +794,9 @@ static int fw_load(struct IR_tx *tx) if (!read_uint8(&data, tx_data->endp, &version)) goto corrupt; if (version != 1) { - dev_err(tx->ir->l.dev, "unsupported code set file version (%u, expected" - "1) -- please upgrade to a newer driver", - version); + dev_err(tx->ir->l.dev, + "unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver", + version); fw_unload_locked(); ret = -EFAULT; goto out; @@ -981,8 +983,9 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret = get_key_data(data_block, code, key); if (ret == -EPROTO) { - dev_err(tx->ir->l.dev, "failed to get data for code %u, key %u -- check " - "lircd.conf entries\n", code, key); + dev_err(tx->ir->l.dev, + "failed to get data for code %u, key %u -- check lircd.conf entries\n", + code, key); return ret; } else if (ret != 0) return ret; @@ -1057,12 +1060,14 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret = i2c_master_send(tx->c, buf, 1); if (ret == 1) break; - dev_dbg(tx->ir->l.dev, "NAK expected: i2c_master_send " - "failed with %d (try %d)\n", ret, i+1); + dev_dbg(tx->ir->l.dev, + "NAK expected: i2c_master_send failed with %d (try %d)\n", + ret, i+1); } if (ret != 1) { - dev_err(tx->ir->l.dev, "IR TX chip never got ready: last i2c_master_send " - "failed with %d\n", ret); + dev_err(tx->ir->l.dev, + "IR TX chip never got ready: last i2c_master_send failed with %d\n", + ret); return ret < 0 ? ret : -EFAULT; } @@ -1165,12 +1170,12 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, */ if (ret != 0) { /* Looks like the chip crashed, reset it */ - dev_err(tx->ir->l.dev, "sending to the IR transmitter chip " - "failed, trying reset\n"); + dev_err(tx->ir->l.dev, + "sending to the IR transmitter chip failed, trying reset\n"); if (failures >= 3) { - dev_err(tx->ir->l.dev, "unable to send to the IR chip " - "after 3 resets, giving up\n"); + dev_err(tx->ir->l.dev, + "unable to send to the IR chip after 3 resets, giving up\n"); mutex_unlock(&ir->ir_lock); mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); @@ -1540,8 +1545,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Proceed only if the Rx client is also ready or not needed */ if (rx == NULL && !tx_only) { - dev_info(tx->ir->l.dev, "probe of IR Tx on %s (i2c-%d) done. Waiting" - " on IR Rx.\n", adap->name, adap->nr); + dev_info(tx->ir->l.dev, + "probe of IR Tx on %s (i2c-%d) done. Waiting on IR Rx.\n", + adap->name, adap->nr); goto out_ok; } } else { @@ -1579,8 +1585,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) "zilog-rx-i2c-%d", adap->nr); if (IS_ERR(rx->task)) { ret = PTR_ERR(rx->task); - dev_err(tx->ir->l.dev, "%s: could not start IR Rx polling thread" - "\n", __func__); + dev_err(tx->ir->l.dev, + "%s: could not start IR Rx polling thread\n", + __func__); /* Failed kthread, so put back the ir ref */ put_ir_device(ir, true); /* Failure exit, so put back rx ref from i2c_client */ @@ -1592,8 +1599,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Proceed only if the Tx client is also ready */ if (tx == NULL) { - pr_info("probe of IR Rx on %s (i2c-%d) done. Waiting" - " on IR Tx.\n", adap->name, adap->nr); + pr_info("probe of IR Rx on %s (i2c-%d) done. Waiting on IR Tx.\n", + adap->name, adap->nr); goto out_ok; } } -- cgit v0.10.2 From 2ecd424006d0e17c526a85e7d5ac4ace476b0dbb Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 10 Dec 2014 21:22:52 -0300 Subject: [media] staging: media: lirc: lirc_zilog.c: keep consistency in dev functions The previous patch switched some dev functions to move the string to a second line. Doing this for all similar functions because it makes the driver easier to read if all similar lines use the same criteria. Signed-off-by: Luis de Bethencourt Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 0d29c8e..20fa401 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -369,7 +369,7 @@ static int add_to_buf(struct IR *ir) ret = i2c_master_send(rx->c, sendbuf, 1); if (ret != 1) { dev_err(ir->l.dev, "i2c_master_send failed with %d\n", - ret); + ret); if (failures >= 3) { mutex_unlock(&ir->ir_lock); dev_err(ir->l.dev, @@ -412,8 +412,9 @@ static int add_to_buf(struct IR *ir) rx->b[0] = keybuf[3]; rx->b[1] = keybuf[4]; rx->b[2] = keybuf[5]; - dev_dbg(ir->l.dev, "key (0x%02x/0x%02x)\n", - rx->b[0], rx->b[1]); + dev_dbg(ir->l.dev, + "key (0x%02x/0x%02x)\n", + rx->b[0], rx->b[1]); } /* key pressed ? */ @@ -657,8 +658,8 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block) dev_dbg(tx->ir->l.dev, "%*ph", 5, buf); ret = i2c_master_send(tx->c, buf, tosend + 1); if (ret != tosend + 1) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", - ret); + dev_err(tx->ir->l.dev, + "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } i += tosend; @@ -711,7 +712,7 @@ static int send_boot_data(struct IR_tx *tx) } if ((buf[0] != 0x80) && (buf[0] != 0xa0)) { dev_err(tx->ir->l.dev, "unexpected IR TX init response: %02x\n", - buf[0]); + buf[0]); return 0; } dev_notice(tx->ir->l.dev, @@ -761,8 +762,9 @@ static int fw_load(struct IR_tx *tx) /* Request codeset data file */ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev); if (ret != 0) { - dev_err(tx->ir->l.dev, "firmware haup-ir-blaster.bin not available (%d)\n", - ret); + dev_err(tx->ir->l.dev, + "firmware haup-ir-blaster.bin not available (%d)\n", + ret); ret = ret < 0 ? ret : -EFAULT; goto out; } @@ -812,7 +814,7 @@ static int fw_load(struct IR_tx *tx) goto corrupt; dev_dbg(tx->ir->l.dev, "%u IR blaster codesets loaded\n", - tx_data->num_code_sets); + tx_data->num_code_sets); tx_data->code_sets = vmalloc( tx_data->num_code_sets * sizeof(char *)); @@ -942,8 +944,9 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, unsigned char buf[MAX_XFER_SIZE]; if (rbuf->chunk_size > sizeof(buf)) { - dev_err(ir->l.dev, "chunk_size is too big (%d)!\n", - rbuf->chunk_size); + dev_err(ir->l.dev, + "chunk_size is too big (%d)!\n", + rbuf->chunk_size); ret = -EINVAL; break; } @@ -966,8 +969,8 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, put_ir_rx(rx, false); set_current_state(TASK_RUNNING); - dev_dbg(ir->l.dev, "read result = %d (%s)\n", - ret, ret ? "Error" : "OK"); + dev_dbg(ir->l.dev, "read result = %d (%s)\n", ret, + ret ? "Error" : "OK"); return ret ? ret : written; } @@ -1079,7 +1082,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) } if (buf[0] != 0x80) { dev_err(tx->ir->l.dev, "unexpected IR TX response #2: %02x\n", - buf[0]); + buf[0]); return -EFAULT; } @@ -1231,7 +1234,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM); dev_dbg(ir->l.dev, "poll result = %s\n", - ret ? "POLLIN|POLLRDNORM" : "none"); + ret ? "POLLIN|POLLRDNORM" : "none"); return ret; } @@ -1338,7 +1341,8 @@ static int close(struct inode *node, struct file *filep) struct IR *ir = filep->private_data; if (ir == NULL) { - dev_err(ir->l.dev, "close: no private_data attached to the file!\n"); + dev_err(ir->l.dev, + "close: no private_data attached to the file!\n"); return -ENODEV; } @@ -1609,13 +1613,15 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->l.minor = minor; /* module option: user requested minor number */ ir->l.minor = lirc_register_driver(&ir->l); if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { - dev_err(tx->ir->l.dev, "%s: \"minor\" must be between 0 and %d (%d)!\n", - __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); + dev_err(tx->ir->l.dev, + "%s: \"minor\" must be between 0 and %d (%d)!\n", + __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); ret = -EBADRQC; goto out_put_xx; } - dev_info(ir->l.dev, "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", - adap->name, adap->nr, ir->l.minor); + dev_info(ir->l.dev, + "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", + adap->name, adap->nr, ir->l.minor); out_ok: if (rx != NULL) @@ -1623,8 +1629,9 @@ out_ok: if (tx != NULL) put_ir_tx(tx, true); put_ir_device(ir, true); - dev_info(ir->l.dev, "probe of IR %s on %s (i2c-%d) done\n", - tx_probe ? "Tx" : "Rx", adap->name, adap->nr); + dev_info(ir->l.dev, + "probe of IR %s on %s (i2c-%d) done\n", + tx_probe ? "Tx" : "Rx", adap->name, adap->nr); mutex_unlock(&ir_devices_lock); return 0; @@ -1636,9 +1643,9 @@ out_put_xx: out_put_ir: put_ir_device(ir, true); out_no_ir: - dev_err(&client->dev, "%s: probing IR %s on %s (i2c-%d) failed with %d\n", - __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, - ret); + dev_err(&client->dev, + "%s: probing IR %s on %s (i2c-%d) failed with %d\n", + __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, ret); mutex_unlock(&ir_devices_lock); return ret; } -- cgit v0.10.2 From 40b8a5a65aa3ba51a80f7bd667df8403d54d6e7a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 10 Dec 2014 21:23:42 -0300 Subject: [media] staging: media: lirc: lirc_zilog.c: missing newline in dev_err() Missing newline character at the end of string passed to dev_err() Signed-off-by: Luis de Bethencourt Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 20fa401..e16627c 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -797,7 +797,7 @@ static int fw_load(struct IR_tx *tx) goto corrupt; if (version != 1) { dev_err(tx->ir->l.dev, - "unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver", + "unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver\n", version); fw_unload_locked(); ret = -EFAULT; -- cgit v0.10.2 From 983c5bd26b86ba1c0d79b770e596bb8b77e42f32 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 8 Dec 2014 13:17:07 -0300 Subject: [media] rc-main: Re-apply filter for no-op protocol change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit da6e162d6a46 ("[media] rc-core: simplify sysfs code"), when the IR protocol is set using the sysfs interface to the same set of protocols that are already set, store_protocols() does not refresh the scancode filter with the new protocol, even if it has already called the change_protocol() callback successfully. This results in the filter being disabled in the hardware and not re-enabled until the filter is set again using sysfs. Fix in store_protocols() by still re-applying the filter whenever the change_protocol() driver callback succeeded. The problem can be reproduced with the img-ir driver by setting a filter, and then setting the protocol to the same protocol that is already set: $ echo nec > protocols $ echo 0xffff > filter_mask $ echo nec > protocols After this, messages which don't match the filter were still being received. Fixes: da6e162d6a46 ("[media] rc-core: simplify sysfs code") Reported-by: Sifan Naeem Signed-off-by: James Hogan Cc: David Härdeman Cc: # v3.17+ Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 86ffcd5..f8c5e47 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1021,16 +1021,16 @@ static ssize_t store_protocols(struct device *device, goto out; } - if (new_protocols == old_protocols) { - rc = len; - goto out; + if (new_protocols != old_protocols) { + *current_protocols = new_protocols; + IR_dprintk(1, "Protocols changed to 0x%llx\n", + (long long)new_protocols); } - *current_protocols = new_protocols; - IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols); - /* - * If the protocol is changed the filter needs updating. + * If a protocol change was attempted the filter may need updating, even + * if the actual protocol mask hasn't changed (since the driver may have + * cleared the filter). * Try setting the same filter with the new protocol (if any). * Fall back to clearing the filter. */ -- cgit v0.10.2 From 99f3cd52aee21091ce62442285a68873e3be833f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 15 Dec 2014 10:40:28 -0300 Subject: [media] vb2-vmalloc: Protect DMA-specific code by #ifdef CONFIG_HAS_DMA If NO_DMA=y: drivers/built-in.o: In function `vb2_vmalloc_dmabuf_ops_detach': videobuf2-vmalloc.c:(.text+0x6f11b0): undefined reference to `dma_unmap_sg' drivers/built-in.o: In function `vb2_vmalloc_dmabuf_ops_map': videobuf2-vmalloc.c:(.text+0x6f1266): undefined reference to `dma_unmap_sg' videobuf2-vmalloc.c:(.text+0x6f1282): undefined reference to `dma_map_sg' As we don't want to make the core VIDEOBUF2_VMALLOC depend on HAS_DMA (it's v4l2 core code, and selected by a lot of drivers), stub out the DMA support if HAS_DMA is not set. Signed-off-by: Geert Uytterhoeven Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 7f6d41b..bcde885 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -211,6 +211,7 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) return 0; } +#ifdef CONFIG_HAS_DMA /*********************************************/ /* DMABUF ops for exporters */ /*********************************************/ @@ -380,6 +381,8 @@ static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flag return dbuf; } +#endif /* CONFIG_HAS_DMA */ + /*********************************************/ /* callbacks for DMABUF buffers */ @@ -437,7 +440,9 @@ const struct vb2_mem_ops vb2_vmalloc_memops = { .put = vb2_vmalloc_put, .get_userptr = vb2_vmalloc_get_userptr, .put_userptr = vb2_vmalloc_put_userptr, +#ifdef CONFIG_HAS_DMA .get_dmabuf = vb2_vmalloc_get_dmabuf, +#endif .map_dmabuf = vb2_vmalloc_map_dmabuf, .unmap_dmabuf = vb2_vmalloc_unmap_dmabuf, .attach_dmabuf = vb2_vmalloc_attach_dmabuf, -- cgit v0.10.2 From dbe1b5ca26396b6c61d711c8ac4de13ebb02e9f6 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Wed, 24 Dec 2014 08:51:38 +1100 Subject: xfs: Make xfs_vn_rename compliant with renameat2() syscall To be able to support RENAME_EXCHANGE flag from renameat2() system call, XFS must have its inode_operations updated, exporting .rename2 method, instead of .rename. This patch just replaces the (now old) .rename method by .rename2, using the same infra-structure, but checking rename flags. Calls to .rename2 using RENAME_EXCHANGE flag, although now handled inside XFS, still return -EINVAL. RENAME_NOREPLACE is handled via VFS and we don't need to care about it inside xfs_vn_rename. Signed-off-by: Carlos Maiolino Reviewed-by: Brian Foster Signed-off-by: Dave Chinner diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index c50311c..abb838a 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -380,18 +380,23 @@ xfs_vn_rename( struct inode *odir, struct dentry *odentry, struct inode *ndir, - struct dentry *ndentry) + struct dentry *ndentry, + unsigned int flags) { struct inode *new_inode = ndentry->d_inode; struct xfs_name oname; struct xfs_name nname; + /* XFS does not support RENAME_EXCHANGE yet */ + if (flags & ~RENAME_NOREPLACE) + return -EINVAL; + xfs_dentry_to_name(&oname, odentry, 0); xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode); return xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), - XFS_I(ndir), &nname, new_inode ? - XFS_I(new_inode) : NULL); + XFS_I(ndir), &nname, + new_inode ? XFS_I(new_inode) : NULL); } /* @@ -1144,7 +1149,7 @@ static const struct inode_operations xfs_dir_inode_operations = { */ .rmdir = xfs_vn_unlink, .mknod = xfs_vn_mknod, - .rename = xfs_vn_rename, + .rename2 = xfs_vn_rename, .get_acl = xfs_get_acl, .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, @@ -1172,7 +1177,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { */ .rmdir = xfs_vn_unlink, .mknod = xfs_vn_mknod, - .rename = xfs_vn_rename, + .rename2 = xfs_vn_rename, .get_acl = xfs_get_acl, .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, -- cgit v0.10.2 From d31a1825450062b85282b4afed1c840fd306d012 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Wed, 24 Dec 2014 08:51:42 +1100 Subject: xfs: Add support to RENAME_EXCHANGE flag Adds a new function named xfs_cross_rename(), responsible for handling requests from sys_renameat2() using RENAME_EXCHANGE flag. Signed-off-by: Carlos Maiolino Reviewed-by: Brian Foster Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 41f804e..9916aef 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2656,6 +2656,124 @@ xfs_sort_for_rename( } /* + * xfs_cross_rename() + * + * responsible for handling RENAME_EXCHANGE flag in renameat2() sytemcall + */ +STATIC int +xfs_cross_rename( + struct xfs_trans *tp, + struct xfs_inode *dp1, + struct xfs_name *name1, + struct xfs_inode *ip1, + struct xfs_inode *dp2, + struct xfs_name *name2, + struct xfs_inode *ip2, + struct xfs_bmap_free *free_list, + xfs_fsblock_t *first_block, + int spaceres) +{ + int error = 0; + int ip1_flags = 0; + int ip2_flags = 0; + int dp2_flags = 0; + + /* Swap inode number for dirent in first parent */ + error = xfs_dir_replace(tp, dp1, name1, + ip2->i_ino, + first_block, free_list, spaceres); + if (error) + goto out; + + /* Swap inode number for dirent in second parent */ + error = xfs_dir_replace(tp, dp2, name2, + ip1->i_ino, + first_block, free_list, spaceres); + if (error) + goto out; + + /* + * If we're renaming one or more directories across different parents, + * update the respective ".." entries (and link counts) to match the new + * parents. + */ + if (dp1 != dp2) { + dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; + + if (S_ISDIR(ip2->i_d.di_mode)) { + error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot, + dp1->i_ino, first_block, + free_list, spaceres); + if (error) + goto out; + + /* transfer ip2 ".." reference to dp1 */ + if (!S_ISDIR(ip1->i_d.di_mode)) { + error = xfs_droplink(tp, dp2); + if (error) + goto out; + error = xfs_bumplink(tp, dp1); + if (error) + goto out; + } + + /* + * Although ip1 isn't changed here, userspace needs + * to be warned about the change, so that applications + * relying on it (like backup ones), will properly + * notify the change + */ + ip1_flags |= XFS_ICHGTIME_CHG; + ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; + } + + if (S_ISDIR(ip1->i_d.di_mode)) { + error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot, + dp2->i_ino, first_block, + free_list, spaceres); + if (error) + goto out; + + /* transfer ip1 ".." reference to dp2 */ + if (!S_ISDIR(ip2->i_d.di_mode)) { + error = xfs_droplink(tp, dp1); + if (error) + goto out; + error = xfs_bumplink(tp, dp2); + if (error) + goto out; + } + + /* + * Although ip2 isn't changed here, userspace needs + * to be warned about the change, so that applications + * relying on it (like backup ones), will properly + * notify the change + */ + ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; + ip2_flags |= XFS_ICHGTIME_CHG; + } + } + + if (ip1_flags) { + xfs_trans_ichgtime(tp, ip1, ip1_flags); + xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE); + } + if (ip2_flags) { + xfs_trans_ichgtime(tp, ip2, ip2_flags); + xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE); + } + if (dp2_flags) { + xfs_trans_ichgtime(tp, dp2, dp2_flags); + xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE); + } + xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE); +out: + return error; +} + +/* * xfs_rename */ int @@ -2665,7 +2783,8 @@ xfs_rename( xfs_inode_t *src_ip, xfs_inode_t *target_dp, struct xfs_name *target_name, - xfs_inode_t *target_ip) + xfs_inode_t *target_ip, + unsigned int flags) { xfs_trans_t *tp = NULL; xfs_mount_t *mp = src_dp->i_mount; @@ -2743,6 +2862,18 @@ xfs_rename( } /* + * Handle RENAME_EXCHANGE flags + */ + if (flags & RENAME_EXCHANGE) { + error = xfs_cross_rename(tp, src_dp, src_name, src_ip, + target_dp, target_name, target_ip, + &free_list, &first_block, spaceres); + if (error) + goto abort_return; + goto finish_rename; + } + + /* * Set up the target. */ if (target_ip == NULL) { @@ -2881,6 +3012,7 @@ xfs_rename( if (new_parent) xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); +finish_rename: /* * If this is a synchronous mount, make sure that the * rename transaction goes to disk before returning to diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 4ed2ba9..f772296 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -338,7 +338,7 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, struct xfs_inode *src_ip, struct xfs_inode *target_dp, struct xfs_name *target_name, - struct xfs_inode *target_ip); + struct xfs_inode *target_ip, unsigned int flags); void xfs_ilock(xfs_inode_t *, uint); int xfs_ilock_nowait(xfs_inode_t *, uint); diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index abb838a..ce80eeb 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -384,19 +384,23 @@ xfs_vn_rename( unsigned int flags) { struct inode *new_inode = ndentry->d_inode; + int omode = 0; struct xfs_name oname; struct xfs_name nname; - /* XFS does not support RENAME_EXCHANGE yet */ - if (flags & ~RENAME_NOREPLACE) + if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) return -EINVAL; - xfs_dentry_to_name(&oname, odentry, 0); + /* if we are exchanging files, we need to set i_mode of both files */ + if (flags & RENAME_EXCHANGE) + omode = ndentry->d_inode->i_mode; + + xfs_dentry_to_name(&oname, odentry, omode); xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode); return xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), XFS_I(ndir), &nname, - new_inode ? XFS_I(new_inode) : NULL); + new_inode ? XFS_I(new_inode) : NULL, flags); } /* -- cgit v0.10.2 From 96ab7954bca0eeedfb17094719db1351fba361d3 Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Wed, 24 Dec 2014 09:46:23 +1100 Subject: xfs: initialize log buf I/O completion wq on log alloc Log buffer I/O completion passes through the high priority m_log_workqueue rather than the default metadata buffer workqueue. The log buffer wq is initialized at I/O submission time. The log buffers are reused once initialized, however, so this is not necessary. Initialize the log buffer I/O completion workqueue pointers once when the log is allocated and log buffers initialized rather than on every log buffer I/O submission. Signed-off-by: Brian Foster Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index e408bf5..4f09e0f 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -1395,6 +1395,8 @@ xlog_alloc_log( ASSERT(xfs_buf_islocked(bp)); xfs_buf_unlock(bp); + /* use high priority wq for log I/O completion */ + bp->b_ioend_wq = mp->m_log_workqueue; bp->b_iodone = xlog_iodone; log->l_xbuf = bp; @@ -1427,6 +1429,8 @@ xlog_alloc_log( ASSERT(xfs_buf_islocked(bp)); xfs_buf_unlock(bp); + /* use high priority wq for log I/O completion */ + bp->b_ioend_wq = mp->m_log_workqueue; bp->b_iodone = xlog_iodone; iclog->ic_bp = bp; iclog->ic_data = bp->b_addr; @@ -1806,8 +1810,6 @@ xlog_sync( XFS_BUF_ZEROFLAGS(bp); XFS_BUF_ASYNC(bp); bp->b_flags |= XBF_SYNCIO; - /* use high priority completion wq */ - bp->b_ioend_wq = log->l_mp->m_log_workqueue; if (log->l_mp->m_flags & XFS_MOUNT_BARRIER) { bp->b_flags |= XBF_FUA; @@ -1856,8 +1858,6 @@ xlog_sync( bp->b_flags |= XBF_SYNCIO; if (log->l_mp->m_flags & XFS_MOUNT_BARRIER) bp->b_flags |= XBF_FUA; - /* use high priority completion wq */ - bp->b_ioend_wq = log->l_mp->m_log_workqueue; ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1); ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); -- cgit v0.10.2 From 77af574eef78c404ea630f7955a5ed0c926a63fe Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 24 Dec 2014 09:47:27 +1100 Subject: xfs: remove extra newlines from xfs messages xfs_warn() and friends add a newline by default, but some messages add another one. Particularly for the failing write message below, this can waste a lot of console real estate! Signed-off-by: Eric Sandeen Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 3f9bd58..925ead2 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -535,7 +535,7 @@ xfs_buf_item_push( if ((bp->b_flags & XBF_WRITE_FAIL) && ___ratelimit(&xfs_buf_write_fail_rl_state, "XFS:")) { xfs_warn(bp->b_target->bt_mount, -"Detected failing async write on buffer block 0x%llx. Retrying async write.\n", +"Detected failing async write on buffer block 0x%llx. Retrying async write.", (long long)bp->b_bn); } diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 4f09e0f..8fbbfb2 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -2027,7 +2027,7 @@ xlog_print_tic_res( " total reg = %u bytes (o/flow = %u bytes)\n" " ophdrs = %u (ophdr space = %u bytes)\n" " ophdr + reg = %u bytes\n" - " num regions = %u\n", + " num regions = %u", ((ticket->t_trans_type <= 0 || ticket->t_trans_type > XFS_TRANS_TYPE_MAX) ? "bad-trans-type" : trans_type_str[ticket->t_trans_type-1]), diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 19cbda1..22e6aca 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -685,7 +685,7 @@ xfs_blkdev_get( mp); if (IS_ERR(*bdevp)) { error = PTR_ERR(*bdevp); - xfs_warn(mp, "Invalid device [%s], error=%d\n", name, error); + xfs_warn(mp, "Invalid device [%s], error=%d", name, error); } return error; -- cgit v0.10.2 From 1a43ec03ddd40793db00dbc7340685f5accf6fc3 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 24 Dec 2014 09:48:35 +1100 Subject: xfs: Keep sb_bad_features2 consistent with sb_features2 Currently when we modify sb_features2, we store the same value also in sb_bad_features2. However in most places we forget to mark field sb_bad_features2 for logging and thus it can happen that a change to it is lost. This results in an inconsistent sb_features2 and sb_bad_features2 fields e.g. after xfstests test xfs/187. Fix the problem by changing XFS_SB_FEATURES2 to actually mean both sb_features2 and sb_bad_features2 fields since this is always what we want to log. This isn't ideal because the fact that XFS_SB_FEATURES2 means two fields could cause some problem in future however the code is hopefully less error prone that it is now. Signed-off-by: Jan Kara Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index fbd6da2..4762732 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -304,8 +304,8 @@ typedef enum { #define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT) #define XFS_SB_IFREE XFS_SB_MVAL(IFREE) #define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS) -#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2) -#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2) +#define XFS_SB_FEATURES2 (XFS_SB_MVAL(FEATURES2) | \ + XFS_SB_MVAL(BAD_FEATURES2)) #define XFS_SB_FEATURES_COMPAT XFS_SB_MVAL(FEATURES_COMPAT) #define XFS_SB_FEATURES_RO_COMPAT XFS_SB_MVAL(FEATURES_RO_COMPAT) #define XFS_SB_FEATURES_INCOMPAT XFS_SB_MVAL(FEATURES_INCOMPAT) @@ -319,9 +319,9 @@ typedef enum { XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \ - XFS_SB_BAD_FEATURES2 | XFS_SB_FEATURES_COMPAT | \ - XFS_SB_FEATURES_RO_COMPAT | XFS_SB_FEATURES_INCOMPAT | \ - XFS_SB_FEATURES_LOG_INCOMPAT | XFS_SB_PQUOTINO) + XFS_SB_FEATURES_COMPAT | XFS_SB_FEATURES_RO_COMPAT | \ + XFS_SB_FEATURES_INCOMPAT | XFS_SB_FEATURES_LOG_INCOMPAT | \ + XFS_SB_PQUOTINO) /* diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index d3d3883..71d2c97 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -678,7 +678,7 @@ xfs_mountfs( xfs_warn(mp, "correcting sb_features alignment problem"); sbp->sb_features2 |= sbp->sb_bad_features2; sbp->sb_bad_features2 = sbp->sb_features2; - mp->m_update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2; + mp->m_update_flags |= XFS_SB_FEATURES2; /* * Re-check for ATTR2 in case it was found in bad_features2 @@ -1436,8 +1436,7 @@ xfs_mount_log_sb( int error; ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | - XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2 | - XFS_SB_VERSIONNUM)); + XFS_SB_FEATURES2 | XFS_SB_VERSIONNUM)); tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0); -- cgit v0.10.2 From 700a3048aaa394b2a6d1468430f892151ce04a01 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 23 Dec 2014 17:06:43 -0600 Subject: livepatch: samples: fix usage example comments Fix a few typos in the livepatch-sample.c usage example comments and add some whitespace to make the comments a little more legible. Reported-by: Udo Seidel Signed-off-by: Josh Poimboeuf Signed-off-by: Jiri Kosina diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c index 21f159d..fb8c861 100644 --- a/samples/livepatch/livepatch-sample.c +++ b/samples/livepatch/livepatch-sample.c @@ -26,12 +26,16 @@ * kernel boot cmdline when /proc/cmdline is read. * * Example: + * * $ cat /proc/cmdline * + * * $ insmod livepatch-sample.ko * $ cat /proc/cmdline * this has been live patched - * $ echo 0 > /sys/kernel/livepatch/klp_sample/enabled + * + * $ echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled + * $ cat /proc/cmdline * */ -- cgit v0.10.2 From 1004b9f146940d280a0f62ca33d241469022bce7 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 23 Dec 2014 18:41:33 +0100 Subject: spi/fsl: unnecessary double init_completion removed The double call to init_completion(&mpc8xxx_spi->done); is not needed presumably this is a editing mistake only. Signed-off-by: Nicholas Mc Guire Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 446b737..9d3f9e0 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -102,8 +102,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, mpc8xxx_spi->rx_shift = 0; mpc8xxx_spi->tx_shift = 0; - init_completion(&mpc8xxx_spi->done); - master->bus_num = pdata->bus_num; master->num_chipselect = pdata->max_chipselect; -- cgit v0.10.2 From 90cc7f1cbbde49c0919953928c225c036ece0d9c Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 23 Dec 2014 11:04:41 +0200 Subject: ASoC: pcm: Fix vague codec and cpu DAI prepare error messages Both codec and cpu DAI prepare print the same error message making it a bit more difficult to grep quickly from sources. Fix this by telling it explicitly. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index eb87d96e2..0ae0e2a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -746,7 +746,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) codec_dai); if (ret < 0) { dev_err(codec_dai->dev, - "ASoC: DAI prepare error: %d\n", ret); + "ASoC: codec DAI prepare error: %d\n", + ret); goto out; } } @@ -755,8 +756,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n", - ret); + dev_err(cpu_dai->dev, + "ASoC: cpu DAI prepare error: %d\n", ret); goto out; } } -- cgit v0.10.2 From 85b88a8dd0c758464f31a9758deb27b31c0d5de7 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Tue, 23 Dec 2014 09:24:50 +0800 Subject: ASoC: Intel: Store the entry_point read from FW file To enable some modules from other than base FW, according to FW interface spec, we need pass the correct entry point param to FW, so here store the entry_point read from FW file for later usage. Signed-off-by: Jie Yang Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 4a5bde9..cad6ea1 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -497,6 +497,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, sst_module->sst_fw = sst_fw; sst_module->scratch_size = template->scratch_size; sst_module->persistent_size = template->persistent_size; + sst_module->entry = template->entry; INIT_LIST_HEAD(&sst_module->block_list); INIT_LIST_HEAD(&sst_module->runtime_list); -- cgit v0.10.2 From 6800b5ba154df5666f123b7d78161e1a9e6ad8ef Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 23 Dec 2014 10:27:54 +0800 Subject: ASoC: rt5677: Revise the filter powers Add the filter powers of the dac mono3 and mono4, and remove the connection of dac stereo1 filter that connect to DAC1 MIX. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 81fe146..a15e39d 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -2645,10 +2645,18 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { /* DAC Mixer */ SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2, RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("dac mono left filter", RT5677_PWR_DIG2, + SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2, RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("dac mono right filter", RT5677_PWR_DIG2, + SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2, RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0), SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)), @@ -3455,10 +3463,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" }, { "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" }, - { "DAC1 MIXL", NULL, "dac stereo1 filter" }, { "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" }, { "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" }, - { "DAC1 MIXR", NULL, "dac stereo1 filter" }, { "DAC1 FS", NULL, "DAC1 MIXL" }, { "DAC1 FS", NULL, "DAC1 MIXR" }, @@ -3530,30 +3536,34 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, { "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" }, { "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" }, - { "Mono DAC MIXL", NULL, "dac mono left filter" }, + { "Mono DAC MIXL", NULL, "dac mono2 left filter" }, { "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" }, { "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" }, { "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, { "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" }, - { "Mono DAC MIXR", NULL, "dac mono right filter" }, + { "Mono DAC MIXR", NULL, "dac mono2 right filter" }, { "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, { "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, { "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" }, { "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" }, + { "DD1 MIXL", NULL, "dac mono3 left filter" }, { "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, { "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, { "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" }, { "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" }, + { "DD1 MIXR", NULL, "dac mono3 right filter" }, { "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, { "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, { "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" }, { "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" }, + { "DD2 MIXL", NULL, "dac mono4 left filter" }, { "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, { "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, { "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" }, { "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" }, + { "DD2 MIXR", NULL, "dac mono4 right filter" }, { "Stereo DAC MIX", NULL, "Stereo DAC MIXL" }, { "Stereo DAC MIX", NULL, "Stereo DAC MIXR" }, -- cgit v0.10.2 From 5a8c7c2628f8d12e9bca6ab24f6718fc57728991 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 23 Dec 2014 10:27:55 +0800 Subject: ASoC: rt5677: Add the ASRC support Add the ASRC support Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index a15e39d..66abfa3 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -921,6 +921,97 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } +static int is_using_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + + if (source->reg == RT5677_ASRC_1) { + switch (source->shift) { + case 12: + reg = RT5677_ASRC_4; + shift = 0; + break; + case 13: + reg = RT5677_ASRC_4; + shift = 4; + break; + case 14: + reg = RT5677_ASRC_4; + shift = 8; + break; + case 15: + reg = RT5677_ASRC_4; + shift = 12; + break; + default: + return 0; + } + } else { + switch (source->shift) { + case 0: + reg = RT5677_ASRC_6; + shift = 8; + break; + case 1: + reg = RT5677_ASRC_6; + shift = 12; + break; + case 2: + reg = RT5677_ASRC_5; + shift = 0; + break; + case 3: + reg = RT5677_ASRC_5; + shift = 4; + break; + case 4: + reg = RT5677_ASRC_5; + shift = 8; + break; + case 5: + reg = RT5677_ASRC_5; + shift = 12; + break; + case 12: + reg = RT5677_ASRC_3; + shift = 0; + break; + case 13: + reg = RT5677_ASRC_3; + shift = 4; + break; + case 14: + reg = RT5677_ASRC_3; + shift = 12; + break; + default: + return 0; + } + } + + val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; + switch (val) { + case 1 ... 6: + return 1; + default: + return 0; + } + +} + +static int can_use_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + + if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384) + return 1; + + return 0; +} + /* Digital Mixer */ static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, @@ -2215,6 +2306,45 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL2", RT5677_PWR_ANLG2, RT5677_PWR_PLL2_BIT, 0, rt5677_set_pll2_event, SND_SOC_DAPM_POST_PMU), + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5677_ASRC_1, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5677_ASRC_1, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5677_ASRC_1, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S4 ASRC", 1, RT5677_ASRC_1, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5677_ASRC_2, 14, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO2 L ASRC", 1, RT5677_ASRC_2, 13, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO2 R ASRC", 1, RT5677_ASRC_2, 12, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO3 L ASRC", 1, RT5677_ASRC_1, 15, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO3 R ASRC", 1, RT5677_ASRC_1, 14, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO4 L ASRC", 1, RT5677_ASRC_1, 13, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO4 R ASRC", 1, RT5677_ASRC_1, 12, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5677_ASRC_2, 11, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5677_ASRC_2, 10, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO3 ASRC", 1, RT5677_ASRC_2, 9, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO4 ASRC", 1, RT5677_ASRC_2, 8, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5677_ASRC_2, 7, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5677_ASRC_2, 6, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5677_ASRC_2, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5677_ASRC_2, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO3 ASRC", 1, RT5677_ASRC_2, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO4 ASRC", 1, RT5677_ASRC_2, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5677_ASRC_2, 1, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5677_ASRC_2, 0, 0, NULL, + 0), + /* Input Side */ /* micbias */ SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5677_PWR_ANLG2, RT5677_PWR_MB1_BIT, @@ -2729,6 +2859,31 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { + { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc }, + { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc }, + { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc }, + { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc }, + { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc }, + { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc }, + { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, + { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, + { "I2S3", NULL, "I2S3 ASRC", can_use_asrc}, + { "I2S4", NULL, "I2S4 ASRC", can_use_asrc}, + + { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc }, + { "dac mono2 left filter", NULL, "DAC MONO2 L ASRC", is_using_asrc }, + { "dac mono2 right filter", NULL, "DAC MONO2 R ASRC", is_using_asrc }, + { "dac mono3 left filter", NULL, "DAC MONO3 L ASRC", is_using_asrc }, + { "dac mono3 right filter", NULL, "DAC MONO3 R ASRC", is_using_asrc }, + { "dac mono4 left filter", NULL, "DAC MONO4 L ASRC", is_using_asrc }, + { "dac mono4 right filter", NULL, "DAC MONO4 R ASRC", is_using_asrc }, + { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, + { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, + { "adc stereo3 filter", NULL, "ADC STO3 ASRC", is_using_asrc }, + { "adc stereo4 filter", NULL, "ADC STO4 ASRC", is_using_asrc }, + { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc }, + { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc }, + { "DMIC1", NULL, "DMIC L1" }, { "DMIC1", NULL, "DMIC R1" }, { "DMIC2", NULL, "DMIC L2" }, -- cgit v0.10.2 From 38d595e2e09ede17712b2d4909339e691fff3f85 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 23 Dec 2014 10:27:56 +0800 Subject: ASoC: rt5677: Adjust the routing of "PLL1" Remove the duplicated PLL1 connections of the adc stereo filters, and remove the PLL1 connections of the DACs because the PLL1 should be connected to dac filters. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 66abfa3..cf39fe6 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3014,8 +3014,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, - { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -3036,8 +3034,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" }, { "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" }, - { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, { "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" }, { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -3052,8 +3048,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" }, { "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" }, - { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" }, { "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" }, { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -3068,8 +3062,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" }, { "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" }, - { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" }, { "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" }, { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -3686,39 +3678,46 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, { "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" }, { "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + { "dac stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" }, { "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, { "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" }, { "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" }, { "Mono DAC MIXL", NULL, "dac mono2 left filter" }, + { "dac mono2 left filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" }, { "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" }, { "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, { "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" }, { "Mono DAC MIXR", NULL, "dac mono2 right filter" }, + { "dac mono2 right filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, { "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, { "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" }, { "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" }, { "DD1 MIXL", NULL, "dac mono3 left filter" }, + { "dac mono3 left filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, { "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, { "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" }, { "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" }, { "DD1 MIXR", NULL, "dac mono3 right filter" }, + { "dac mono3 right filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, { "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, { "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" }, { "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" }, { "DD2 MIXL", NULL, "dac mono4 left filter" }, + { "dac mono4 left filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, { "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, { "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" }, { "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" }, { "DD2 MIXR", NULL, "dac mono4 right filter" }, + { "dac mono4 right filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Stereo DAC MIX", NULL, "Stereo DAC MIXL" }, { "Stereo DAC MIX", NULL, "Stereo DAC MIXR" }, @@ -3740,11 +3739,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" }, { "DAC 1", NULL, "DAC12 SRC Mux" }, - { "DAC 1", NULL, "PLL1", is_sys_clk_from_pll }, { "DAC 2", NULL, "DAC12 SRC Mux" }, - { "DAC 2", NULL, "PLL1", is_sys_clk_from_pll }, { "DAC 3", NULL, "DAC3 SRC Mux" }, - { "DAC 3", NULL, "PLL1", is_sys_clk_from_pll }, { "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" }, { "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" }, -- cgit v0.10.2 From 549858ce76e31d5e2139e5588df976ee42607a0d Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Mon, 22 Dec 2014 11:35:16 -0800 Subject: spi: img-spfi: Select FIFO based on transfer length Since the 32-bit FIFO is deeper (64 bytes) than the 8-bit FIFO (16 bytes), use the 32-bit FIFO when there are at least 32 bits remaining to be transferred in PIO mode or when the transfer length is 32-bit aligned in DMA mode. Signed-off-by: Andrew Bresticker Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index aad6683..c01567d 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -160,16 +160,16 @@ static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, unsigned int count = 0; u32 status; - while (count < max) { + while (count < max / 4) { spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); if (status & SPFI_INTERRUPT_SDFUL) break; - spfi_writel(spfi, buf[count / 4], SPFI_TX_32BIT_VALID_DATA); - count += 4; + spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA); + count++; } - return count; + return count * 4; } static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf, @@ -196,17 +196,17 @@ static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf, unsigned int count = 0; u32 status; - while (count < max) { + while (count < max / 4) { spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT, SPFI_INTERRUPT_CLEAR); status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); if (!(status & SPFI_INTERRUPT_GDEX32BIT)) break; - buf[count / 4] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); - count += 4; + buf[count] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); + count++; } - return count; + return count * 4; } static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf, @@ -251,17 +251,15 @@ static int img_spfi_start_pio(struct spi_master *master, time_before(jiffies, timeout)) { unsigned int tx_count, rx_count; - switch (xfer->bits_per_word) { - case 32: + if (tx_bytes >= 4) tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes); - rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); - break; - case 8: - default: + else tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes); + + if (rx_bytes >= 4) + rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); + else rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes); - break; - } tx_buf += tx_count; rx_buf += rx_count; @@ -331,14 +329,11 @@ static int img_spfi_start_dma(struct spi_master *master, if (xfer->rx_buf) { rxconf.direction = DMA_DEV_TO_MEM; - switch (xfer->bits_per_word) { - case 32: + if (xfer->len % 4 == 0) { rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; rxconf.src_addr_width = 4; rxconf.src_maxburst = 4; - break; - case 8: - default: + } else { rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; rxconf.src_addr_width = 1; rxconf.src_maxburst = 4; @@ -358,18 +353,14 @@ static int img_spfi_start_dma(struct spi_master *master, if (xfer->tx_buf) { txconf.direction = DMA_MEM_TO_DEV; - switch (xfer->bits_per_word) { - case 32: + if (xfer->len % 4 == 0) { txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; txconf.dst_addr_width = 4; txconf.dst_maxburst = 4; - break; - case 8: - default: + } else { txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; txconf.dst_addr_width = 1; txconf.dst_maxburst = 4; - break; } dmaengine_slave_config(spfi->tx_ch, &txconf); @@ -508,9 +499,7 @@ static void img_spfi_set_cs(struct spi_device *spi, bool enable) static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { - if (xfer->bits_per_word == 8 && xfer->len > SPFI_8BIT_FIFO_SIZE) - return true; - if (xfer->bits_per_word == 32 && xfer->len > SPFI_32BIT_FIFO_SIZE) + if (xfer->len > SPFI_32BIT_FIFO_SIZE) return true; return false; } -- cgit v0.10.2 From 3110628d89f80fbafa085fd62e75afcb39fb764c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 19 Dec 2014 17:15:53 +0900 Subject: spi: sh-msiof: Configure MSIOF sync signal timing in device tree The MSIOF controller has DTDL and SYNCDL in SITMDR1 register. So, this patch adds new properties like the following commit: d0fb47a5237d8b9576113568bacfd27892308b62 (spi: fsl-espi: Configure FSL eSPI CSBEF and CSAFT) Signed-off-by: Yoshihiro Shimoda Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index d11c372..4c388bb 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -30,6 +30,22 @@ Optional properties: specifiers, one for transmission, and one for reception. - dma-names : Must contain a list of two DMA names, "tx" and "rx". +- renesas,dtdl : delay sync signal (setup) in transmit mode. + Must contain one of the following values: + 0 (no bit delay) + 50 (0.5-clock-cycle delay) + 100 (1-clock-cycle delay) + 150 (1.5-clock-cycle delay) + 200 (2-clock-cycle delay) + +- renesas,syncdl : delay sync signal (hold) in transmit mode. + Must contain one of the following values: + 0 (no bit delay) + 50 (0.5-clock-cycle delay) + 100 (1-clock-cycle delay) + 150 (1.5-clock-cycle delay) + 200 (2-clock-cycle delay) + 300 (3-clock-cycle delay) Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 239be7c..2a87cb9 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -82,6 +82,8 @@ struct sh_msiof_spi_priv { #define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ #define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ #define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ +#define MDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */ +#define MDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */ #define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */ #define MDR1_FLD_SHIFT 2 #define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ @@ -279,6 +281,48 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); } +static u32 sh_msiof_get_delay_bit(u32 dtdl_or_syncdl) +{ + /* + * DTDL/SYNCDL bit : p->info->dtdl or p->info->syncdl + * b'000 : 0 + * b'001 : 100 + * b'010 : 200 + * b'011 (SYNCDL only) : 300 + * b'101 : 50 + * b'110 : 150 + */ + if (dtdl_or_syncdl % 100) + return dtdl_or_syncdl / 100 + 5; + else + return dtdl_or_syncdl / 100; +} + +static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p) +{ + u32 val; + + if (!p->info) + return 0; + + /* check if DTDL and SYNCDL is allowed value */ + if (p->info->dtdl > 200 || p->info->syncdl > 300) { + dev_warn(&p->pdev->dev, "DTDL or SYNCDL is too large\n"); + return 0; + } + + /* check if the sum of DTDL and SYNCDL becomes an integer value */ + if ((p->info->dtdl + p->info->syncdl) % 100) { + dev_warn(&p->pdev->dev, "the sum of DTDL/SYNCDL is not good\n"); + return 0; + } + + val = sh_msiof_get_delay_bit(p->info->dtdl) << MDR1_DTDL_SHIFT; + val |= sh_msiof_get_delay_bit(p->info->syncdl) << MDR1_SYNCDL_SHIFT; + + return val; +} + static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 cpol, u32 cpha, u32 tx_hi_z, u32 lsb_first, u32 cs_high) @@ -296,6 +340,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; + tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { /* These bits are reserved if RX needs TX */ @@ -952,6 +997,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) &info->tx_fifo_override); of_property_read_u32(np, "renesas,rx-fifo-size", &info->rx_fifo_override); + of_property_read_u32(np, "renesas,dtdl", &info->dtdl); + of_property_read_u32(np, "renesas,syncdl", &info->syncdl); info->num_chipselect = num_cs; diff --git a/include/linux/spi/sh_msiof.h b/include/linux/spi/sh_msiof.h index 88a14d8..b087a85 100644 --- a/include/linux/spi/sh_msiof.h +++ b/include/linux/spi/sh_msiof.h @@ -7,6 +7,8 @@ struct sh_msiof_spi_info { u16 num_chipselect; unsigned int dma_tx_id; unsigned int dma_rx_id; + u32 dtdl; + u32 syncdl; }; #endif /* __SPI_SH_MSIOF_H__ */ -- cgit v0.10.2 From 0425e2420c0ab1b5da24f6d9fce39241ad85fc46 Mon Sep 17 00:00:00 2001 From: Flora Fu Date: Fri, 5 Dec 2014 12:07:54 +0800 Subject: regulator: mt6397: Add support for MT6397 regulator Add MT6397 regulator driver. Signed-off-by: Flora Fu Signed-off-by: Mark Brown diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c3a60b5..f622d06 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -433,6 +433,15 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MT6397 + tristate "MediaTek MT6397 PMIC" + depends on MFD_MT6397 + help + Say y here to select this option to enable the power regulator of + MediaTek MT6397 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_PALMAS tristate "TI Palmas PMIC Regulators" depends on MFD_PALMAS diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 1f28ebf..1a0fbc3 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c new file mode 100644 index 0000000..a5b2f47 --- /dev/null +++ b/drivers/regulator/mt6397-regulator.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Flora Fu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MT6397 regulators' information + * + * @desc: standard fields of regulator description. + * @qi: Mask for query enable signal status of regulators + * @vselon_reg: Register sections for hardware control mode of bucks + * @vselctrl_reg: Register for controlling the buck control mode. + * @vselctrl_mask: Mask for query buck's voltage control mode. + */ +struct mt6397_regulator_info { + struct regulator_desc desc; + u32 qi; + u32 vselon_reg; + u32 vselctrl_reg; + u32 vselctrl_mask; +}; + +#define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ + vosel, vosel_mask, voselon, vosel_ctrl) \ +[MT6397_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6397_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6397_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = (max - min)/step + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(0), \ + }, \ + .qi = BIT(13), \ + .vselon_reg = voselon, \ + .vselctrl_reg = vosel_ctrl, \ + .vselctrl_mask = BIT(1), \ +} + +#define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ + vosel_mask) \ +[MT6397_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6397_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6397_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .volt_table = ldo_volt_table, \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + }, \ + .qi = BIT(15), \ +} + +#define MT6397_REG_FIXED(match, vreg, enreg, enbit, volt) \ +[MT6397_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6397_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6397_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + .min_uV = volt, \ + }, \ + .qi = BIT(15), \ +} + +static const struct regulator_linear_range buck_volt_range1[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range2[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range3[] = { + REGULATOR_LINEAR_RANGE(1500000, 0, 0x1f, 20000), +}; + +static const u32 ldo_volt_table1[] = { + 1500000, 1800000, 2500000, 2800000, +}; + +static const u32 ldo_volt_table2[] = { + 1800000, 3300000, +}; + +static const u32 ldo_volt_table3[] = { + 3000000, 3300000, +}; + +static const u32 ldo_volt_table4[] = { + 1220000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table5[] = { + 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table5_v2[] = { + 1200000, 1000000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table6[] = { + 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000, +}; + +static const u32 ldo_volt_table7[] = { + 1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000, +}; + +static int mt6397_get_status(struct regulator_dev *rdev) +{ + int ret; + u32 regval; + struct mt6397_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->desc.enable_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; +} + +static struct regulator_ops mt6397_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6397_get_status, +}; + +static struct regulator_ops mt6397_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6397_get_status, +}; + +static struct regulator_ops mt6397_volt_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6397_get_status, +}; + +/* The array is indexed by id(MT6397_ID_XXX) */ +static struct mt6397_regulator_info mt6397_regulators[] = { + MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f, + MT6397_VCA15_CON10, MT6397_VCA15_CON5), + MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f, + MT6397_VPCA7_CON10, MT6397_VPCA7_CON5), + MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9, + 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5), + MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9, + 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5), + MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f, + MT6397_VCORE_CON10, MT6397_VCORE_CON5), + MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1, + MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f, + MT6397_VGPU_CON10, MT6397_VGPU_CON5), + MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2, + MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f, + MT6397_VDRM_CON10, MT6397_VDRM_CON5), + MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000, + buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f, + MT6397_VIO18_CON10, MT6397_VIO18_CON5), + MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000), + MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000), + MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1, + MT6397_ANALDO_CON2, 15, MT6397_ANALDO_CON6, 0xC0), + MT6397_REG_FIXED("ldo_vio28", VIO28, MT6397_DIGLDO_CON0, 14, 2800000), + MT6397_REG_FIXED("ldo_vusb", VUSB, MT6397_DIGLDO_CON1, 14, 3300000), + MT6397_LDO("ldo_vmc", VMC, ldo_volt_table2, + MT6397_DIGLDO_CON2, 12, MT6397_DIGLDO_CON29, 0x10), + MT6397_LDO("ldo_vmch", VMCH, ldo_volt_table3, + MT6397_DIGLDO_CON3, 14, MT6397_DIGLDO_CON17, 0x80), + MT6397_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table3, + MT6397_DIGLDO_CON4, 14, MT6397_DIGLDO_CON18, 0x10), + MT6397_LDO("ldo_vgp1", VGP1, ldo_volt_table4, + MT6397_DIGLDO_CON5, 15, MT6397_DIGLDO_CON19, 0xE0), + MT6397_LDO("ldo_vgp2", VGP2, ldo_volt_table5, + MT6397_DIGLDO_CON6, 15, MT6397_DIGLDO_CON20, 0xE0), + MT6397_LDO("ldo_vgp3", VGP3, ldo_volt_table5, + MT6397_DIGLDO_CON7, 15, MT6397_DIGLDO_CON21, 0xE0), + MT6397_LDO("ldo_vgp4", VGP4, ldo_volt_table5, + MT6397_DIGLDO_CON8, 15, MT6397_DIGLDO_CON22, 0xE0), + MT6397_LDO("ldo_vgp5", VGP5, ldo_volt_table6, + MT6397_DIGLDO_CON9, 15, MT6397_DIGLDO_CON23, 0xE0), + MT6397_LDO("ldo_vgp6", VGP6, ldo_volt_table5, + MT6397_DIGLDO_CON10, 15, MT6397_DIGLDO_CON33, 0xE0), + MT6397_LDO("ldo_vibr", VIBR, ldo_volt_table7, + MT6397_DIGLDO_CON24, 15, MT6397_DIGLDO_CON25, 0xE00), +}; + +static int mt6397_set_buck_vosel_reg(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + int i; + u32 regval; + + for (i = 0; i < MT6397_MAX_REGULATOR; i++) { + if (mt6397_regulators[i].vselctrl_reg) { + if (regmap_read(mt6397->regmap, + mt6397_regulators[i].vselctrl_reg, + ®val) < 0) { + dev_err(&pdev->dev, + "Failed to read buck ctrl\n"); + return -EIO; + } + + if (regval & mt6397_regulators[i].vselctrl_mask) { + mt6397_regulators[i].desc.vsel_reg = + mt6397_regulators[i].vselon_reg; + } + } + } + + return 0; +} + +static int mt6397_regulator_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + struct regulator_dev *rdev; + int i; + u32 reg_value, version; + + /* Query buck controller to select activated voltage register part */ + if (mt6397_set_buck_vosel_reg(pdev)) + return -EIO; + + /* Read PMIC chip revision to update constraints and voltage table */ + if (regmap_read(mt6397->regmap, MT6397_CID, ®_value) < 0) { + dev_err(&pdev->dev, "Failed to read Chip ID\n"); + return -EIO; + } + dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value); + + version = (reg_value & 0xFF); + switch (version) { + case MT6397_REGULATOR_ID91: + mt6397_regulators[MT6397_ID_VGP2].desc.volt_table = + ldo_volt_table5_v2; + break; + default: + break; + } + + for (i = 0; i < MT6397_MAX_REGULATOR; i++) { + config.dev = &pdev->dev; + config.driver_data = &mt6397_regulators[i]; + config.regmap = mt6397->regmap; + rdev = devm_regulator_register(&pdev->dev, + &mt6397_regulators[i].desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mt6397_regulators[i].desc.name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static struct platform_driver mt6397_regulator_driver = { + .driver = { + .name = "mt6397-regulator", + }, + .probe = mt6397_regulator_probe, +}; + +module_platform_driver(mt6397_regulator_driver); + +MODULE_AUTHOR("Flora Fu "); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mt6397-regulator"); diff --git a/include/linux/regulator/mt6397-regulator.h b/include/linux/regulator/mt6397-regulator.h new file mode 100644 index 0000000..30cc596 --- /dev/null +++ b/include/linux/regulator/mt6397-regulator.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Flora Fu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_REGULATOR_MT6397_H +#define __LINUX_REGULATOR_MT6397_H + +enum { + MT6397_ID_VPCA15 = 0, + MT6397_ID_VPCA7, + MT6397_ID_VSRAMCA15, + MT6397_ID_VSRAMCA7, + MT6397_ID_VCORE, + MT6397_ID_VGPU, + MT6397_ID_VDRM, + MT6397_ID_VIO18 = 7, + MT6397_ID_VTCXO, + MT6397_ID_VA28, + MT6397_ID_VCAMA, + MT6397_ID_VIO28, + MT6397_ID_VUSB, + MT6397_ID_VMC, + MT6397_ID_VMCH, + MT6397_ID_VEMC3V3, + MT6397_ID_VGP1, + MT6397_ID_VGP2, + MT6397_ID_VGP3, + MT6397_ID_VGP4, + MT6397_ID_VGP5, + MT6397_ID_VGP6, + MT6397_ID_VIBR, + MT6397_ID_RG_MAX, +}; + +#define MT6397_MAX_REGULATOR MT6397_ID_RG_MAX +#define MT6397_REGULATOR_ID97 0x97 +#define MT6397_REGULATOR_ID91 0x91 + +#endif /* __LINUX_REGULATOR_MT6397_H */ -- cgit v0.10.2 From 2696757579010d5480018e8466973531aa22e56e Mon Sep 17 00:00:00 2001 From: Flora Fu Date: Fri, 5 Dec 2014 12:07:57 +0800 Subject: regulator: Add document for MT6397 regulator Signed-off-by: Flora Fu Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt new file mode 100644 index 0000000..a42b1d6 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt @@ -0,0 +1,217 @@ +Mediatek MT6397 Regulator Driver + +Required properties: +- compatible: "mediatek,mt6397-regulator" +- mt6397regulator: List of regulators provided by this controller. It is named + according to its regulator type, buck_ and ldo_. + The definition for each of these nodes is defined using the standard binding + for regulators at Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are:: +BUCK: + buck_vpca15, buck_vpca7, buck_vsramca15, buck_vsramca7, buck_vcore, buck_vgpu, + buck_vdrm, buck_vio18 +LDO: + ldo_vtcxo, ldo_va28, ldo_vcama, ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, + ldo_vemc3v3, ldo_vgp1, ldo_vgp2, ldo_vgp3, ldo_vgp4, ldo_vgp5, ldo_vgp6, + ldo_vibr + +Example: + pmic { + compatible = "mediatek,mt6397"; + + mt6397regulator: mt6397regulator { + compatible = "mediatek,mt6397-regulator"; + + mt6397_vpca15_reg: buck_vpca15 { + regulator-compatible = "buck_vpca15"; + regulator-name = "vpca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <200>; + }; + + mt6397_vpca7_reg: buck_vpca7 { + regulator-compatible = "buck_vpca7"; + regulator-name = "vpca7"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vsramca15_reg: buck_vsramca15 { + regulator-compatible = "buck_vsramca15"; + regulator-name = "vsramca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + + }; + + mt6397_vsramca7_reg: buck_vsramca7 { + regulator-compatible = "buck_vsramca7"; + regulator-name = "vsramca7"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + + }; + + mt6397_vcore_reg: buck_vcore { + regulator-compatible = "buck_vcore"; + regulator-name = "vcore"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vgpu_reg: buck_vgpu { + regulator-compatible = "buck_vgpu"; + regulator-name = "vgpu"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vdrm_reg: buck_vdrm { + regulator-compatible = "buck_vdrm"; + regulator-name = "vdrm"; + regulator-min-microvolt = < 800000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <500>; + }; + + mt6397_vio18_reg: buck_vio18 { + regulator-compatible = "buck_vio18"; + regulator-name = "vio18"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2120000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <500>; + }; + + mt6397_vtcxo_reg: ldo_vtcxo { + regulator-compatible = "ldo_vtcxo"; + regulator-name = "vtcxo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <90>; + }; + + mt6397_va28_reg: ldo_va28 { + regulator-compatible = "ldo_va28"; + regulator-name = "va28"; + /* fixed output 2.8 V */ + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vcama_reg: ldo_vcama { + regulator-compatible = "ldo_vcama"; + regulator-name = "vcama"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vio28_reg: ldo_vio28 { + regulator-compatible = "ldo_vio28"; + regulator-name = "vio28"; + /* fixed output 2.8 V */ + regulator-enable-ramp-delay = <240>; + }; + + mt6397_usb_reg: ldo_vusb { + regulator-compatible = "ldo_vusb"; + regulator-name = "vusb"; + /* fixed output 3.3 V */ + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vmc_reg: ldo_vmc { + regulator-compatible = "ldo_vmc"; + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vmch_reg: ldo_vmch { + regulator-compatible = "ldo_vmch"; + regulator-name = "vmch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vemc_3v3_reg: ldo_vemc3v3 { + regulator-compatible = "ldo_vemc3v3"; + regulator-name = "vemc_3v3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp1_reg: ldo_vgp1 { + regulator-compatible = "ldo_vgp1"; + regulator-name = "vcamd"; + regulator-min-microvolt = <1220000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <240>; + }; + + mt6397_vgp2_reg: ldo_vgp2 { + egulator-compatible = "ldo_vgp2"; + regulator-name = "vcamio"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp3_reg: ldo_vgp3 { + regulator-compatible = "ldo_vgp3"; + regulator-name = "vcamaf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp4_reg: ldo_vgp4 { + regulator-compatible = "ldo_vgp4"; + regulator-name = "vgp4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp5_reg: ldo_vgp5 { + regulator-compatible = "ldo_vgp5"; + regulator-name = "vgp5"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp6_reg: ldo_vgp6 { + regulator-compatible = "ldo_vgp6"; + regulator-name = "vgp6"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vibr_reg: ldo_vibr { + regulator-compatible = "ldo_vibr"; + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + }; + }; -- cgit v0.10.2 From bba1431211e6fdc56680d98d2bdabaab1fd13b79 Mon Sep 17 00:00:00 2001 From: Jianqun Xu Date: Wed, 24 Dec 2014 17:37:01 +0800 Subject: ASoC: rockchip: i2s: set TDL and RDL to 16 samples Set Transmit Data Level(TDL) and Receive Data Level(RDL) to 16 samples. Without this setting, the TDL is default to be 0x00 (means 0 sample), and the RDL is default to be 0x1f (means 32 samples). Signed-off-by: Jianqun Xu Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 26ec511..dac0002 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -247,6 +247,10 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val); regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val); + regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, + I2S_DMACR_TDL(16)); + regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, + I2S_DMACR_RDL(16)); return 0; } -- cgit v0.10.2 From 53aebb7f19b71df6cf5aace87609b88cfc1c87ec Mon Sep 17 00:00:00 2001 From: Beomho Seo Date: Thu, 18 Dec 2014 20:13:36 +0900 Subject: regulator: rt5033-regulator: Use regulator_nodes/of_match in the descriptor This patch is add regulator_nodes/of_match in the regulator descriptor for using information from DT instead of sppecific codes. Cc: Liam Girdwood Cc: Mark Brown Signed-off-by: Beomho Seo Signed-off-by: Mark Brown diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c index 870cc49..96d2c18 100644 --- a/drivers/regulator/rt5033-regulator.c +++ b/drivers/regulator/rt5033-regulator.c @@ -36,6 +36,8 @@ static struct regulator_ops rt5033_buck_ops = { static const struct regulator_desc rt5033_supported_regulators[] = { [RT5033_BUCK] = { .name = "BUCK", + .of_match = of_match_ptr("BUCK"), + .regulators_node = of_match_ptr("regulators"), .id = RT5033_BUCK, .ops = &rt5033_buck_ops, .type = REGULATOR_VOLTAGE, @@ -50,6 +52,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = { }, [RT5033_LDO] = { .name = "LDO", + .of_match = of_match_ptr("LDO"), + .regulators_node = of_match_ptr("regulators"), .id = RT5033_LDO, .ops = &rt5033_buck_ops, .type = REGULATOR_VOLTAGE, @@ -64,6 +68,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = { }, [RT5033_SAFE_LDO] = { .name = "SAFE_LDO", + .of_match = of_match_ptr("SAFE_LDO"), + .regulators_node = of_match_ptr("regulators"), .id = RT5033_SAFE_LDO, .ops = &rt5033_safe_ldo_ops, .type = REGULATOR_VOLTAGE, @@ -81,7 +87,7 @@ static int rt5033_regulator_probe(struct platform_device *pdev) int ret, i; struct regulator_config config = {}; - config.dev = &pdev->dev; + config.dev = rt5033->dev; config.driver_data = rt5033; for (i = 0; i < ARRAY_SIZE(rt5033_supported_regulators); i++) { -- cgit v0.10.2 From 0628ee7c81a8ced9b10f9ee300707f7f79fdecf1 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Sun, 21 Dec 2014 22:36:37 -0500 Subject: libata: s/ata_id_removeable()/ata_id_removable()/ Changes the spelling typos of removeable to removable where ata_id_removeable is defined in ata.h and called in libata-scsi.c respectively. Signed-off-by: Nicholas Krause Signed-off-by: Tejun Heo diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e364e86..7659d64 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1995,8 +1995,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) VPRINTK("ENTER\n"); - /* set scsi removeable (RMB) bit per ata bit */ - if (ata_id_removeable(args->id)) + /* set scsi removable (RMB) bit per ata bit */ + if (ata_id_removable(args->id)) hdr[1] |= (1 << 7); if (args->dev->class == ATA_DEV_ZAC) { diff --git a/include/linux/ata.h b/include/linux/ata.h index f2f4d8d..1648026 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -503,7 +503,7 @@ struct ata_bmdma_prd { #define ata_id_has_dma(id) ((id)[ATA_ID_CAPABILITY] & (1 << 8)) #define ata_id_has_ncq(id) ((id)[ATA_ID_SATA_CAPABILITY] & (1 << 8)) #define ata_id_queue_depth(id) (((id)[ATA_ID_QUEUE_DEPTH] & 0x1f) + 1) -#define ata_id_removeable(id) ((id)[ATA_ID_CONFIG] & (1 << 7)) +#define ata_id_removable(id) ((id)[ATA_ID_CONFIG] & (1 << 7)) #define ata_id_has_atapi_AN(id) \ ((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \ ((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \ -- cgit v0.10.2 From ebd8146bba4d1716e2e47cbd5583f6836eeafb48 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sat, 20 Dec 2014 17:46:02 +0100 Subject: ALSA: ice1712: wm8776.c: Remove some unused functions Removes some functions that are not used anywhere: snd_wm8776_set_master_mode() snd_wm8776_set_adc_if() snd_wm8776_set_dac_if() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c index e66c0da..ebd2fe4 100644 --- a/sound/pci/ice1712/wm8776.c +++ b/sound/pci/ice1712/wm8776.c @@ -452,21 +452,6 @@ void snd_wm8776_resume(struct snd_wm8776 *wm) snd_wm8776_write(wm, i, wm->regs[i]); } -void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac) -{ - snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac); -} - -void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc) -{ - snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc); -} - -void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode) -{ - snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode); -} - void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power) { snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power); diff --git a/sound/pci/ice1712/wm8776.h b/sound/pci/ice1712/wm8776.h index 93a2d69..42acef0 100644 --- a/sound/pci/ice1712/wm8776.h +++ b/sound/pci/ice1712/wm8776.h @@ -216,9 +216,6 @@ struct snd_wm8776 { void snd_wm8776_init(struct snd_wm8776 *wm); void snd_wm8776_resume(struct snd_wm8776 *wm); -void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac); -void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc); -void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode); void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power); void snd_wm8776_volume_restore(struct snd_wm8776 *wm); int snd_wm8776_build_controls(struct snd_wm8776 *wm); -- cgit v0.10.2 From 57da6bdd4823ad70ac58c5cd968943a4be95d739 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 21 Dec 2014 13:35:12 +0100 Subject: ALSA: hda - patch_analog.c: Remove some unused functions Removes some functions that are not used anywhere: ad198x_ch_mode_get() ad198x_ch_mode_info() ad198x_ch_mode_info() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index a9d78e2..d285904 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -739,39 +739,6 @@ static int patch_ad1981(struct hda_codec *codec) * E/F quad mic array */ -#ifdef ENABLE_AD_STATIC_QUIRKS -static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, spec->multiout.max_channels); -} - -static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return err; -} -#endif /* ENABLE_AD_STATIC_QUIRKS */ - static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { -- cgit v0.10.2 From eb58d4844b4ee797bbefa6a75db3a999b71209b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 26 Dec 2014 12:22:35 +0100 Subject: ALSA: gus: Remove unused gus_instr.c The instrument layer codes have been dropped years ago, but this file was left intentionally with a slight hope for the new implementations. But, looking at the reality, the probability we'll have a new code for ISA GUS board is very low, and I won't bet it. So, rather clean this legacy stuff up. Developers can still refer to the old code via git history. Reported-by: Rickard Strandqvist Signed-off-by: Takashi Iwai diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c deleted file mode 100644 index 4dc9caf..0000000 --- a/sound/isa/gus/gus_instr.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Routines for Gravis UltraSound soundcards - Synthesizer - * Copyright (c) by Jaroslav Kysela - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include - -/* - * - */ - -int snd_gus_iwffff_put_sample(void *private_data, struct iwffff_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - struct snd_gf1_mem_block *block; - int err; - - if (wave->format & IWFFFF_WAVE_ROM) - return 0; /* it's probably ok - verify the address? */ - if (wave->format & IWFFFF_WAVE_STEREO) - return -EINVAL; /* not supported */ - block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF, - NULL, wave->size, - wave->format & IWFFFF_WAVE_16BIT, 1, - wave->share_id); - if (block == NULL) - return -ENOMEM; - err = snd_gus_dram_write(gus, data, - block->ptr, wave->size); - if (err < 0) { - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0); - snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block); - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1); - return err; - } - wave->address.memory = block->ptr; - return 0; -} - -int snd_gus_iwffff_get_sample(void *private_data, struct iwffff_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, - wave->format & IWFFFF_WAVE_ROM ? 1 : 0); -} - -int snd_gus_iwffff_remove_sample(void *private_data, struct iwffff_wave *wave, - int atomic) -{ - struct snd_gus_card *gus = private_data; - - if (wave->format & IWFFFF_WAVE_ROM) - return 0; /* it's probably ok - verify the address? */ - return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory); -} - -/* - * - */ - -int snd_gus_gf1_put_sample(void *private_data, struct gf1_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - struct snd_gf1_mem_block *block; - int err; - - if (wave->format & GF1_WAVE_STEREO) - return -EINVAL; /* not supported */ - block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_WAVE_GF1, - NULL, wave->size, - wave->format & GF1_WAVE_16BIT, 1, - wave->share_id); - if (block == NULL) - return -ENOMEM; - err = snd_gus_dram_write(gus, data, - block->ptr, wave->size); - if (err < 0) { - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0); - snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block); - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1); - return err; - } - wave->address.memory = block->ptr; - return 0; -} - -int snd_gus_gf1_get_sample(void *private_data, struct gf1_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0); -} - -int snd_gus_gf1_remove_sample(void *private_data, struct gf1_wave *wave, - int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory); -} - -/* - * - */ - -int snd_gus_simple_put_sample(void *private_data, struct simple_instrument *instr, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - struct snd_gf1_mem_block *block; - int err; - - if (instr->format & SIMPLE_WAVE_STEREO) - return -EINVAL; /* not supported */ - block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE, - NULL, instr->size, - instr->format & SIMPLE_WAVE_16BIT, 1, - instr->share_id); - if (block == NULL) - return -ENOMEM; - err = snd_gus_dram_write(gus, data, block->ptr, instr->size); - if (err < 0) { - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0); - snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block); - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1); - return err; - } - instr->address.memory = block->ptr; - return 0; -} - -int snd_gus_simple_get_sample(void *private_data, struct simple_instrument *instr, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0); -} - -int snd_gus_simple_remove_sample(void *private_data, struct simple_instrument *instr, - int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory); -} -- cgit v0.10.2 From ea3651fee6c92a29244830334979396465ed8587 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 14 Nov 2014 14:19:03 -0800 Subject: PCI: keystone: Fix error handling of irq_of_parse_and_map() Return value of irq_of_parse_and_map() is unsigned int, with 0 indicating failure, so testing for negative result never works. Signed-off-by: Dmitry Torokhov Signed-off-by: Bjorn Helgaas Acked-By: Murali Karicheri diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 78f79e3..23a1d97 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -197,7 +197,7 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, */ for (temp = 0; temp < max_host_irqs; temp++) { host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp); - if (host_irqs[temp] < 0) + if (!host_irqs[temp]) break; } if (temp) { -- cgit v0.10.2 From c51d411fe1e5f5f378b4db6b10dbe89e2e8688e4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 14 Nov 2014 14:21:53 -0800 Subject: PCI: rcar: Fix error handling of irq_of_parse_and_map() Return value of irq_of_parse_and_map() is unsigned int, with 0 indicating failure, so testing for negative result never works. Signed-off-by: Dmitry Torokhov Signed-off-by: Bjorn Helgaas Acked-by: Phil Edworthy diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 748786c..b258744 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -757,7 +757,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev, goto err_map_reg; i = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (i < 0) { + if (!i) { dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); err = -ENOENT; goto err_map_reg; @@ -765,7 +765,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev, pcie->msi.irq1 = i; i = irq_of_parse_and_map(pdev->dev.of_node, 1); - if (i < 0) { + if (!i) { dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); err = -ENOENT; goto err_map_reg; -- cgit v0.10.2 From 80f6d910dc46f4df91a6f0a52d94e025c053987b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 18 Nov 2014 17:18:20 +0100 Subject: PCI: layerscape: Fix platform_no_drv_owner.cocci warnings No need to set .owner here. The core will do it. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Julia Lawall Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index 6697b1a..68c9e5e 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -167,7 +167,6 @@ MODULE_DEVICE_TABLE(of, ls_pcie_of_match); static struct platform_driver ls_pcie_driver = { .driver = { .name = "layerscape-pcie", - .owner = THIS_MODULE, .of_match_table = ls_pcie_of_match, }, }; -- cgit v0.10.2 From 19bd9c0b98372fceeec507383f7cb54f4fa51b12 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 13 Nov 2014 20:37:37 +0100 Subject: PCI: tegra: Remove unnecessary tegra_pcie_fixup_bridge() The bridge setup is already done by generic code while scanning the buses. Do not duplicate (or potentially alter) this setup as a fixup. Tested-by: Alexandre Courbot Reviewed-by: Thierry Reding Tested-by: Thierry Reding Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Thierry Reding diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index a800ae9..6f9c29f 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -625,19 +625,6 @@ static void tegra_pcie_port_free(struct tegra_pcie_port *port) devm_kfree(pcie->dev, port); } -static void tegra_pcie_fixup_bridge(struct pci_dev *dev) -{ - u16 reg; - - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) { - pci_read_config_word(dev, PCI_COMMAND, ®); - reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_SERR); - pci_write_config_word(dev, PCI_COMMAND, reg); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge); - /* Tegra PCIE root complex wrongly reports device class */ static void tegra_pcie_fixup_class(struct pci_dev *dev) { -- cgit v0.10.2 From 04dae5509c0573fbdab52766a14da5dd60c29a6f Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 13 Nov 2014 20:37:37 +0100 Subject: PCI: tegra: Remove unnecessary tegra_pcie_fixup_bridge() The bridge setup is already done by generic code while scanning the buses. Do not duplicate (or potentially alter) this setup as a fixup. Tested-by: Alexandre Courbot Tested-by: Thierry Reding Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Reviewed-by: Thierry Reding Acked-by: Thierry Reding diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index a800ae9..6f9c29f 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -625,19 +625,6 @@ static void tegra_pcie_port_free(struct tegra_pcie_port *port) devm_kfree(pcie->dev, port); } -static void tegra_pcie_fixup_bridge(struct pci_dev *dev) -{ - u16 reg; - - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) { - pci_read_config_word(dev, PCI_COMMAND, ®); - reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_SERR); - pci_write_config_word(dev, PCI_COMMAND, reg); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge); - /* Tegra PCIE root complex wrongly reports device class */ static void tegra_pcie_fixup_class(struct pci_dev *dev) { -- cgit v0.10.2 From 17f14b51f2dc2fce2636ee49c5fbf49ff27aecb0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 26 Dec 2014 16:28:08 -0700 Subject: PCI: Delete unnecessary NULL pointer checks The pci_dev_put() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index a5a7fd8..46db293 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -214,8 +214,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); - if (slot->dev) - pci_dev_put(slot->dev); + pci_dev_put(slot->dev); kfree(slot); } -- cgit v0.10.2 From 270384ccfc2ba3849b9d02f7a37c395987c30ed2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 26 Dec 2014 14:27:58 +0100 Subject: ALSA: atmel: fix building the ac97 driver for at91-multiplatform at91 will no longer export the mach/cpu.h and mach/hardware.h header files in the future, which would break building the atmel ac97c driver. Since the cpu_is_* check is only used to find out whether we are running on avr32 or arm/at91, we can hardcode that check in the ARM case. Signed-off-by: Arnd Bergmann Link: http://www.spinics.net/lists/arm-kernel/msg382068.html Signed-off-by: Alexandre Belloni Signed-off-by: Takashi Iwai diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 4f6b14d..5e6a1db 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -34,10 +34,10 @@ #include #include +#ifdef CONFIG_AVR32 #include - -#ifdef CONFIG_ARCH_AT91 -#include +#else +#define cpu_is_at32ap7000() 0 #endif #include "ac97c.h" -- cgit v0.10.2 From 7c674700098c87b305b99652e3c694c4ef195866 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Sat, 27 Dec 2014 18:19:12 -0700 Subject: PCI: Move domain assignment from arm64 to generic code The current logic in arm64 pci_bus_assign_domain_nr() is flawed in that depending on the host controller configuration for a platform and the initialization sequence, core code may end up allocating PCI domain numbers from both DT and the generic domain counter, which would result in PCI domain allocation aliases/errors. Fix the logic behind the PCI domain number assignment and move the resulting code to the PCI core so the same domain allocation logic is used on all platforms that select CONFIG_PCI_DOMAINS_GENERIC. [bhelgaas: tidy changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Liviu Dudau Acked-by: Arnd Bergmann CC: Rob Herring CC: Catalin Marinas diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index ce5836c..6f93c24 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -46,25 +46,3 @@ int pcibios_add_device(struct pci_dev *dev) return 0; } - - -#ifdef CONFIG_PCI_DOMAINS_GENERIC -static bool dt_domain_found = false; - -void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) -{ - int domain = of_get_pci_domain_nr(parent->of_node); - - if (domain >= 0) { - dt_domain_found = true; - } else if (dt_domain_found == true) { - dev_err(parent, "Node %s is missing \"linux,pci-domain\" property in DT\n", - parent->of_node->full_name); - return; - } else { - domain = pci_get_new_domain_nr(); - } - - bus->domain_nr = domain; -} -#endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cab05f3..c419554 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -4439,6 +4441,53 @@ int pci_get_new_domain_nr(void) { return atomic_inc_return(&__domain_nr); } + +#ifdef CONFIG_PCI_DOMAINS_GENERIC +void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) +{ + static int use_dt_domains = -1; + int domain = of_get_pci_domain_nr(parent->of_node); + + /* + * Check DT domain and use_dt_domains values. + * + * If DT domain property is valid (domain >= 0) and + * use_dt_domains != 0, the DT assignment is valid since this means + * we have not previously allocated a domain number by using + * pci_get_new_domain_nr(); we should also update use_dt_domains to + * 1, to indicate that we have just assigned a domain number from + * DT. + * + * If DT domain property value is not valid (ie domain < 0), and we + * have not previously assigned a domain number from DT + * (use_dt_domains != 1) we should assign a domain number by + * using the: + * + * pci_get_new_domain_nr() + * + * API and update the use_dt_domains value to keep track of method we + * are using to assign domain numbers (use_dt_domains = 0). + * + * All other combinations imply we have a platform that is trying + * to mix domain numbers obtained from DT and pci_get_new_domain_nr(), + * which is a recipe for domain mishandling and it is prevented by + * invalidating the domain value (domain = -1) and printing a + * corresponding error. + */ + if (domain >= 0 && use_dt_domains) { + use_dt_domains = 1; + } else if (domain < 0 && use_dt_domains != 1) { + use_dt_domains = 0; + domain = pci_get_new_domain_nr(); + } else { + dev_err(parent, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n", + parent->of_node->full_name); + domain = -1; + } + + bus->domain_nr = domain; +} +#endif #endif /** -- cgit v0.10.2 From c88d54ba0c3d89b925bfb8e98b13a3f55b55cde4 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 21 Nov 2014 11:29:25 +0000 Subject: CNS3xxx: Remove artificial dependency on pci_sys_data domain. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On cns3xxx platforms the PCI controller probing code relies on an artificial dependency on the domain number to look-up the internal data structures. This patch reworks the host controller control data structure and adds a domain equivalent field named port in it so that the dependency on pci_sys_data domain field can be eventually removed. Acked-by: Krzysztof Hałasa Signed-off-by: Arnd Bergmann [lp: added commit log, removed pci_sys_data domain references] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 45d6bd0..f6bf9f6 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -30,18 +30,15 @@ struct cns3xxx_pcie { unsigned int irqs[2]; struct resource res_io; struct resource res_mem; - struct hw_pci hw_pci; - + int port; bool linked; }; -static struct cns3xxx_pcie cns3xxx_pcie[]; /* forward decl. */ - static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata) { struct pci_sys_data *root = sysdata; - return &cns3xxx_pcie[root->domain]; + return root->private_data; } static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev) @@ -192,13 +189,7 @@ static struct cns3xxx_pcie cns3xxx_pcie[] = { .flags = IORESOURCE_MEM, }, .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, }, - .hw_pci = { - .domain = 0, - .nr_controllers = 1, - .ops = &cns3xxx_pcie_ops, - .setup = cns3xxx_pci_setup, - .map_irq = cns3xxx_pcie_map_irq, - }, + .port = 0, }, [1] = { .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT, @@ -217,19 +208,13 @@ static struct cns3xxx_pcie cns3xxx_pcie[] = { .flags = IORESOURCE_MEM, }, .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, }, - .hw_pci = { - .domain = 1, - .nr_controllers = 1, - .ops = &cns3xxx_pcie_ops, - .setup = cns3xxx_pci_setup, - .map_irq = cns3xxx_pcie_map_irq, - }, + .port = 1, }, }; static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci) { - int port = cnspci->hw_pci.domain; + int port = cnspci->port; u32 reg; unsigned long time; @@ -260,9 +245,9 @@ static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci) static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) { - int port = cnspci->hw_pci.domain; + int port = cnspci->port; struct pci_sys_data sd = { - .domain = port, + .private_data = cnspci, }; struct pci_bus bus = { .number = 0, @@ -323,6 +308,14 @@ static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr, void __init cns3xxx_pcie_init_late(void) { int i; + void *private_data; + struct hw_pci hw_pci = { + .nr_controllers = 1, + .ops = &cns3xxx_pcie_ops, + .setup = cns3xxx_pci_setup, + .map_irq = cns3xxx_pcie_map_irq, + .private_data = &private_data, + }; pcibios_min_io = 0; pcibios_min_mem = 0; @@ -335,7 +328,8 @@ void __init cns3xxx_pcie_init_late(void) cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i)); cns3xxx_pcie_check_link(&cns3xxx_pcie[i]); cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]); - pci_common_init(&cns3xxx_pcie[i].hw_pci); + private_data = &cns3xxx_pcie[i]; + pci_common_init(&hw_pci); } pci_assign_unassigned_resources(); -- cgit v0.10.2 From 8c7d14746abce601b768533c3ccb3f3e64f98551 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 21 Nov 2014 11:29:26 +0000 Subject: ARM/PCI: Move to generic PCI domains Most if not all ARM PCI host controller device drivers either ignore the domain field in the pci_sys_data structure or just increment it every time a host controller is probed, using it as a domain counter. Therefore, instead of relying on pci_sys_data to stash the domain number in a standard location, ARM pcibios code can be moved to the newly introduced generic PCI domains code, implemented in commits: 41e5c0f81d3e ("of/pci: Add pci_get_new_domain_nr() and of_get_pci_domain_nr()") 670ba0c8883b ("PCI: Add generic domain handling") ARM code is made to select PCI_DOMAINS_GENERIC by default, which builds core PCI code that assigns the domain number through the generic function: void pci_bus_assign_domain_nr(...) that relies on a DT property to define the domain number or falls back to a counter according to a predefined logic; its usage replaces the current domain assignment code in PCI host controllers present in the kernel. Tested-by: Lucas Stach Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Yijing Wang Reviewed-By: Jason Gunthorpe # mvebu Acked-by: Russell King Acked-by: Lucas Stach Acked-by: Jingoo Han Acked-by: Phil Edworthy Acked-by: Arnd Bergmann CC: Mohit Kumar diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 97d07ed..dcb2e0c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1279,6 +1279,9 @@ config PCI_DOMAINS bool depends on PCI +config PCI_DOMAINS_GENERIC + def_bool PCI_DOMAINS + config PCI_NANOENGINE bool "BSE nanoEngine PCI support" depends on SA1100_NANOENGINE diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 8292b5f..28b9bb3 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h @@ -19,9 +19,6 @@ struct pci_bus; struct device; struct hw_pci { -#ifdef CONFIG_PCI_DOMAINS - int domain; -#endif #ifdef CONFIG_PCI_MSI struct msi_controller *msi_ctrl; #endif @@ -45,9 +42,6 @@ struct hw_pci { * Per-controller structure */ struct pci_sys_data { -#ifdef CONFIG_PCI_DOMAINS - int domain; -#endif #ifdef CONFIG_PCI_MSI struct msi_controller *msi_ctrl; #endif diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h index 7e95d85..585dc33 100644 --- a/arch/arm/include/asm/pci.h +++ b/arch/arm/include/asm/pci.h @@ -18,13 +18,6 @@ static inline int pcibios_assign_all_busses(void) } #ifdef CONFIG_PCI_DOMAINS -static inline int pci_domain_nr(struct pci_bus *bus) -{ - struct pci_sys_data *root = bus->sysdata; - - return root->domain; -} - static inline int pci_proc_domain(struct pci_bus *bus) { return pci_domain_nr(bus); diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index a4effd6..ddd75c5 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -463,9 +463,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, if (!sys) panic("PCI: unable to allocate sys data!"); -#ifdef CONFIG_PCI_DOMAINS - sys->domain = hw->domain; -#endif #ifdef CONFIG_PCI_MSI sys->msi_ctrl = hw->msi_ctrl; #endif diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 1dd7595..1309cfb 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -101,9 +101,7 @@ struct mvebu_pcie { struct mvebu_pcie_port *ports; struct msi_controller *msi; struct resource io; - char io_name[30]; struct resource realio; - char mem_name[30]; struct resource mem; struct resource busn; int nports; @@ -723,18 +721,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) { struct mvebu_pcie *pcie = sys_to_pcie(sys); int i; - int domain = 0; -#ifdef CONFIG_PCI_DOMAINS - domain = sys->domain; -#endif - - snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x", - domain); - pcie->mem.name = pcie->mem_name; - - snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain); - pcie->realio.name = pcie->io_name; + pcie->mem.name = "PCI MEM"; + pcie->realio.name = "PCI I/O"; if (request_resource(&iomem_resource, &pcie->mem)) return 0; diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index df781cd..eef3111 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -508,9 +508,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp) dw_pci.private_data = (void **)&pp; pci_common_init_dev(pp->dev, &dw_pci); -#ifdef CONFIG_PCI_DOMAINS - dw_pci.domain++; -#endif return 0; } diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 748786c..ba28078 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -397,9 +397,6 @@ static void rcar_pcie_enable(struct rcar_pcie *pcie) #endif pci_common_init_dev(&pdev->dev, &rcar_pci); -#ifdef CONFIG_PCI_DOMAINS - rcar_pci.domain++; -#endif } static int phy_wait_for_ack(struct rcar_pcie *pcie) -- cgit v0.10.2 From 5fafed3e5612e9f308d20dc94adf5fc3d4a1a2a8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sat, 27 Dec 2014 20:37:37 -0800 Subject: Input: add tps65218 power button driver With this driver, we can report KEY_POWER on AM437x SK. This patch has been tested with said board. Signed-off-by: Felipe Balbi Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt new file mode 100644 index 0000000..e30e0b9 --- /dev/null +++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt @@ -0,0 +1,17 @@ +Texas Instruments TPS65218 power button + +This driver provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be "ti,tps65218-pwrbutton" +- interrupts: should be one of the following + - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218 + +Example: + +&tps { + power-button { + compatible = "ti,tps65218-pwrbutton"; + interrupts = <3 IRQ_TYPE_EDGE_BOTH>; + }; +}; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1da0a20..9591917 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -416,6 +416,16 @@ config INPUT_RETU_PWRBUTTON To compile this driver as a module, choose M here. The module will be called retu-pwrbutton. +config INPUT_TPS65218_PWRBUTTON + tristate "TPS65218 Power button driver" + depends on MFD_TPS65218 + help + Say Y here if you want to enable power buttong reporting for + the TPS65218 Power Management IC device. + + To compile this driver as a module, choose M here. The module will + be called tps65218-pwrbutton. + config INPUT_TWL4030_PWRBUTTON tristate "TWL4030 Power button Driver" depends on TWL4030_CORE diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 1f135af..9a1083f 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c new file mode 100644 index 0000000..54508de --- /dev/null +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -0,0 +1,126 @@ +/* + * Texas Instruments' TPS65218 Power Button Input Driver + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Felipe Balbi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tps65218_pwrbutton { + struct device *dev; + struct tps65218 *tps; + struct input_dev *idev; +}; + +static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr) +{ + struct tps65218_pwrbutton *pwr = _pwr; + unsigned int reg; + int error; + + error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, ®); + if (error) { + dev_err(pwr->dev, "can't read register: %d\n", error); + goto out; + } + + if (reg & TPS65218_STATUS_PB_STATE) { + input_report_key(pwr->idev, KEY_POWER, 1); + pm_wakeup_event(pwr->dev, 0); + } else { + input_report_key(pwr->idev, KEY_POWER, 0); + } + + input_sync(pwr->idev); + +out: + return IRQ_HANDLED; +} + +static int tps65218_pwron_probe(struct platform_device *pdev) +{ + struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct tps65218_pwrbutton *pwr; + struct input_dev *idev; + int error; + int irq; + + pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); + if (!pwr) + return -ENOMEM; + + idev = devm_input_allocate_device(dev); + if (!idev) + return -ENOMEM; + + idev->name = "tps65218_pwrbutton"; + idev->phys = "tps65218_pwrbutton/input0"; + idev->dev.parent = dev; + idev->id.bustype = BUS_I2C; + + input_set_capability(idev, EV_KEY, KEY_POWER); + + pwr->tps = tps; + pwr->dev = dev; + pwr->idev = idev; + platform_set_drvdata(pdev, pwr); + device_init_wakeup(dev, true); + + irq = platform_get_irq(pdev, 0); + error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "tps65218-pwrbutton", pwr); + if (error) { + dev_err(dev, "failed to request IRQ #%d: %d\n", + irq, error); + return error; + } + + error= input_register_device(idev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + return 0; +} + +static struct of_device_id of_tps65218_pwr_match[] = { + { .compatible = "ti,tps65218-pwrbutton" }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match); + +static struct platform_driver tps65218_pwron_driver = { + .probe = tps65218_pwron_probe, + .driver = { + .name = "tps65218_pwrbutton", + .of_match_table = of_tps65218_pwr_match, + }, +}; +module_platform_driver(tps65218_pwron_driver); + +MODULE_DESCRIPTION("TPS65218 Power Button"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Felipe Balbi "); -- cgit v0.10.2 From e3a8446a6a1bff8c2345cacd4f3b8bdea0ba36d8 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Mon, 12 May 2014 20:09:55 -0700 Subject: powerpc/pseries: relocate "config DTL" so kconfig nests properly Moving config DTL up so it is below config PPC_SPLPAR means that menuconfig will show config DTL nicely indented right below config PPC_SPLPAR when PPC_SPLPAR is enabled. To contrast that, right now if I enable PPC_SPLPAR in menuconfig, all I can immediately tell is that "something showed up further down the list where I wasn't looking", and I end up having to toggle the option a few times to figure out what showed up, or look at the KConfig to find out that config DTL depends on config PPC_SPLPAR. Signed-off-by: Cody P Schafer Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 756b482..a758a9c 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -34,6 +34,16 @@ config PPC_SPLPAR processors, that is, which share physical processors between two or more partitions. +config DTL + bool "Dispatch Trace Log" + depends on PPC_SPLPAR && DEBUG_FS + help + SPLPAR machines can log hypervisor preempt & dispatch events to a + kernel buffer. Saying Y here will enable logging these events, + which are accessible through a debugfs file. + + Say N if you are unsure. + config PSERIES_MSI bool depends on PCI_MSI && PPC_PSERIES && EEH @@ -123,13 +133,3 @@ config HV_PERF_CTRS systems. 24x7 is available on Power 8 systems. If unsure, select Y. - -config DTL - bool "Dispatch Trace Log" - depends on PPC_SPLPAR && DEBUG_FS - help - SPLPAR machines can log hypervisor preempt & dispatch events to a - kernel buffer. Saying Y here will enable logging these events, - which are accessible through a debugfs file. - - Say N if you are unsure. -- cgit v0.10.2 From 05b981f493e07856371ecd4a9294f187f5b50cf6 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Tue, 15 Jul 2014 13:43:47 +0200 Subject: powerpc/xmon: use isspace/isxdigit/isalnum from linux/ctype.h isxdigit() macro definition is the same. isalnum() from linux/ctype.h will accept additional latin non-ASCII characters. This is harmless since this macro is used in scanhex() which parses user input. isspace() from linux/ctype.h will accept vertical tab and form feed but not NULL. The use of this macro is modified to accept NULL as well. Additional characters are harmless since this macro is also only used in scanhex(). Signed-off-by: Vincent Bernat Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 5b150f0..e66ace7 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -183,14 +184,6 @@ extern void xmon_leave(void); #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) #endif -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) -#define isalnum(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'z') \ - || ('A' <= (c) && (c) <= 'Z')) -#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) - static char *help_string = "\ Commands:\n\ b show breakpoints\n\ @@ -2164,9 +2157,6 @@ static void dump_pacas(void) } #endif -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) static void dump(void) { @@ -2569,7 +2559,7 @@ scanhex(unsigned long *vp) int i; for (i=0; i<63; i++) { c = inchar(); - if (isspace(c)) { + if (isspace(c) || c == '\0') { termch = c; break; } -- cgit v0.10.2 From e144d4edbce67ea269d181f81b9c5ef631743430 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 20 Jul 2014 15:20:59 +0800 Subject: powerpc/4xx: Fix return value check in hsta_msi_probe() In case of error, the function ioremap() returns NULL not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Signed-off-by: Wei Yongjun Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c index ed9970f..f366d2d 100644 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -145,7 +145,7 @@ static int hsta_msi_probe(struct platform_device *pdev) ppc4xx_hsta_msi.address = mem->start; ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem)); ppc4xx_hsta_msi.irq_count = irq_count; - if (IS_ERR(ppc4xx_hsta_msi.data)) { + if (!ppc4xx_hsta_msi.data) { dev_err(dev, "Unable to map memory\n"); return -ENOMEM; } -- cgit v0.10.2 From 456295e284beb7b61a55ead9500d30f94ab06d52 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Mon, 8 Dec 2014 19:17:57 +1100 Subject: cxl: Fix leaking interrupts if attach process fails In this particular error path we have already allocated the AFU interrupts, but have not yet set the status to STARTED. The detach context code will only attempt to release the interrupts if the context is in state STARTED, so in this case the interrupts would remain allocated. This patch releases the AFU interrupts immediately if the attach call fails to prevent them leaking. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index e9f2f10..b09be44 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -185,8 +185,10 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID)); if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor, - amr))) + amr))) { + afu_release_irqs(ctx); goto out; + } ctx->status = STARTED; rc = 0; -- cgit v0.10.2 From 13da704682471669685ccc3fe111fd6c0127b2eb Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Mon, 8 Dec 2014 19:17:58 +1100 Subject: cxl: Early return from cxl_handle_fault for a shut down context If a context is being detached and we get a translation fault for it there is little point getting it's mm and handling the fault, so just respond with an address error and return earlier. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index f8684bc..e010302 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c @@ -180,6 +180,12 @@ void cxl_handle_fault(struct work_struct *fault_work) return; } + /* Early return if the context is being / has been detached */ + if (ctx->status == CLOSED) { + cxl_ack_ae(ctx); + return; + } + pr_devel("CXL BOTTOM HALF handling fault for afu pe: %i. " "DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar); -- cgit v0.10.2 From d6a6af2c181400aade59417e698c7cd9bec8804e Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Mon, 8 Dec 2014 19:17:59 +1100 Subject: cxl: Disable AFU debug flag Upon inspection of the implementation specific registers, it was discovered that the high bit of the implementation specific RXCTL register was enabled, which enables the DEADB00F debug feature. The debug feature causes MMIO reads to a disabled AFU to respond with 0xDEADB00F instead of all Fs. In general this should not be visible as the kernel will only allow MMIO access to enabled AFUs, but there may be some circumstances where an AFU may become disabled while it is use. One such case would be an AFU designed to only be used in the dedicated process mode and to disable itself after it has completed it's work (however even in that case the effects of this debug flag would be limited as the userspace application must have completed any required MMIO accesses before the AFU disables itself with or without the flag). This patch removes the debug flag and replaces the magic value programmed into this register with a preprocessor define so it is clearer what the rest of this initialisation does. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 28078f8..0df0438 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -287,6 +287,13 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PE_SOFTWARE_STATE_S (1ul << (31 - 30)) /* Suspend */ #define CXL_PE_SOFTWARE_STATE_T (1ul << (31 - 31)) /* Terminate */ +/****** CXL_PSL_RXCTL_An (Implementation Specific) ************************** + * Controls AFU Hang Pulse, which sets the timeout for the AFU to respond to + * the PSL for any response (except MMIO). Timeouts will occur between 1x to 2x + * of the hang pulse frequency. + */ +#define CXL_PSL_RXCTL_AFUHP_4S 0x7000000000000000ULL + /* SPA->sw_command_status */ #define CXL_SPA_SW_CMD_MASK 0xffff000000000000ULL #define CXL_SPA_SW_CMD_TERMINATE 0x0001000000000000ULL diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 0f2cc9f8..2ccd0a9 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -348,7 +348,7 @@ static int init_implementation_afu_regs(struct cxl_afu *afu) cxl_p1n_write(afu, CXL_PSL_COALLOC_A, 0xFF000000FEFEFEFEULL); /* for debugging with trace arrays */ cxl_p1n_write(afu, CXL_PSL_SLICE_TRACE, 0x0000FFFF00000000ULL); - cxl_p1n_write(afu, CXL_PSL_RXCTL_A, 0xF000000000000000ULL); + cxl_p1n_write(afu, CXL_PSL_RXCTL_A, CXL_PSL_RXCTL_AFUHP_4S); return 0; } -- cgit v0.10.2 From db7933f392ac4d9719d41d3f203a5f6a1c40f300 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Mon, 8 Dec 2014 19:18:00 +1100 Subject: cxl: Disable SPAP register when freeing SPA When we deactivate the AFU directed mode we free the scheduled process area, but did not clear the register in the hardware that has a pointer to it. This should be fine since we will have already cleared out every context and we won't do anything that would cause the hardware to access it until after we have allocated a new one, but just to be safe this patch clears out the register when we free the page. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index f2b37b4..0f24fa5 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -185,6 +185,7 @@ static int alloc_spa(struct cxl_afu *afu) static void release_spa(struct cxl_afu *afu) { + cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0); free_pages((unsigned long) afu->spa, afu->spa_order); } -- cgit v0.10.2 From 01b14505c35cdc47f5abc1f6799cee23f2f10149 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 23 Dec 2014 11:32:07 +1100 Subject: powerpc/44x/Akebono: Remove select of IBM_EMAC_RGMII_WOL Commit 2a2c74b2efcb ("IBM Akebono: Add the Akebono platform") added a select of IBM_EMAC_RGMII_WOL. But that Kconfig symbol isn't (yet) part of the tree. So this select has been a nop since that commit was included in v3.16-rc1. Signed-off-by: Paul Bolle Acked-by: Alistair Popple Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index d2ac1c1..5538e57 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -214,7 +214,6 @@ config AKEBONO select ETHERNET select NET_VENDOR_IBM select IBM_EMAC_EMAC4 - select IBM_EMAC_RGMII_WOL select USB if USB_SUPPORT select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD -- cgit v0.10.2 From 803d57de2b27000ed4400d16561c75821efe8333 Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Wed, 17 Dec 2014 12:05:13 +0100 Subject: powerpc/lib: Do not include string.o in obj-y twice In the Makefile, string.o (which is generated from string.S) is included into the list of objects being built unconditionally (obj-y) in line 12. Additionally, if CONFIG_PPC64 is set, it is included again in line 17. This patch removes the latter unnecessary inclusion. Signed-off-by: Andreas Ruprecht Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 597562f..1b01159 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -14,8 +14,7 @@ obj-y := string.o alloc.o \ obj-$(CONFIG_PPC32) += div64.o copy_32.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ - usercopy_64.o mem_64.o string.o \ - hweight_64.o \ + usercopy_64.o mem_64.o hweight_64.o \ copyuser_power7.o string_64.o copypage_power7.o ifeq ($(CONFIG_GENERIC_CSUM),) obj-y += checksum_$(CONFIG_WORD_SIZE).o -- cgit v0.10.2 From 9a4fc4eaf111ca960c9f524b850598e9dbc9697f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 10 Jul 2014 19:34:31 +1000 Subject: powerpc/kvm: Create proper names for the kvm_host_state PMU fields We have two arrays in kvm_host_state that contain register values for the PMU. Currently we only create an asm-offsets symbol for the base of the arrays, and do the array offset in the assembly code. Creating an asm-offsets symbol for each field individually makes the code much nicer to read, particularly for the MMCRx/SIxR/SDAR fields, and might have helped us notice the recent double restore bug we had in this code. Signed-off-by: Michael Ellerman Acked-by: Alexander Graf diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index e624f96..4717859 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -644,8 +644,19 @@ int main(void) HSTATE_FIELD(HSTATE_SAVED_XIRR, saved_xirr); HSTATE_FIELD(HSTATE_HOST_IPI, host_ipi); HSTATE_FIELD(HSTATE_PTID, ptid); - HSTATE_FIELD(HSTATE_MMCR, host_mmcr); - HSTATE_FIELD(HSTATE_PMC, host_pmc); + HSTATE_FIELD(HSTATE_MMCR0, host_mmcr[0]); + HSTATE_FIELD(HSTATE_MMCR1, host_mmcr[1]); + HSTATE_FIELD(HSTATE_MMCRA, host_mmcr[2]); + HSTATE_FIELD(HSTATE_SIAR, host_mmcr[3]); + HSTATE_FIELD(HSTATE_SDAR, host_mmcr[4]); + HSTATE_FIELD(HSTATE_MMCR2, host_mmcr[5]); + HSTATE_FIELD(HSTATE_SIER, host_mmcr[6]); + HSTATE_FIELD(HSTATE_PMC1, host_pmc[0]); + HSTATE_FIELD(HSTATE_PMC2, host_pmc[1]); + HSTATE_FIELD(HSTATE_PMC3, host_pmc[2]); + HSTATE_FIELD(HSTATE_PMC4, host_pmc[3]); + HSTATE_FIELD(HSTATE_PMC5, host_pmc[4]); + HSTATE_FIELD(HSTATE_PMC6, host_pmc[5]); HSTATE_FIELD(HSTATE_PURR, host_purr); HSTATE_FIELD(HSTATE_SPURR, host_spurr); HSTATE_FIELD(HSTATE_DSCR, host_dscr); diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S index 36540a9..0fdc4a2 100644 --- a/arch/powerpc/kvm/book3s_hv_interrupts.S +++ b/arch/powerpc/kvm/book3s_hv_interrupts.S @@ -93,15 +93,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfspr r5, SPRN_MMCR1 mfspr r9, SPRN_SIAR mfspr r10, SPRN_SDAR - std r7, HSTATE_MMCR(r13) - std r5, HSTATE_MMCR + 8(r13) - std r6, HSTATE_MMCR + 16(r13) - std r9, HSTATE_MMCR + 24(r13) - std r10, HSTATE_MMCR + 32(r13) + std r7, HSTATE_MMCR0(r13) + std r5, HSTATE_MMCR1(r13) + std r6, HSTATE_MMCRA(r13) + std r9, HSTATE_SIAR(r13) + std r10, HSTATE_SDAR(r13) BEGIN_FTR_SECTION mfspr r9, SPRN_SIER - std r8, HSTATE_MMCR + 40(r13) - std r9, HSTATE_MMCR + 48(r13) + std r8, HSTATE_MMCR2(r13) + std r9, HSTATE_SIER(r13) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfspr r3, SPRN_PMC1 mfspr r5, SPRN_PMC2 @@ -109,12 +109,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfspr r7, SPRN_PMC4 mfspr r8, SPRN_PMC5 mfspr r9, SPRN_PMC6 - stw r3, HSTATE_PMC(r13) - stw r5, HSTATE_PMC + 4(r13) - stw r6, HSTATE_PMC + 8(r13) - stw r7, HSTATE_PMC + 12(r13) - stw r8, HSTATE_PMC + 16(r13) - stw r9, HSTATE_PMC + 20(r13) + stw r3, HSTATE_PMC1(r13) + stw r5, HSTATE_PMC2(r13) + stw r6, HSTATE_PMC3(r13) + stw r7, HSTATE_PMC4(r13) + stw r8, HSTATE_PMC5(r13) + stw r9, HSTATE_PMC6(r13) 31: /* diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 10554df..bb94e6f 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -83,35 +83,35 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) cmpwi r4, 0 beq 23f /* skip if not */ BEGIN_FTR_SECTION - ld r3, HSTATE_MMCR(r13) + ld r3, HSTATE_MMCR0(r13) andi. r4, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO cmpwi r4, MMCR0_PMAO beql kvmppc_fix_pmao END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) - lwz r3, HSTATE_PMC(r13) - lwz r4, HSTATE_PMC + 4(r13) - lwz r5, HSTATE_PMC + 8(r13) - lwz r6, HSTATE_PMC + 12(r13) - lwz r8, HSTATE_PMC + 16(r13) - lwz r9, HSTATE_PMC + 20(r13) + lwz r3, HSTATE_PMC1(r13) + lwz r4, HSTATE_PMC2(r13) + lwz r5, HSTATE_PMC3(r13) + lwz r6, HSTATE_PMC4(r13) + lwz r8, HSTATE_PMC5(r13) + lwz r9, HSTATE_PMC6(r13) mtspr SPRN_PMC1, r3 mtspr SPRN_PMC2, r4 mtspr SPRN_PMC3, r5 mtspr SPRN_PMC4, r6 mtspr SPRN_PMC5, r8 mtspr SPRN_PMC6, r9 - ld r3, HSTATE_MMCR(r13) - ld r4, HSTATE_MMCR + 8(r13) - ld r5, HSTATE_MMCR + 16(r13) - ld r6, HSTATE_MMCR + 24(r13) - ld r7, HSTATE_MMCR + 32(r13) + ld r3, HSTATE_MMCR0(r13) + ld r4, HSTATE_MMCR1(r13) + ld r5, HSTATE_MMCRA(r13) + ld r6, HSTATE_SIAR(r13) + ld r7, HSTATE_SDAR(r13) mtspr SPRN_MMCR1, r4 mtspr SPRN_MMCRA, r5 mtspr SPRN_SIAR, r6 mtspr SPRN_SDAR, r7 BEGIN_FTR_SECTION - ld r8, HSTATE_MMCR + 40(r13) - ld r9, HSTATE_MMCR + 48(r13) + ld r8, HSTATE_MMCR2(r13) + ld r9, HSTATE_SIER(r13) mtspr SPRN_MMCR2, r8 mtspr SPRN_SIER, r9 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) -- cgit v0.10.2 From 72dca06f62c50415de3202f204200f58769d0b8b Mon Sep 17 00:00:00 2001 From: Aniroop Mathur Date: Sun, 28 Dec 2014 22:08:38 +0530 Subject: regulator: core: Avoid negative regulator no & initialize it to -1 This patch initializes regulator_no to -1 to avoid extra subtraction operation performed every time we register a regulator and avoid negative regulator no in its name. Signed-off-by: Aniroop Mathur Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e225711..4bc5ea9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3585,7 +3585,7 @@ regulator_register(const struct regulator_desc *regulator_desc, { const struct regulation_constraints *constraints = NULL; const struct regulator_init_data *init_data; - static atomic_t regulator_no = ATOMIC_INIT(0); + static atomic_t regulator_no = ATOMIC_INIT(-1); struct regulator_dev *rdev; struct device *dev; int ret, i; @@ -3658,8 +3658,8 @@ regulator_register(const struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; - dev_set_name(&rdev->dev, "regulator.%d", - atomic_inc_return(®ulator_no) - 1); + dev_set_name(&rdev->dev, "regulator.%lu", + atomic_inc_return(®ulator_no)); ret = device_register(&rdev->dev); if (ret != 0) { put_device(&rdev->dev); -- cgit v0.10.2 From 39138818a4f5c62d70f35504477c2509f982f211 Mon Sep 17 00:00:00 2001 From: Aniroop Mathur Date: Mon, 29 Dec 2014 22:36:48 +0530 Subject: regulator: core: Fix format specifier warning Signed-off-by: Aniroop Mathur Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4bc5ea9..c2554d8 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3659,7 +3659,7 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%lu", - atomic_inc_return(®ulator_no)); + (unsigned long) atomic_inc_return(®ulator_no)); ret = device_register(&rdev->dev); if (ret != 0) { put_device(&rdev->dev); -- cgit v0.10.2 From 0667dd5f6c203480f2e8dcb3fc039ef723453a2f Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Tue, 16 Dec 2014 12:21:55 +0200 Subject: spi: qup: Add SPI_CPOL configuration support Device support SPI_CPOL, but driver have missed to add support for this configuration. Signed-off-by: Ivan T. Ivanov Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index e7fb5a0..ff9cdbd 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -337,7 +337,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(spi->master); - u32 config, iomode, mode; + u32 config, iomode, mode, control; int ret, n_words, w_size; if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { @@ -392,6 +392,15 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); + control = readl_relaxed(controller->base + SPI_IO_CONTROL); + + if (spi->mode & SPI_CPOL) + control |= SPI_IO_C_CLK_IDLE_HIGH; + else + control &= ~SPI_IO_C_CLK_IDLE_HIGH; + + writel_relaxed(control, controller->base + SPI_IO_CONTROL); + config = readl_relaxed(controller->base + SPI_CONFIG); if (spi->mode & SPI_LOOP) -- cgit v0.10.2 From 05be1d079ec0b3691783e4384b1ada82149ff7d2 Mon Sep 17 00:00:00 2001 From: Mathias Gottschlag Date: Mon, 29 Dec 2014 09:26:35 -0800 Subject: Input: psmouse - support for the FocalTech PS/2 protocol extensions Most of the protocol for these touchpads has been reverse engineered. This commit adds a basic multitouch-capable driver. A lot of the protocol is still unknown. Especially, we don't know how to identify the device yet apart from the PNP ID. The previous workaround for these devices has been left in place in case the driver is not compiled into the kernel or in case some other device with the same PNP ID is not recognized by the driver yet still has the same problems with the device probing code. Signed-off-by: Mathias Gottschlag Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index d8b46b0..2541bfa 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -146,6 +146,16 @@ config MOUSE_PS2_OLPC If unsure, say N. +config MOUSE_PS2_FOCALTECH + bool "FocalTech PS/2 mouse protocol extension" if EXPERT + default y + depends on MOUSE_PS2 + help + Say Y here if you have a FocalTech PS/2 TouchPad connected to + your system. + + If unsure, say Y. + config MOUSE_SERIAL tristate "Serial mouse" select SERIO diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index f4d657e..fca38ba 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -2,6 +2,7 @@ * Focaltech TouchPad PS/2 mouse driver * * Copyright (c) 2014 Red Hat Inc. + * Copyright (c) 2014 Mathias Gottschlag * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,15 +14,14 @@ * Hans de Goede */ -/* - * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with - * detection only, to avoid further detection attempts confusing the touchpad - * this way it at least works in PS/2 mouse compatibility mode. - */ #include #include +#include +#include +#include #include "psmouse.h" +#include "focaltech.h" static const char * const focaltech_pnp_ids[] = { "FLT0101", @@ -30,6 +30,12 @@ static const char * const focaltech_pnp_ids[] = { NULL }; +/* + * Even if the kernel is built without support for Focaltech PS/2 touchpads (or + * when the real driver fails to recognize the device), we still have to detect + * them in order to avoid further detection attempts confusing the touchpad. + * This way it at least works in PS/2 mouse compatibility mode. + */ int focaltech_detect(struct psmouse *psmouse, bool set_properties) { if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) @@ -37,16 +43,404 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { psmouse->vendor = "FocalTech"; - psmouse->name = "FocalTech Touchpad in mouse emulation mode"; + psmouse->name = "FocalTech Touchpad"; } return 0; } -int focaltech_init(struct psmouse *psmouse) +static void focaltech_reset(struct psmouse *psmouse) { ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); psmouse_reset(psmouse); +} + +#ifdef CONFIG_MOUSE_PS2_FOCALTECH + +/* + * Packet types - the numbers are not consecutive, so we might be missing + * something here. + */ +#define FOC_TOUCH 0x3 /* bitmap of active fingers */ +#define FOC_ABS 0x6 /* absolute position of one finger */ +#define FOC_REL 0x9 /* relative position of 1-2 fingers */ + +#define FOC_MAX_FINGERS 5 + +#define FOC_MAX_X 2431 +#define FOC_MAX_Y 1663 + +/* + * Current state of a single finger on the touchpad. + */ +struct focaltech_finger_state { + /* The touchpad has generated a touch event for the finger */ + bool active; + + /* + * The touchpad has sent position data for the finger. The + * flag is 0 when the finger is not active, and there is a + * time between the first touch event for the finger and the + * following absolute position packet for the finger where the + * touchpad has declared the finger to be valid, but we do not + * have any valid position yet. + */ + bool valid; + + /* + * Absolute position (from the bottom left corner) of the + * finger. + */ + unsigned int x; + unsigned int y; +}; + +/* + * Description of the current state of the touchpad hardware. + */ +struct focaltech_hw_state { + /* + * The touchpad tracks the positions of the fingers for us, + * the array indices correspond to the finger indices returned + * in the report packages. + */ + struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; + + /* True if the clickpad has been pressed. */ + bool pressed; +}; + +struct focaltech_data { + unsigned int x_max, y_max; + struct focaltech_hw_state state; +}; + +static void focaltech_report_state(struct psmouse *psmouse) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + struct input_dev *dev = psmouse->dev; + int i; + + for (i = 0; i < FOC_MAX_FINGERS; i++) { + struct focaltech_finger_state *finger = &state->fingers[i]; + bool active = finger->active && finger->valid; + + input_mt_slot(dev, i); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); + if (active) { + input_report_abs(dev, ABS_MT_POSITION_X, finger->x); + input_report_abs(dev, ABS_MT_POSITION_Y, + FOC_MAX_Y - finger->y); + } + } + input_mt_report_pointer_emulation(dev, true); + + input_report_key(psmouse->dev, BTN_LEFT, state->pressed); + input_sync(psmouse->dev); +} + +static void focaltech_process_touch_packet(struct psmouse *psmouse, + unsigned char *packet) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + unsigned char fingers = packet[1]; + int i; + + state->pressed = (packet[0] >> 4) & 1; + + /* the second byte contains a bitmap of all fingers touching the pad */ + for (i = 0; i < FOC_MAX_FINGERS; i++) { + state->fingers[i].active = fingers & 0x1; + if (!state->fingers[i].active) { + /* + * Even when the finger becomes active again, we still + * will have to wait for the first valid position. + */ + state->fingers[i].valid = false; + } + fingers >>= 1; + } +} + +static void focaltech_process_abs_packet(struct psmouse *psmouse, + unsigned char *packet) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + unsigned int finger; + + finger = (packet[1] >> 4) - 1; + if (finger >= FOC_MAX_FINGERS) { + psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", + finger); + return; + } + + state->pressed = (packet[0] >> 4) & 1; + + /* + * packet[5] contains some kind of tool size in the most + * significant nibble. 0xff is a special value (latching) that + * signals a large contact area. + */ + if (packet[5] == 0xff) { + state->fingers[finger].valid = false; + return; + } + + state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; + state->fingers[finger].y = (packet[3] << 8) | packet[4]; + state->fingers[finger].valid = true; +} + +static void focaltech_process_rel_packet(struct psmouse *psmouse, + unsigned char *packet) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + int finger1, finger2; + + state->pressed = packet[0] >> 7; + finger1 = ((packet[0] >> 4) & 0x7) - 1; + if (finger1 < FOC_MAX_FINGERS) { + state->fingers[finger1].x += (char)packet[1]; + state->fingers[finger1].y += (char)packet[2]; + } else { + psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", + finger1); + } + + /* + * If there is an odd number of fingers, the last relative + * packet only contains one finger. In this case, the second + * finger index in the packet is 0 (we subtract 1 in the lines + * above to create array indices, so the finger will overflow + * and be above FOC_MAX_FINGERS). + */ + finger2 = ((packet[3] >> 4) & 0x7) - 1; + if (finger2 < FOC_MAX_FINGERS) { + state->fingers[finger2].x += (char)packet[4]; + state->fingers[finger2].y += (char)packet[5]; + } +} + +static void focaltech_process_packet(struct psmouse *psmouse) +{ + unsigned char *packet = psmouse->packet; + + switch (packet[0] & 0xf) { + case FOC_TOUCH: + focaltech_process_touch_packet(psmouse, packet); + break; + + case FOC_ABS: + focaltech_process_abs_packet(psmouse, packet); + break; + + case FOC_REL: + focaltech_process_rel_packet(psmouse, packet); + break; + + default: + psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); + break; + } + + focaltech_report_state(psmouse); +} + +static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) +{ + if (psmouse->pktcnt >= 6) { /* Full packet received */ + focaltech_process_packet(psmouse); + return PSMOUSE_FULL_PACKET; + } + + /* + * We might want to do some validation of the data here, but + * we do not know the protocol well enough + */ + return PSMOUSE_GOOD_DATA; +} + +static int focaltech_switch_protocol(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + + param[0] = 0; + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + param[0] = 1; + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) + return -EIO; + + return 0; +} + +static void focaltech_disconnect(struct psmouse *psmouse) +{ + focaltech_reset(psmouse); + kfree(psmouse->private); + psmouse->private = NULL; +} + +static int focaltech_reconnect(struct psmouse *psmouse) +{ + int error; + + focaltech_reset(psmouse); + + error = focaltech_switch_protocol(psmouse); + if (error) { + psmouse_err(psmouse, "Unable to initialize the device\n"); + return error; + } + + return 0; +} + +static void focaltech_set_input_params(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct focaltech_data *priv = psmouse->private; + + /* + * Undo part of setup done for us by psmouse core since touchpad + * is not a relative device. + */ + __clear_bit(EV_REL, dev->evbit); + __clear_bit(REL_X, dev->relbit); + __clear_bit(REL_Y, dev->relbit); + __clear_bit(BTN_RIGHT, dev->keybit); + __clear_bit(BTN_MIDDLE, dev->keybit); + + /* + * Now set up our capabilities. + */ + __set_bit(EV_ABS, dev->evbit); + input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); + input_mt_init_slots(dev, 5, INPUT_MT_POINTER); + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +} + +static int focaltech_read_register(struct ps2dev *ps2dev, int reg, + unsigned char *param) +{ + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) + return -EIO; + + param[0] = 0; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + param[0] = reg; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + return -EIO; + + return 0; +} + +static int focaltech_read_size(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + struct focaltech_data *priv = psmouse->private; + char param[3]; + + if (focaltech_read_register(ps2dev, 2, param)) + return -EIO; + + /* not sure whether this is 100% correct */ + priv->x_max = (unsigned char)param[1] * 128; + priv->y_max = (unsigned char)param[2] * 128; + + return 0; +} +int focaltech_init(struct psmouse *psmouse) +{ + struct focaltech_data *priv; + int error; + + psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + focaltech_reset(psmouse); + + error = focaltech_read_size(psmouse); + if (error) { + psmouse_err(psmouse, + "Unable to read the size of the touchpad\n"); + goto fail; + } + + error = focaltech_switch_protocol(psmouse); + if (error) { + psmouse_err(psmouse, "Unable to initialize the device\n"); + goto fail; + } + + focaltech_set_input_params(psmouse); + + psmouse->protocol_handler = focaltech_process_byte; + psmouse->pktsize = 6; + psmouse->disconnect = focaltech_disconnect; + psmouse->reconnect = focaltech_reconnect; + psmouse->cleanup = focaltech_reset; + /* resync is not supported yet */ + psmouse->resync_time = 0; return 0; + +fail: + focaltech_reset(psmouse); + kfree(priv); + return error; } + +bool focaltech_supported(void) +{ + return true; +} + +#else /* CONFIG_MOUSE_PS2_FOCALTECH */ + +int focaltech_init(struct psmouse *psmouse) +{ + focaltech_reset(psmouse); + + return 0; +} + +bool focaltech_supported(void) +{ + return false; +} + +#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h index 498650c..71870a9 100644 --- a/drivers/input/mouse/focaltech.h +++ b/drivers/input/mouse/focaltech.h @@ -2,6 +2,7 @@ * Focaltech TouchPad PS/2 mouse driver * * Copyright (c) 2014 Red Hat Inc. + * Copyright (c) 2014 Mathias Gottschlag * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,5 +19,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties); int focaltech_init(struct psmouse *psmouse); +bool focaltech_supported(void); #endif diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 26994f6..4a9de33 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -725,16 +725,19 @@ static int psmouse_extensions(struct psmouse *psmouse, /* Always check for focaltech, this is safe as it uses pnp-id matching */ if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { - if (!set_properties || focaltech_init(psmouse) == 0) { - /* - * Not supported yet, use bare protocol. - * Note that we need to also restrict - * psmouse_max_proto so that psmouse_initialize() - * does not try to reset rate and resolution, - * because even that upsets the device. - */ - psmouse_max_proto = PSMOUSE_PS2; - return PSMOUSE_PS2; + if (max_proto > PSMOUSE_IMEX) { + if (!set_properties || focaltech_init(psmouse) == 0) { + if (focaltech_supported()) + return PSMOUSE_FOCALTECH; + /* + * Note that we need to also restrict + * psmouse_max_proto so that psmouse_initialize() + * does not try to reset rate and resolution, + * because even that upsets the device. + */ + psmouse_max_proto = PSMOUSE_PS2; + return PSMOUSE_PS2; + } } } @@ -1063,6 +1066,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { .alias = "cortps", .detect = cortron_detect, }, +#ifdef CONFIG_MOUSE_PS2_FOCALTECH + { + .type = PSMOUSE_FOCALTECH, + .name = "FocalTechPS/2", + .alias = "focaltech", + .detect = focaltech_detect, + .init = focaltech_init, + }, +#endif { .type = PSMOUSE_AUTO, .name = "auto", diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index f4cf664..c2ff137 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -96,6 +96,7 @@ enum psmouse_type { PSMOUSE_FSP, PSMOUSE_SYNAPTICS_RELATIVE, PSMOUSE_CYPRESS, + PSMOUSE_FOCALTECH, PSMOUSE_AUTO /* This one should always be last */ }; -- cgit v0.10.2 From f361a2febfdad7c91de75a69ca1855f170485604 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 29 Dec 2014 10:32:24 -0800 Subject: Input: elants_i2c - remove unnecessary version.h inclusion Based on versioncheck. Signed-off-by: Fabian Frederick Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index a510f7e..926c58e 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -33,10 +33,8 @@ #include #include #include -#include #include #include -#include #include #include #include -- cgit v0.10.2 From e9e8520f229bd6881b51d03c010df6c0312bfef8 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 29 Dec 2014 14:15:24 -0800 Subject: Input: synaptics - use in-kernel tracking for reporting mt data The current code tries to consider all states and transitions to properly detect which finger is attached to which slot. The code is quite huge and difficult to read. If the sensor manages to group the touch points but is not reliable in giving tracking ids, we can simply use the kernel tracking method. Note that it is already used by Cr-48 Chromebooks. Incidentaly, this fixes a bug reported by Peter Hutterer: """ on the Lenovo T440, run: evemu-record /dev/input/event4 | grep BTN_ then put one, two, three, two fingers down when you go from 3 to 2 fingers the driver sends a spurious BTN_TOUCH 0 event: E: 0.000000 0001 014a 0001 # EV_KEY / BTN_TOUCH 1 E: 0.000000 0001 0145 0001 # EV_KEY / BTN_TOOL_FINGER 1 E: 0.770008 0001 0145 0000 # EV_KEY / BTN_TOOL_FINGER 0 E: 0.770008 0001 014d 0001 # EV_KEY / BTN_TOOL_DOUBLETAP 1 E: 1.924716 0001 014d 0000 # EV_KEY / BTN_TOOL_DOUBLETAP 0 E: 1.924716 0001 014e 0001 # EV_KEY / BTN_TOOL_TRIPLETAP 1 .. changing from 3 to 2 fingers now E: 3.152641 0001 014a 0000 # EV_KEY / BTN_TOUCH 0 E: 3.152641 0001 014d 0001 # EV_KEY / BTN_TOOL_DOUBLETAP 1 E: 3.152641 0001 014e 0000 # EV_KEY / BTN_TOOL_TRIPLETAP 0 E: 3.176948 0001 014a 0001 # EV_KEY / BTN_TOUCH 1 quick look in the kernel shows it's caused by hw.z going to 0 for a packet, so probably a firmware bug. either way, it makes it hard to track BTN_TOUCH as signal that at least one finger is down. """ The in-kernel tracking is enough to remove this spurious BTN_TOUCH 0. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 9031a0a..fd89249 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -569,14 +569,6 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count, - int sgm, int agm) -{ - state->count = count; - state->sgm = sgm; - state->agm = agm; -} - static void synaptics_parse_agm(const unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) @@ -595,16 +587,13 @@ static void synaptics_parse_agm(const unsigned char buf[], break; case 2: - /* AGM-CONTACT packet: (count, sgm, agm) */ - synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]); + /* AGM-CONTACT packet: we are only interested in the count */ + priv->agm_count = buf[1]; break; default: break; } - - /* Record that at least one AGM has been received since last SGM */ - priv->agm_pending = true; } static bool is_forcepad; @@ -798,388 +787,68 @@ static void synaptics_report_buttons(struct psmouse *psmouse, input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); } -static void synaptics_report_slot(struct input_dev *dev, int slot, - const struct synaptics_hw_state *hw) -{ - input_mt_slot(dev, slot); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL)); - if (!hw) - return; - - input_report_abs(dev, ABS_MT_POSITION_X, hw->x); - input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y)); - input_report_abs(dev, ABS_MT_PRESSURE, hw->z); -} - static void synaptics_report_mt_data(struct psmouse *psmouse, - struct synaptics_mt_state *mt_state, - const struct synaptics_hw_state *sgm) + const struct synaptics_hw_state *sgm, + int num_fingers) { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state *agm = &priv->agm; - struct synaptics_mt_state *old = &priv->mt_state; + const struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; + struct input_mt_pos pos[2]; + int slot[2], nsemi, i; - switch (mt_state->count) { - case 0: - synaptics_report_slot(dev, 0, NULL); - synaptics_report_slot(dev, 1, NULL); - break; - case 1: - if (mt_state->sgm == -1) { - synaptics_report_slot(dev, 0, NULL); - synaptics_report_slot(dev, 1, NULL); - } else if (mt_state->sgm == 0) { - synaptics_report_slot(dev, 0, sgm); - synaptics_report_slot(dev, 1, NULL); - } else { - synaptics_report_slot(dev, 0, NULL); - synaptics_report_slot(dev, 1, sgm); - } - break; - default: - /* - * If the finger slot contained in SGM is valid, and either - * hasn't changed, or is new, or the old SGM has now moved to - * AGM, then report SGM in MTB slot 0. - * Otherwise, empty MTB slot 0. - */ - if (mt_state->sgm != -1 && - (mt_state->sgm == old->sgm || - old->sgm == -1 || mt_state->agm == old->sgm)) - synaptics_report_slot(dev, 0, sgm); - else - synaptics_report_slot(dev, 0, NULL); + nsemi = clamp_val(num_fingers, 0, 2); - /* - * If the finger slot contained in AGM is valid, and either - * hasn't changed, or is new, then report AGM in MTB slot 1. - * Otherwise, empty MTB slot 1. - * - * However, in the case where the AGM is new, make sure that - * that it is either the same as the old SGM, or there was no - * SGM. - * - * Otherwise, if the SGM was just 1, and the new AGM is 2, then - * the new AGM will keep the old SGM's tracking ID, which can - * cause apparent drumroll. This happens if in the following - * valid finger sequence: - * - * Action SGM AGM (MTB slot:Contact) - * 1. Touch contact 0 (0:0) - * 2. Touch contact 1 (0:0, 1:1) - * 3. Lift contact 0 (1:1) - * 4. Touch contacts 2,3 (0:2, 1:3) - * - * In step 4, contact 3, in AGM must not be given the same - * tracking ID as contact 1 had in step 3. To avoid this, - * the first agm with contact 3 is dropped and slot 1 is - * invalidated (tracking ID = -1). - */ - if (mt_state->agm != -1 && - (mt_state->agm == old->agm || - (old->agm == -1 && - (old->sgm == -1 || mt_state->agm == old->sgm)))) - synaptics_report_slot(dev, 1, agm); - else - synaptics_report_slot(dev, 1, NULL); - break; + for (i = 0; i < nsemi; i++) { + pos[i].x = hw[i]->x; + pos[i].y = synaptics_invert_y(hw[i]->y); } + input_mt_assign_slots(dev, slot, pos, nsemi); + + for (i = 0; i < nsemi; i++) { + input_mt_slot(dev, slot[i]); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); + input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); + input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); + input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); + } + + input_mt_drop_unused(dev); + /* Don't use active slot count to generate BTN_TOOL events. */ input_mt_report_pointer_emulation(dev, false); /* Send the number of fingers reported by touchpad itself. */ - input_mt_report_finger_count(dev, mt_state->count); + input_mt_report_finger_count(dev, num_fingers); synaptics_report_buttons(psmouse, sgm); input_sync(dev); } -/* Handle case where mt_state->count = 0 */ -static void synaptics_image_sensor_0f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - synaptics_mt_state_set(mt_state, 0, -1, -1); - priv->mt_state_lost = false; -} - -/* Handle case where mt_state->count = 1 */ -static void synaptics_image_sensor_1f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - struct synaptics_hw_state *agm = &priv->agm; - struct synaptics_mt_state *old = &priv->mt_state; - - /* - * If the last AGM was (0,0,0), and there is only one finger left, - * then we absolutely know that SGM contains slot 0, and all other - * fingers have been removed. - */ - if (priv->agm_pending && agm->z == 0) { - synaptics_mt_state_set(mt_state, 1, 0, -1); - priv->mt_state_lost = false; - return; - } - - switch (old->count) { - case 0: - synaptics_mt_state_set(mt_state, 1, 0, -1); - break; - case 1: - /* - * If mt_state_lost, then the previous transition was 3->1, - * and SGM now contains either slot 0 or 1, but we don't know - * which. So, we just assume that the SGM now contains slot 1. - * - * If pending AGM and either: - * (a) the previous SGM slot contains slot 0, or - * (b) there was no SGM slot - * then, the SGM now contains slot 1 - * - * Case (a) happens with very rapid "drum roll" gestures, where - * slot 0 finger is lifted and a new slot 1 finger touches - * within one reporting interval. - * - * Case (b) happens if initially two or more fingers tap - * briefly, and all but one lift before the end of the first - * reporting interval. - * - * (In both these cases, slot 0 will becomes empty, so SGM - * contains slot 1 with the new finger) - * - * Else, if there was no previous SGM, it now contains slot 0. - * - * Otherwise, SGM still contains the same slot. - */ - if (priv->mt_state_lost || - (priv->agm_pending && old->sgm <= 0)) - synaptics_mt_state_set(mt_state, 1, 1, -1); - else if (old->sgm == -1) - synaptics_mt_state_set(mt_state, 1, 0, -1); - break; - case 2: - /* - * If mt_state_lost, we don't know which finger SGM contains. - * - * So, report 1 finger, but with both slots empty. - * We will use slot 1 on subsequent 1->1 - */ - if (priv->mt_state_lost) { - synaptics_mt_state_set(mt_state, 1, -1, -1); - break; - } - /* - * Since the last AGM was NOT (0,0,0), it was the finger in - * slot 0 that has been removed. - * So, SGM now contains previous AGM's slot, and AGM is now - * empty. - */ - synaptics_mt_state_set(mt_state, 1, old->agm, -1); - break; - case 3: - /* - * Since last AGM was not (0,0,0), we don't know which finger - * is left. - * - * So, report 1 finger, but with both slots empty. - * We will use slot 1 on subsequent 1->1 - */ - synaptics_mt_state_set(mt_state, 1, -1, -1); - priv->mt_state_lost = true; - break; - case 4: - case 5: - /* mt_state was updated by AGM-CONTACT packet */ - break; - } -} - -/* Handle case where mt_state->count = 2 */ -static void synaptics_image_sensor_2f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - struct synaptics_mt_state *old = &priv->mt_state; - - switch (old->count) { - case 0: - synaptics_mt_state_set(mt_state, 2, 0, 1); - break; - case 1: - /* - * If previous SGM contained slot 1 or higher, SGM now contains - * slot 0 (the newly touching finger) and AGM contains SGM's - * previous slot. - * - * Otherwise, SGM still contains slot 0 and AGM now contains - * slot 1. - */ - if (old->sgm >= 1) - synaptics_mt_state_set(mt_state, 2, 0, old->sgm); - else - synaptics_mt_state_set(mt_state, 2, 0, 1); - break; - case 2: - /* - * If mt_state_lost, SGM now contains either finger 1 or 2, but - * we don't know which. - * So, we just assume that the SGM contains slot 0 and AGM 1. - */ - if (priv->mt_state_lost) - synaptics_mt_state_set(mt_state, 2, 0, 1); - /* - * Otherwise, use the same mt_state, since it either hasn't - * changed, or was updated by a recently received AGM-CONTACT - * packet. - */ - break; - case 3: - /* - * 3->2 transitions have two unsolvable problems: - * 1) no indication is given which finger was removed - * 2) no way to tell if agm packet was for finger 3 - * before 3->2, or finger 2 after 3->2. - * - * So, report 2 fingers, but empty all slots. - * We will guess slots [0,1] on subsequent 2->2. - */ - synaptics_mt_state_set(mt_state, 2, -1, -1); - priv->mt_state_lost = true; - break; - case 4: - case 5: - /* mt_state was updated by AGM-CONTACT packet */ - break; - } -} - -/* Handle case where mt_state->count = 3 */ -static void synaptics_image_sensor_3f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - struct synaptics_mt_state *old = &priv->mt_state; - - switch (old->count) { - case 0: - synaptics_mt_state_set(mt_state, 3, 0, 2); - break; - case 1: - /* - * If previous SGM contained slot 2 or higher, SGM now contains - * slot 0 (one of the newly touching fingers) and AGM contains - * SGM's previous slot. - * - * Otherwise, SGM now contains slot 0 and AGM contains slot 2. - */ - if (old->sgm >= 2) - synaptics_mt_state_set(mt_state, 3, 0, old->sgm); - else - synaptics_mt_state_set(mt_state, 3, 0, 2); - break; - case 2: - /* - * If the AGM previously contained slot 3 or higher, then the - * newly touching finger is in the lowest available slot. - * - * If SGM was previously 1 or higher, then the new SGM is - * now slot 0 (with a new finger), otherwise, the new finger - * is now in a hidden slot between 0 and AGM's slot. - * - * In all such cases, the SGM now contains slot 0, and the AGM - * continues to contain the same slot as before. - */ - if (old->agm >= 3) { - synaptics_mt_state_set(mt_state, 3, 0, old->agm); - break; - } - - /* - * After some 3->1 and all 3->2 transitions, we lose track - * of which slot is reported by SGM and AGM. - * - * For 2->3 in this state, report 3 fingers, but empty all - * slots, and we will guess (0,2) on a subsequent 0->3. - * - * To userspace, the resulting transition will look like: - * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2] - */ - if (priv->mt_state_lost) { - synaptics_mt_state_set(mt_state, 3, -1, -1); - break; - } - - /* - * If the (SGM,AGM) really previously contained slots (0, 1), - * then we cannot know what slot was just reported by the AGM, - * because the 2->3 transition can occur either before or after - * the AGM packet. Thus, this most recent AGM could contain - * either the same old slot 1 or the new slot 2. - * Subsequent AGMs will be reporting slot 2. - * - * To userspace, the resulting transition will look like: - * 2:[0,1] -> 3:[0,-1] -> 3:[0,2] - */ - synaptics_mt_state_set(mt_state, 3, 0, -1); - break; - case 3: - /* - * If, for whatever reason, the previous agm was invalid, - * Assume SGM now contains slot 0, AGM now contains slot 2. - */ - if (old->agm <= 2) - synaptics_mt_state_set(mt_state, 3, 0, 2); - /* - * mt_state either hasn't changed, or was updated by a recently - * received AGM-CONTACT packet. - */ - break; - - case 4: - case 5: - /* mt_state was updated by AGM-CONTACT packet */ - break; - } -} - -/* Handle case where mt_state->count = 4, or = 5 */ -static void synaptics_image_sensor_45f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - /* mt_state was updated correctly by AGM-CONTACT packet */ - priv->mt_state_lost = false; -} - static void synaptics_image_sensor_process(struct psmouse *psmouse, struct synaptics_hw_state *sgm) { struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state *agm = &priv->agm; - struct synaptics_mt_state mt_state; - - /* Initialize using current mt_state (as updated by last agm) */ - mt_state = agm->mt_state; + int num_fingers; /* * Update mt_state using the new finger count and current mt_state. */ if (sgm->z == 0) - synaptics_image_sensor_0f(priv, &mt_state); + num_fingers = 0; else if (sgm->w >= 4) - synaptics_image_sensor_1f(priv, &mt_state); + num_fingers = 1; else if (sgm->w == 0) - synaptics_image_sensor_2f(priv, &mt_state); - else if (sgm->w == 1 && mt_state.count <= 3) - synaptics_image_sensor_3f(priv, &mt_state); + num_fingers = 2; + else if (sgm->w == 1) + num_fingers = priv->agm_count ? priv->agm_count : 3; else - synaptics_image_sensor_45f(priv, &mt_state); + num_fingers = 4; /* Send resulting input events to user space */ - synaptics_report_mt_data(psmouse, &mt_state, sgm); - - /* Store updated mt_state */ - priv->mt_state = agm->mt_state = mt_state; - priv->agm_pending = false; + synaptics_report_mt_data(psmouse, sgm, num_fingers); } static void synaptics_profile_sensor_process(struct psmouse *psmouse, @@ -1439,7 +1108,7 @@ static void set_input_params(struct psmouse *psmouse, ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - input_mt_init_slots(dev, 2, INPUT_MT_POINTER); + input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); /* Image sensors can signal 4 and 5 finger clicks */ __set_bit(BTN_TOOL_QUADTAP, dev->keybit); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 1bd01f2..6faf9bb 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -119,16 +119,6 @@ #define SYN_REDUCED_FILTER_FUZZ 8 /* - * A structure to describe which internal touchpad finger slots are being - * reported in raw packets. - */ -struct synaptics_mt_state { - int count; /* num fingers being tracked */ - int sgm; /* which slot is reported by sgm pkt */ - int agm; /* which slot is reported by agm pkt*/ -}; - -/* * A structure to describe the state of the touchpad hardware (buttons and pad) */ struct synaptics_hw_state { @@ -143,9 +133,6 @@ struct synaptics_hw_state { unsigned int down:1; unsigned char ext_buttons; signed char scroll; - - /* As reported in last AGM-CONTACT packets */ - struct synaptics_mt_state mt_state; }; struct synaptics_data { @@ -170,15 +157,12 @@ struct synaptics_data { struct serio *pt_port; /* Pass-through serio port */ - struct synaptics_mt_state mt_state; /* Current mt finger state */ - bool mt_state_lost; /* mt_state may be incorrect */ - /* * Last received Advanced Gesture Mode (AGM) packet. An AGM packet * contains position data for a second contact, at half resolution. */ struct synaptics_hw_state agm; - bool agm_pending; /* new AGM packet received */ + unsigned int agm_count; /* finger count reported by agm */ /* ForcePad handling */ unsigned long press_start; -- cgit v0.10.2 From aa104b1aaaa3bd132106daccf7fb10eed806d325 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 29 Dec 2014 14:17:44 -0800 Subject: Input: synaptics - remove duplicated code synaptics_profile_sensor_process() and synaptics_report_mt_data() now share the exact same code. Remove one implementation and rely on the other where it was used. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index fd89249..8ae1841 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -851,42 +851,6 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse, synaptics_report_mt_data(psmouse, sgm, num_fingers); } -static void synaptics_profile_sensor_process(struct psmouse *psmouse, - struct synaptics_hw_state *sgm, - int num_fingers) -{ - struct input_dev *dev = psmouse->dev; - struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; - struct input_mt_pos pos[2]; - int slot[2], nsemi, i; - - nsemi = clamp_val(num_fingers, 0, 2); - - for (i = 0; i < nsemi; i++) { - pos[i].x = hw[i]->x; - pos[i].y = synaptics_invert_y(hw[i]->y); - } - - input_mt_assign_slots(dev, slot, pos, nsemi); - - for (i = 0; i < nsemi; i++) { - input_mt_slot(dev, slot[i]); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); - input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); - input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); - input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); - } - - input_mt_drop_unused(dev); - input_mt_report_pointer_emulation(dev, false); - input_mt_report_finger_count(dev, num_fingers); - - synaptics_report_buttons(psmouse, sgm); - - input_sync(dev); -} - /* * called for each full received packet from the touchpad */ @@ -951,7 +915,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) } if (cr48_profile_sensor) { - synaptics_profile_sensor_process(psmouse, &hw, num_fingers); + synaptics_report_mt_data(psmouse, &hw, num_fingers); return; } -- cgit v0.10.2 From 8ea8f3eb9c6aee87e23907fc263108a0f9091c71 Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Fri, 26 Dec 2014 09:26:22 +0100 Subject: Update of Documentation/00-INDEX Added files - hsi.txt was added by 3a8ab8af (HSI: Add some general description for the HSI subsystem) - lzo.txt was added by d98a0526 (lzo: document part of the encoding) - xillybus.txt was added by 7051924f (xillybus: Move out of staging) - mailbox.txt was added by 15320fbc (add documentation for mailbox framework) Moved files - xommit 214e0aed (Move locking related docs into Documentation/locking/): * lockdep-design.txt * lockstat.txt * mutex-design.txt * rt-mutex-design.txt * rt-mutex.txt * spinlocks.txt * ww-mutex-design.txt - kselftest.txt was moved by 3c415707 (kselftest: Move the docs to the Documentation dir) CC: Davidlohr Bueso CC: Willy Tarreau CC: Randy Dunlap CC: Greg Kroah-Hartman CC: Sebastian Reichel CC: Eli Billauer CC: Jonathan Corbet CC: Jiri Kosina CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org Cc: Tim Bird Cc: Shuah Khan Signed-off-by: Henrik Austad Signed-off-by: Jonathan Corbet diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 1750fce..0fb40ac 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -209,6 +209,8 @@ hid/ - directory with information on human interface devices highuid.txt - notes on the change from 16 bit to 32 bit user/group IDs. +hsi.txt + - HSI subsystem overview. hwspinlock.txt - hardware spinlock provides hardware assistance for synchronization timers/ @@ -277,6 +279,8 @@ kprobes.txt - documents the kernel probes debugging feature. kref.txt - docs on adding reference counters (krefs) to kernel objects. +kselftest.txt + - small unittests for (some) individual codepaths in the kernel. laptops/ - directory with laptop related info and laptop driver documentation. ldm.txt @@ -285,22 +289,22 @@ leds/ - directory with info about LED handling under Linux. local_ops.txt - semantics and behavior of local atomic operations. -lockdep-design.txt - - documentation on the runtime locking correctness validator. locking/ - directory with info about kernel locking primitives -lockstat.txt - - info on collecting statistics on locks (and contention). lockup-watchdogs.txt - info on soft and hard lockup detectors (aka nmi_watchdog). logo.gif - full colour GIF image of Linux logo (penguin - Tux). logo.txt - info on creator of above logo & site to get additional images from. +lzo.txt + - kernel LZO decompressor input formats m68k/ - directory with info about Linux on Motorola 68k architecture. magic-number.txt - list of magic numbers used to mark/protect kernel data structures. +mailbox.txt + - How to write drivers for the common mailbox framework (IPC). md.txt - info on boot arguments for the multiple devices driver. media-framework.txt @@ -327,8 +331,6 @@ mtd/ - directory with info about memory technology devices (flash) mono.txt - how to execute Mono-based .NET binaries with the help of BINFMT_MISC. -mutex-design.txt - - info on the generic mutex subsystem. namespaces/ - directory with various information about namespaces netlabel/ @@ -395,10 +397,6 @@ robust-futexes.txt - a description of what robust futexes are. rpmsg.txt - info on the Remote Processor Messaging (rpmsg) Framework -rt-mutex-design.txt - - description of the RealTime mutex implementation design. -rt-mutex.txt - - desc. of RT-mutex subsystem with PI (Priority Inheritance) support. rtc.txt - notes on how to use the Real Time Clock (aka CMOS clock) driver. s390/ @@ -425,8 +423,6 @@ sparse.txt - info on how to obtain and use the sparse tool for typechecking. spi/ - overview of Linux kernel Serial Peripheral Interface (SPI) support. -spinlocks.txt - - info on using spinlocks to provide exclusive access in kernel. stable_api_nonsense.txt - info on why the kernel does not have a stable in-kernel api or abi. stable_kernel_rules.txt @@ -483,10 +479,10 @@ wimax/ - directory with info about Intel Wireless Wimax Connections workqueue.txt - information on the Concurrency Managed Workqueue implementation -ww-mutex-design.txt - - Intro to Mutex wait/would deadlock handling.s x86/x86_64/ - directory with info on Linux support for AMD x86-64 (Hammer) machines. +xillybus.txt + - Overview and basic ui of xillybus driver xtensa/ - directory with documents relating to arch/xtensa port/implementation xz.txt diff --git a/Documentation/locking/00-INDEX b/Documentation/locking/00-INDEX new file mode 100644 index 0000000..c256c9b --- /dev/null +++ b/Documentation/locking/00-INDEX @@ -0,0 +1,16 @@ +00-INDEX + - this file. +lockdep-design.txt + - documentation on the runtime locking correctness validator. +lockstat.txt + - info on collecting statistics on locks (and contention). +mutex-design.txt + - info on the generic mutex subsystem. +rt-mutex-design.txt + - description of the RealTime mutex implementation design. +rt-mutex.txt + - desc. of RT-mutex subsystem with PI (Priority Inheritance) support. +spinlocks.txt + - info on using spinlocks to provide exclusive access in kernel. +ww-mutex-design.txt + - Intro to Mutex wait/would deadlock handling.s -- cgit v0.10.2 From 9007fd324163d3f082ff2898b9b0aec6ae3d872b Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Fri, 26 Dec 2014 09:26:23 +0100 Subject: Update of Documentation/networking/00-INDEX - altera_tse.txt was added by 04add4ab (Add Altera Ethernet (TSE) Documentation) - cdc_mbim.txt was added by a563babe (cdc_mbim: add driver documentation) - dctcp.txt was added by e3118e83 (tcp: add DCTCP congestion control algorithm) CC: Jonathan Corbet CC: "David S. Miller" CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Henrik Austad Signed-off-by: Jonathan Corbet diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 557b6ef..df27a1a 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -1,7 +1,5 @@ 00-INDEX - this file -3c505.txt - - information on the 3Com EtherLink Plus (3c505) driver. 3c509.txt - information on the 3Com Etherlink III Series Ethernet cards. 6pack.txt @@ -24,6 +22,8 @@ README.sb1000 - info on General Instrument/NextLevel SURFboard1000 cable modem. alias.txt - info on using alias network devices. +altera_tse.txt + - Altera Triple-Speed Ethernet controller. arcnet-hardware.txt - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt @@ -42,6 +42,8 @@ bridge.txt - where to get user space programs for ethernet bridging with Linux. can.txt - documentation on CAN protocol family. +cdc_mbim.txt + - 3G/LTE USB modem (Mobile Broadband Interface Model) cops.txt - info on the COPS LocalTalk Linux driver cs89x0.txt @@ -54,6 +56,8 @@ cxgb.txt - Release Notes for the Chelsio N210 Linux device driver. dccp.txt - the Datagram Congestion Control Protocol (DCCP) (RFC 4340..42). +dctcp.txt + - DataCenter TCP congestion control de4x5.txt - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver decnet.txt -- cgit v0.10.2 From 5f6c3ac51db846290264325fa1ce2b5d65e8a803 Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Fri, 26 Dec 2014 09:26:24 +0100 Subject: Update of Documentation/arm/00-INDEX Added: - arm/Makefile was added by adb19fb6 (add makefiles for more targets) - arm/CCN.txt was added by a33b0daa (ARM CCN PMU driver) Removed: - arm/Sharp-LH was removed by 82e6923e (ARM: lh7a40x: remove unmaintained platform support) Not updated: Documentation/arm/msm/ is missing 00-INDEX (1 files) Documentation/arm/Samsung-S3C24XX/ is missing 00-INDEX (12 files) Documentation/arm/nwfpe/ is missing 00-INDEX (4 files) Documentation/arm/OMAP/ is missing 00-INDEX (2 files) Documentation/arm/sunxi/ is missing 00-INDEX (2 files) Documentation/arm/SPEAr/ is missing 00-INDEX (1 files) Documentation/arm/Marvell/ is missing 00-INDEX (1 files) Documentation/arm/SA1100/ is missing 00-INDEX (18 files) Documentation/arm/pxa/ is missing 00-INDEX (1 files) Documentation/arm/sti/ is missing 00-INDEX (4 files) Documentation/arm/SH-Mobile/ is missing 00-INDEX (4 files) Documentation/arm/VFP/ is missing 00-INDEX (1 files) Documentation/arm/Samsung/ is missing 00-INDEX (3 files) Cc: Jonathan Corbet Cc: Pawel Moll Cc: Jiri Kosina Cc: linux-doc@vger.kernel.org (open list:DOCUMENTATION) Cc: linux-kernel@vger.kernel.org (open list) Signed-off-by: Henrik Austad Signed-off-by: Jonathan Corbet diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX index 3b08bc2..8edb900 100644 --- a/Documentation/arm/00-INDEX +++ b/Documentation/arm/00-INDEX @@ -2,11 +2,15 @@ - this file Booting - requirements for booting +CCN.txt + - Cache Coherent Network ring-bus and perf PMU driver. Interrupts - ARM Interrupt subsystem documentation IXP4xx - Intel IXP4xx Network processor. -msm +Makefile + - Build sourcefiles as part of the Documentation-build for arm +msm/ - MSM specific documentation Netwinder - Netwinder specific documentation @@ -18,11 +22,9 @@ README - General ARM documentation SA1100/ - SA1100 documentation -Samsung-S3C24XX +Samsung-S3C24XX/ - S3C24XX ARM Linux Overview -Sharp-LH - - Linux on Sharp LH79524 and LH7A40X System On a Chip (SOC) -SPEAr +SPEAr/ - ST SPEAr platform Linux Overview VFP/ - Release notes for Linux Kernel Vector Floating Point support code -- cgit v0.10.2 From dcf16713c9ebaf50e82ca702a950f0a3256f493f Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Fri, 26 Dec 2014 09:26:25 +0100 Subject: Update of Documentation/cgroups/00-INDEX unified-hierarchy.txt was added by 65731578 (cgroup: add documentation about unified hierarchy) Cc: Tejun Heo Cc: Li Zefan Cc: Jonathan Corbet Cc: cgroups@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Henrik Austad Signed-off-by: Jonathan Corbet diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX index bc461b6..96ce071 100644 --- a/Documentation/cgroups/00-INDEX +++ b/Documentation/cgroups/00-INDEX @@ -24,3 +24,5 @@ net_prio.txt - Network priority cgroups details and usages. resource_counter.txt - Resource Counter API. +unified-hierarchy.txt + - Description the new/next cgroup interface. -- cgit v0.10.2 From 912ee9ca37afb517647af3744726a97f764f419f Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Fri, 26 Dec 2014 09:26:26 +0100 Subject: Update of Documentation/dmaengine/00-INDEX - client.txt was moved by f36d2e67 (dmaengine: Move the current doc to a folder of its own) - dmatmest.txt was moved by 935cdb56 (dmanegine: move dmatest.txt to dmaengine folder) - provider.txt was added by c4d2ae967 (Documentation: dmaengine: Add a documentation for the dma controller API). Cc: Maxime Ripard Cc: Vinod Koul Cc: Jonathan Corbet Cc: dmaengine@vger.kernel.org Cc: linux-doc@vger.kernel.org Signed-off-by: Henrik Austad Signed-off-by: Jonathan Corbet diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 0fb40ac..cd077ca 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -29,8 +29,6 @@ DMA-ISA-LPC.txt - How to do DMA with ISA (and LPC) devices. DMA-attributes.txt - listing of the various possible attributes a DMA region can have -dmatest.txt - - how to compile, configure and use the dmatest system. DocBook/ - directory with DocBook templates etc. for kernel documentation. EDID/ @@ -163,8 +161,6 @@ digsig.txt -info on the Digital Signature Verification API dma-buf-sharing.txt - the DMA Buffer Sharing API Guide -dmaengine.txt - -the DMA Engine API Guide dontdiff - file containing a list of files that should never be diff'ed. driver-model/ diff --git a/Documentation/dmaengine/00-INDEX b/Documentation/dmaengine/00-INDEX new file mode 100644 index 0000000..07de657 --- /dev/null +++ b/Documentation/dmaengine/00-INDEX @@ -0,0 +1,8 @@ +00-INDEX + - this file. +client.txt + -the DMA Engine API Guide. +dmatest.txt + - how to compile, configure and use the dmatest system. +provider.txt + - the DMA controller API. \ No newline at end of file -- cgit v0.10.2 From 2cd14f5da6579175f387f93c0561918647a3b6c6 Mon Sep 17 00:00:00 2001 From: Jeremiah Mahler Date: Fri, 26 Dec 2014 06:57:49 -0800 Subject: doc: driver-model: improve wording "is provide the" Improve the wording by changing it from "is provide the" to "is to give the". Signed-off-by: Jeremiah Mahler Signed-off-by: Jonathan Corbet diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt index 6754b2d..b577a45 100644 --- a/Documentation/driver-model/bus.txt +++ b/Documentation/driver-model/bus.txt @@ -45,7 +45,7 @@ them are inherently bus-specific. Drivers typically declare an array of device IDs of devices they support that reside in a bus-specific driver structure. -The purpose of the match callback is provide the bus an opportunity to +The purpose of the match callback is to give the bus an opportunity to determine if a particular driver supports a particular device by comparing the device IDs the driver supports with the device ID of a particular device, without sacrificing bus-specific functionality or -- cgit v0.10.2 From bf5777bcdc540661f2f5d531a13e4e9c9fb7ee22 Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 22 Dec 2014 20:00:36 -0500 Subject: Documentation: GNU is frequently spelled Gnu The official spelling of GNU is GNU and not Gnu. Bug 89551 https://bugzilla.kernel.org/show_bug.cgi?id=89551 Signed-off-by: Kevin Law Signed-off-by: Jonathan Corbet diff --git a/Documentation/Changes b/Documentation/Changes index 74bdda9..646cdaa 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -21,8 +21,8 @@ running a Linux kernel. Also, not all tools are necessary on all systems; obviously, if you don't have any ISDN hardware, for example, you probably needn't concern yourself with isdn4k-utils. -o Gnu C 3.2 # gcc --version -o Gnu make 3.80 # make --version +o GNU C 3.2 # gcc --version +o GNU make 3.80 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version o module-init-tools 0.9.10 # depmod -V @@ -57,7 +57,7 @@ computer. Make ---- -You will need Gnu make 3.80 or later to build the kernel. +You will need GNU make 3.80 or later to build the kernel. Binutils -------- -- cgit v0.10.2 From 380945365d3824e7c62deb17930453acdcb65eaa Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 17 Oct 2012 20:29:22 +0400 Subject: Documentation: update seq_file Update descriptions of seq_path() and seq_path_root(): starting with commit v3.2-rc4-1-g02125a8, seq_path_root() no longer changes the value of root; starting with commit v3.2-rc7-104-g8c9379e, some arguments of seq_path() and seq_path_root() are const. Signed-off-by: Dmitry V. Levin Acked-by: Rob Landley Signed-off-by: Jonathan Corbet diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index b797ed3..9de4303 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt @@ -194,16 +194,16 @@ which is in the string esc will be represented in octal form in the output. There are also a pair of functions for printing filenames: - int seq_path(struct seq_file *m, struct path *path, char *esc); - int seq_path_root(struct seq_file *m, struct path *path, - struct path *root, char *esc) + int seq_path(struct seq_file *m, const struct path *path, + const char *esc); + int seq_path_root(struct seq_file *m, const struct path *path, + const struct path *root, const char *esc) Here, path indicates the file of interest, and esc is a set of characters which should be escaped in the output. A call to seq_path() will output the path relative to the current process's filesystem root. If a different -root is desired, it can be used with seq_path_root(). Note that, if it -turns out that path cannot be reached from root, the value of root will be -changed in seq_file_root() to a root which *does* work. +root is desired, it can be used with seq_path_root(). If it turns out that +path cannot be reached from root, seq_path_root() returns SEQ_SKIP. A function producing complicated output may want to check bool seq_has_overflowed(struct seq_file *m); -- cgit v0.10.2 From e71e2c6fbbac673f3e222c7a6b6b62bcf6f40fb1 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 29 Dec 2014 16:17:36 -0700 Subject: MAINTAINERS: Add the docs-next git tree to the maintainer entry Signed-off-by: Jonathan Corbet diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8..76f9c0d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3207,6 +3207,7 @@ F: Documentation/ X: Documentation/ABI/ X: Documentation/devicetree/ X: Documentation/[a-z][a-z]_[A-Z][A-Z]/ +T: git git://git.lwn.net/linux-2.6.git docs-next DOUBLETALK DRIVER M: "James R. Van Zandt" -- cgit v0.10.2 From e00bfcbf043877fb85f77daf330a01e057dfcf3b Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Wed, 17 Dec 2014 17:13:56 -0800 Subject: Documentation/SubmittingPatches: unify whitespace/tabs for the DCO The Developers Certificate of Origin has a mixture of tabs and white spaces which is annoying to view if your editor explicitly views white space characters. Also remove any trailing white spaces found in the file. Signed-off-by: Stefan Beller Signed-off-by: Jonathan Corbet diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 1fa1caa..1671ce3 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -223,9 +223,9 @@ Do not send more than 15 patches at once to the vger mailing lists!!! Linus Torvalds is the final arbiter of all changes accepted into the -Linux kernel. His e-mail address is . +Linux kernel. His e-mail address is . He gets a lot of e-mail, so typically you should do your best to -avoid- -sending him e-mail. +sending him e-mail. Patches which are bug fixes, are "obvious" changes, or similarly require little discussion should be sent or CC'd to Linus. Patches @@ -387,11 +387,11 @@ can certify the below: person who certified (a), (b) or (c) and I have not modified it. - (d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. then you just add a line saying @@ -401,7 +401,7 @@ using your real name (sorry, no pseudonyms or anonymous contributions.) Some people also put extra tags at the end. They'll just be ignored for now, but you can do this to mark internal company procedures or just -point out some special detail about the sign-off. +point out some special detail about the sign-off. If you are a subsystem or branch maintainer, sometimes you need to slightly modify patches you receive in order to merge them, because the code is not -- cgit v0.10.2 From 4b5d6aadce5e054d33719a7490076294c83d2f88 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Dec 2014 19:38:51 -0200 Subject: spi: spi-imx: Do not store the irq number in the private structure The irq number is only used inside the probe function, so there is really no need to store it in the private structure. Use a local 'irq' variable to hold the the irq number instead. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 961b97d..6a2ff75 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -89,7 +89,6 @@ struct spi_imx_data { struct completion xfer_done; void __iomem *base; - int irq; struct clk *clk_per; struct clk *clk_ipg; unsigned long spi_clk; @@ -1076,7 +1075,7 @@ static int spi_imx_probe(struct platform_device *pdev) struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; - int i, ret, num_cs; + int i, ret, num_cs, irq; if (!np && !mxc_platform_info) { dev_err(&pdev->dev, "can't get the platform data\n"); @@ -1143,16 +1142,16 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_master_put; } - spi_imx->irq = platform_get_irq(pdev, 0); - if (spi_imx->irq < 0) { - ret = spi_imx->irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; goto out_master_put; } - ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, spi_imx_isr, 0, dev_name(&pdev->dev), spi_imx); if (ret) { - dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); + dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret); goto out_master_put; } -- cgit v0.10.2 From 7c27ba46792d3596a83f28243e235a92cba80d45 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Dec 2014 23:52:35 -0200 Subject: ASoC: fsl_spdif: Use dev_name() for registering the irq The 'name' array is currently stored inside the fsl_spdif_priv private structure only for registering the interrupt name. This can be simplified by registering it with dev_name() instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index af042942..73da1f0 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -90,7 +90,6 @@ struct spdif_mixer_control { * @sysclk: system clock for rx clock rate measurement * @dma_params_tx: DMA parameters for transmit channel * @dma_params_rx: DMA parameters for receive channel - * @name: driver name */ struct fsl_spdif_priv { struct spdif_mixer_control fsl_spdif_control; @@ -109,12 +108,8 @@ struct fsl_spdif_priv { struct clk *sysclk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; - - /* The name space will be allocated dynamically */ - char name[0]; }; - /* DPLL locked and lock loss interrupt handler */ static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) { @@ -1169,19 +1164,15 @@ static int fsl_spdif_probe(struct platform_device *pdev) if (!np) return -ENODEV; - spdif_priv = devm_kzalloc(&pdev->dev, - sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1, - GFP_KERNEL); + spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL); if (!spdif_priv) return -ENOMEM; - strcpy(spdif_priv->name, np->name); - spdif_priv->pdev = pdev; /* Initialize this copy of the CPU DAI driver structure */ memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); - spdif_priv->cpu_dai_drv.name = spdif_priv->name; + spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev); /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1203,7 +1194,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, - spdif_priv->name, spdif_priv); + dev_name(&pdev->dev), spdif_priv); if (ret) { dev_err(&pdev->dev, "could not claim irq %u\n", irq); return ret; -- cgit v0.10.2 From 888c819d0feb9975216978c797ca7f8dfd48ed08 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Dec 2014 23:52:36 -0200 Subject: ASoC: fsl_asrc: Use dev_name() for registering the irq The 'name' array is currently stored inside the fsl_asrc private structure only for registering the interrupt name. This can be simplified by registering it with dev_name() instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 026a801..5326ca7 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -818,7 +818,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) return -ENOMEM; asrc_priv->pdev = pdev; - strncpy(asrc_priv->name, np->name, sizeof(asrc_priv->name) - 1); /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -842,7 +841,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, - asrc_priv->name, asrc_priv); + dev_name(&pdev->dev), asrc_priv); if (ret) { dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); return ret; diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index a3f211f..4aed63c 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -433,7 +433,6 @@ struct fsl_asrc_pair { * @channel_avail: non-occupied channel numbers * @asrc_rate: default sample rate for ASoC Back-Ends * @asrc_width: default sample width for ASoC Back-Ends - * @name: driver name */ struct fsl_asrc { struct snd_dmaengine_dai_dma_data dma_params_rx; @@ -452,8 +451,6 @@ struct fsl_asrc { int asrc_rate; int asrc_width; - - char name[32]; }; extern struct snd_soc_platform_driver fsl_asrc_platform; -- cgit v0.10.2 From 3b952436d4cca59bfdc8ede174dd746a4b31c804 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 10 Dec 2014 10:59:13 -0300 Subject: [media] cx23885: do not unregister demod I2C client twice on error Demod I2C client should be NULL after demod is unregistered on error path, otherwise it will be unregistered again when driver is unload. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index c47d182..6bb7935 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1793,12 +1793,14 @@ static int dvb_register(struct cx23885_tsport *port) client_tuner->dev.driver == NULL) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; goto frontend_detach; } if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; goto frontend_detach; } port->i2c_client_tuner = client_tuner; @@ -1843,12 +1845,14 @@ static int dvb_register(struct cx23885_tsport *port) client_tuner->dev.driver == NULL) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; goto frontend_detach; } if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; goto frontend_detach; } port->i2c_client_tuner = client_tuner; @@ -1989,6 +1993,7 @@ static int dvb_register(struct cx23885_tsport *port) client_tuner->dev.driver == NULL) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; goto frontend_detach; } if (!try_module_get(client_tuner->dev.driver->owner)) { -- cgit v0.10.2 From a593f2cfc1b89d0342b82242ed3d31c1a4494f24 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 10 Dec 2014 11:05:59 -0300 Subject: [media] cx23885: correct some I2C client indentations These comparisons fit single line. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 6bb7935..0f60bc4 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1823,8 +1823,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &si2168_config; request_module(info.type); client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); - if (client_demod == NULL || - client_demod->dev.driver == NULL) + if (client_demod == NULL || client_demod->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_demod->dev.driver->owner)) { i2c_unregister_device(client_demod); @@ -1841,8 +1840,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &si2157_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || - client_tuner->dev.driver == NULL) { + if (client_tuner == NULL || client_tuner->dev.driver == NULL) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); port->i2c_client_demod = NULL; @@ -1878,8 +1876,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &m88ts2022_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || - client_tuner->dev.driver == NULL) + if (client_tuner == NULL || client_tuner->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); @@ -1925,8 +1922,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &m88ts2022_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || - client_tuner->dev.driver == NULL) + if (client_tuner == NULL || client_tuner->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); @@ -1971,8 +1967,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &si2168_config; request_module(info.type); client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); - if (client_demod == NULL || - client_demod->dev.driver == NULL) + if (client_demod == NULL || client_demod->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_demod->dev.driver->owner)) { i2c_unregister_device(client_demod); @@ -1989,8 +1984,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &si2157_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || - client_tuner->dev.driver == NULL) { + if (client_tuner == NULL || client_tuner->dev.driver == NULL) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); port->i2c_client_demod = NULL; @@ -2115,8 +2109,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &sp2_config; request_module(info.type); client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info); - if (client_ci == NULL || - client_ci->dev.driver == NULL) { + if (client_ci == NULL || client_ci->dev.driver == NULL) { if (client_tuner) { module_put(client_tuner->dev.driver->owner); i2c_unregister_device(client_tuner); -- cgit v0.10.2 From 93009ca673394f0bfb99aa8d8e76f3581a2b38e8 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 11 Dec 2014 15:44:51 -0300 Subject: [media] cx23885: fix I2C scan printout 1) I2C slave addresses were printed so called 8-bit format. Use standard 7-bit notation. 2) I2C slave address was printed with hex formatted without leading zeros, which makes output one digit shorter in a case of address fit to one hex digit. Use 4 char wide hex number with leading zeros as usually used for I2C slave addresses. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index fd71306..1135ea3 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -300,8 +300,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + printk(KERN_INFO "%s: i2c scan: found device @ 0x%04x [%s]\n", + name, i, i2c_devs[i] ? i2c_devs[i] : "???"); } } -- cgit v0.10.2 From 1fc77d013ba85a29e2edfaba02fd21e8c8187fae Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 11 Dec 2014 16:12:46 -0300 Subject: [media] cx23885: Hauppauge WinTV-HVR5525 Add board profile for Hauppauge WinTV-HVR5525. Device is build upon following main components: Conexant CX23888 Montage M88RS6000 Allegro A8293 Silicon Labs Si2168-B40 Silicon Labs Si2157-A30 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index f613314..74d774e 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -41,6 +41,7 @@ config VIDEO_CX23885 select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index db99ca2..2a92bcd 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -706,6 +706,11 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR5525] = { + .name = "Hauppauge WinTV-HVR5525", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -989,6 +994,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x4254, .subdevice = 0x0982, .card = CX23885_BOARD_DVBSKY_T982, + }, { + .subvendor = 0x0070, + .subdevice = 0xf038, + .card = CX23885_BOARD_HAUPPAUGE_HVR5525, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1161,6 +1170,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 85721: /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, Dual channel ATSC and Basic analog */ + case 150329: + /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ break; default: printk(KERN_WARNING "%s: warning: " @@ -1632,6 +1643,29 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) msleep(100); cx23885_gpio_set(dev, GPIO_2); break; + case CX23885_BOARD_HAUPPAUGE_HVR5525: + /* + * GPIO-00 IR_WIDE + * GPIO-02 wake# + * GPIO-03 VAUX Pres. + * GPIO-07 PROG# + * GPIO-08 SAT_RESN + * GPIO-09 TER_RESN + * GPIO-10 B2_SENSE + * GPIO-11 B1_SENSE + * GPIO-15 IR_LED_STATUS + * GPIO-19 IR_NARROW + * GPIO-20 Blauster1 + * ALTGPIO VAUX_SWITCH + * AUX_PLL_CLK : Blaster2 + */ + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); + cx23885_gpio_clear(dev, GPIO_8 | GPIO_9); + msleep(100); + cx23885_gpio_set(dev, GPIO_8 | GPIO_9); + msleep(100); + break; } } @@ -1873,6 +1907,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR4400: case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: + case CX23885_BOARD_HAUPPAUGE_HVR5525: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -1997,6 +2032,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR5525: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 0f60bc4..63c0de3 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -74,6 +74,7 @@ #include "sp2.h" #include "m88ds3103.h" #include "m88ts2022.h" +#include "m88rs6000t.h" static unsigned int debug; @@ -915,6 +916,16 @@ static const struct m88ds3103_config dvbsky_s952_portc_m88ds3103_config = { .agc = 0x99, }; +static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = { + .i2c_addr = 0x69, + .clock = 27000000, + .i2c_wr_max = 33, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .agc = 0x99, +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -1999,6 +2010,93 @@ static int dvb_register(struct cx23885_tsport *port) } port->i2c_client_tuner = client_tuner; break; + case CX23885_BOARD_HAUPPAUGE_HVR5525: + switch (port->nr) { + struct m88rs6000t_config m88rs6000t_config; + + /* port b - satellite */ + case 1: + /* attach frontend */ + fe0->dvb.frontend = dvb_attach(m88ds3103_attach, + &hauppauge_hvr5525_m88ds3103_config, + &dev->i2c_bus[0].i2c_adap, &adapter); + if (fe0->dvb.frontend == NULL) + break; + + /* attach SEC */ + if (!dvb_attach(a8293_attach, fe0->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_a8293_config)) + goto frontend_detach; + + /* attach tuner */ + memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config)); + m88rs6000t_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "m88rs6000t", I2C_NAME_SIZE); + info.addr = 0x21; + info.platform_data = &m88rs6000t_config; + request_module("%s", info.type); + client_tuner = i2c_new_device(adapter, &info); + if (!client_tuner || !client_tuner->dev.driver) + goto frontend_detach; + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + + /* delegate signal strength measurement to tuner */ + fe0->dvb.frontend->ops.read_signal_strength = + fe0->dvb.frontend->ops.tuner_ops.get_rf_strength; + break; + /* port c - terrestrial/cable */ + case 2: + /* attach frontend */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &fe0->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module("%s", info.type); + client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module("%s", info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); + if (!client_tuner || !client_tuner->dev.driver) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index f55cd12..4f358eb 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -99,6 +99,7 @@ #define CX23885_BOARD_DVBSKY_S950 49 #define CX23885_BOARD_DVBSKY_S952 50 #define CX23885_BOARD_DVBSKY_T982 51 +#define CX23885_BOARD_HAUPPAUGE_HVR5525 52 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit v0.10.2 From 19f52fae5adb7f2fd5b75251f9bd761f43a36476 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 18:43:36 +0100 Subject: ALSA: Fix handling of multiple msbits constraints on the same runtime If the sound card is made up of discrete components, each with their own driver (e.g. like in the ASoC case), we might end up with multiple msbits constraint rules installed. Currently this will result in msbits being set to whatever the last rule set it to. This patch updates the behavior of the rule to choose the minimum (other than zero) of all the installed rules. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ec9e786..b0c1535 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1300,7 +1300,7 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, unsigned int msbits = l >> 16; struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); if (snd_interval_single(i) && snd_interval_value(i) == width) - params->msbits = msbits; + params->msbits = min_not_zero(params->msbits, msbits); return 0; } -- cgit v0.10.2 From 8ef9df55a72425e269575fa74cbbedec4672bdc4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 18:43:37 +0100 Subject: ALSA: Add support for wildcard msbits constraints Currently the msbits constraints requires to specify a specific sample format width for which the constraint should be applied. But often the number of most significant bits is not sample format specific, but rather a absolute limit. E.g. the PCM interface might accept 32-bit and 24-bit samples, but the DAC has a 16-bit resolution and throws away the LSBs. In this case for both 32-bit and 24-bit format msbits should be set to 16. This patch extends snd_pcm_hw_constraint_msbits() so that a wildcard constraint can be setup that is applied for all formats with a sample width larger than the specified msbits. Choosing the wildcard constraint is done by setting the sample width parameter of the function to 0. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b0c1535..db05e04 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1299,8 +1299,14 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, int width = l & 0xffff; unsigned int msbits = l >> 16; struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - if (snd_interval_single(i) && snd_interval_value(i) == width) + + if (!snd_interval_single(i)) + return 0; + + if ((snd_interval_value(i) == width) || + (width == 0 && snd_interval_value(i) > msbits)) params->msbits = min_not_zero(params->msbits, msbits); + return 0; } @@ -1311,6 +1317,11 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, * @width: sample bits width * @msbits: msbits width * + * This constraint will set the number of most significant bits (msbits) if a + * sample format with the specified width has been select. If width is set to 0 + * the msbits will be set for any sample format with a width larger than the + * specified msbits. + * * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, -- cgit v0.10.2 From 0e2a37513a1fafa0b9829e992633a80861c3b4b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 18:43:38 +0100 Subject: ASoC: pcm: Use wildcard msbits constraints Use the new wildcard msbits constraints instead of installing a constraint for each available sample format width. Signed-off-by: Lars-Peter Clausen Acked-by: Mark Brown Signed-off-by: Takashi Iwai diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index eb87d96e2..d62d6a5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -301,15 +301,6 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) return symmetry; } -/* - * List of sample sizes that might go over the bus for parameter - * application. There ought to be a wildcard sample size for things - * like the DAC/ADC resolution to use but there isn't right now. - */ -static int sample_sizes[] = { - 24, 32, -}; - static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -318,17 +309,10 @@ static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) if (!bits) return; - for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { - if (bits >= sample_sizes[i]) - continue; - - ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, - sample_sizes[i], bits); - if (ret != 0) - dev_warn(rtd->dev, - "ASoC: Failed to set MSB %d/%d: %d\n", - bits, sample_sizes[i], ret); - } + ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits); + if (ret != 0) + dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n", + bits, ret); } static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) -- cgit v0.10.2 From 26c0d8a415e5c4a01faf24165ec9dea821f6a908 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:38 +0100 Subject: ALSA: pcm_params: Remove unused add/sub functions Those two functions are not used anywhere and also their name is a bit to generic to be in a global header, so remove them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 6b1c78f..15760f5 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -325,20 +325,6 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn i1->max == i2->max && i1->openmax == i2->openmax; } -static inline unsigned int add(unsigned int a, unsigned int b) -{ - if (a >= UINT_MAX - b) - return UINT_MAX; - return a + b; -} - -static inline unsigned int sub(unsigned int a, unsigned int b) -{ - if (a > b) - return a - b; - return 0; -} - #define params_access(p) ((__force snd_pcm_access_t)\ snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS))) #define params_format(p) ((__force snd_pcm_format_t)\ -- cgit v0.10.2 From b3a8c862cd33b97c920122248ed9931af546de54 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:39 +0100 Subject: ALSA: pcm: Remove unused SNDRV_PCM_IOCTL1_{FALSE,TRUE} defines Both SNDRV_PCM_IOCTL1_FALSE and SNDRV_PCM_IOCTL1_TRUE are unused and have in fact never been used (at least as far as the git history goes). Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index b429b73..3652c94 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -94,9 +94,6 @@ struct snd_pcm_ops { #define SNDRV_PCM_DEVICES 8 #endif -#define SNDRV_PCM_IOCTL1_FALSE ((void *)0) -#define SNDRV_PCM_IOCTL1_TRUE ((void *)1) - #define SNDRV_PCM_IOCTL1_RESET 0 #define SNDRV_PCM_IOCTL1_INFO 1 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 -- cgit v0.10.2 From 744c2ad2f98965473880ef85cac2f8a8ca95959f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:41 +0100 Subject: ALSA: pcm: Convert params_* mask helpers to static inline functions Use static inline functions instead of macros for the remaining params_*() helpers that have not been converted yet. This is slightly cleaner and offers better type safety. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 15760f5..bf51f22 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -325,12 +325,24 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn i1->max == i2->max && i1->openmax == i2->openmax; } -#define params_access(p) ((__force snd_pcm_access_t)\ - snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS))) -#define params_format(p) ((__force snd_pcm_format_t)\ - snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT))) -#define params_subformat(p) \ - snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) +static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p) +{ + return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p, + SNDRV_PCM_HW_PARAM_ACCESS)); +} + +static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p) +{ + return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p, + SNDRV_PCM_HW_PARAM_FORMAT)); +} + +static inline snd_pcm_subformat_t +params_subformat(const struct snd_pcm_hw_params *p) +{ + return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p, + SNDRV_PCM_HW_PARAM_SUBFORMAT)); +} static inline unsigned int params_period_bytes(const struct snd_pcm_hw_params *p) -- cgit v0.10.2 From 89827ca9dd6173da7dcc035653bea67fa6ac0cbf Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:42 +0100 Subject: ALSA: pcm: Add kernel doc for params_*() functions Add kernel doc for the remaining undocumented params_*() functions. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index bf51f22..2e2169e 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -325,18 +325,30 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn i1->max == i2->max && i1->openmax == i2->openmax; } +/** + * params_access - get the access type from the hw params + * @p: hw params + */ static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p) { return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_ACCESS)); } +/** + * params_format - get the sample format from the hw params + * @p: hw params + */ static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p) { return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_FORMAT)); } +/** + * params_subformat - get the sample subformat from the hw params + * @p: hw params + */ static inline snd_pcm_subformat_t params_subformat(const struct snd_pcm_hw_params *p) { @@ -344,6 +356,10 @@ params_subformat(const struct snd_pcm_hw_params *p) SNDRV_PCM_HW_PARAM_SUBFORMAT)); } +/** + * params_period_bytes - get the period size (in bytes) from the hw params + * @p: hw params + */ static inline unsigned int params_period_bytes(const struct snd_pcm_hw_params *p) { @@ -352,14 +368,27 @@ params_period_bytes(const struct snd_pcm_hw_params *p) params_channels(p)) / 8; } -static inline int -params_width(const struct snd_pcm_hw_params *p) +/** + * params_width - get the number of bits of the sample format from the hw params + * @p: hw params + * + * This function returns the number of bits per sample that the selected sample + * format of the hw params has. + */ +static inline int params_width(const struct snd_pcm_hw_params *p) { return snd_pcm_format_width(params_format(p)); } -static inline int -params_physical_width(const struct snd_pcm_hw_params *p) +/* + * params_physical_width - get the storage size of the sample format from the hw params + * @p: hw params + * + * This functions returns the number of bits per sample that the selected sample + * format of the hw params takes up in memory. This will be equal or larger than + * params_width(). + */ +static inline int params_physical_width(const struct snd_pcm_hw_params *p) { return snd_pcm_format_physical_width(params_format(p)); } -- cgit v0.10.2 From cd9978f1d3dbb9596a7ab9c652cb0d9b355489b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:43 +0100 Subject: ALSA: pcm: Simplify params_period_bytes() The hw_params struct has a parameter that contains the period size in bytes. This can be used instead of deriving the value from other parameters. This is similar to e.g. params_buffer_bytes() Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 2e2169e..042049b 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -363,9 +363,7 @@ params_subformat(const struct snd_pcm_hw_params *p) static inline unsigned int params_period_bytes(const struct snd_pcm_hw_params *p) { - return (params_period_size(p) * - snd_pcm_format_physical_width(params_format(p)) * - params_channels(p)) / 8; + return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min; } /** -- cgit v0.10.2 From 599ee3291ae88700749e2910a11d1c0f0532355e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:44 +0100 Subject: ALSA: pcm: Use __ffs() instead of ffs() in snd_mask_min() The difference between __ffs and ffs is that ffs will return a one based index whereas __ffs will return a zero based index. Furthermore ffs will check if the passed value is zero and return zero in that case, whereas __ffs behavior is undefined if the passed parameter is 0. Since we already check if the mask is 0 before calling ffs and also subtract 1 from the result __ffs is the better choice. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 042049b..c99e20b 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -92,7 +92,7 @@ static inline unsigned int snd_mask_min(const struct snd_mask *mask) int i; for (i = 0; i < SNDRV_MASK_SIZE; i++) { if (mask->bits[i]) - return ffs(mask->bits[i]) - 1 + (i << 5); + return __ffs(mask->bits[i]) + (i << 5); } return 0; } -- cgit v0.10.2 From f6dbe1bee59741cd7699e7da3019e67c77d9bd6f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:45 +0100 Subject: ALSA: snd_pcm_oss_period_size: Use round{up,down}_pow_of_two() Instead of opencoding them use the standard roundup_pow_of_two() and rounddown_pow_of_two() helper functions. This gets rids one of the few users of the custom ld2() function and also makes it a bit more obvious what the code does. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index ada69d7..80423a4c 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -719,7 +719,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, oss_buffer_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size; - oss_buffer_size = 1 << ld2(oss_buffer_size); + oss_buffer_size = rounddown_pow_of_two(oss_buffer_size); if (atomic_read(&substream->mmap_count)) { if (oss_buffer_size > runtime->oss.mmap_bytes) oss_buffer_size = runtime->oss.mmap_bytes; @@ -755,14 +755,14 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, min_period_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL)); min_period_size *= oss_frame_size; - min_period_size = 1 << (ld2(min_period_size - 1) + 1); + min_period_size = roundup_pow_of_two(min_period_size); if (oss_period_size < min_period_size) oss_period_size = min_period_size; max_period_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL)); max_period_size *= oss_frame_size; - max_period_size = 1 << ld2(max_period_size); + max_period_size = rounddown_pow_of_two(max_period_size); if (oss_period_size > max_period_size) oss_period_size = max_period_size; -- cgit v0.10.2 From 757b037650c9ecca79a46ab744820b1b3c1bb49d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Dec 2014 19:41:46 +0100 Subject: ALSA: pcm: Replace custom ld2 function with __fls __fls has the same semantics as ld2, so there is no need to re-implement it. Furthermore a lot of architectures have custom implementations of __fls that are able to use special hardware instructions to compute the result. This makes the code slightly shorter and faster. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index c99e20b..3c45f39 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -38,31 +38,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, #define MASK_OFS(i) ((i) >> 5) #define MASK_BIT(i) (1U << ((i) & 31)) -static inline unsigned int ld2(u_int32_t v) -{ - unsigned r = 0; - - if (v >= 0x10000) { - v >>= 16; - r += 16; - } - if (v >= 0x100) { - v >>= 8; - r += 8; - } - if (v >= 0x10) { - v >>= 4; - r += 4; - } - if (v >= 4) { - v >>= 2; - r += 2; - } - if (v >= 2) - r++; - return r; -} - static inline size_t snd_mask_sizeof(void) { return sizeof(struct snd_mask); @@ -102,7 +77,7 @@ static inline unsigned int snd_mask_max(const struct snd_mask *mask) int i; for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) { if (mask->bits[i]) - return ld2(mask->bits[i]) + (i << 5); + return __fls(mask->bits[i]) + (i << 5); } return 0; } -- cgit v0.10.2 From 5a1b8a80daa15e5b1920735133b80dd46975765f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Dec 2014 16:10:32 +0200 Subject: ASoC: davinci-mcasp: Support for combined tx/rx interrupt line Some SoC, like da850/OMAP-L138 uses one common interrupt request for TX/RX events. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 30b94d4..95eef58 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -364,6 +364,20 @@ static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) return IRQ_RETVAL(handled_mask); } +static irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data) +{ + struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; + irqreturn_t ret = IRQ_NONE; + + if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]) + ret = davinci_mcasp_tx_irq_handler(irq, data); + + if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]) + ret |= davinci_mcasp_rx_irq_handler(irq, data); + + return ret; +} + static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { @@ -1441,6 +1455,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->dev = &pdev->dev; + irq = platform_get_irq_byname(pdev, "common"); + if (irq >= 0) { + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common\n", + dev_name(&pdev->dev)); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + davinci_mcasp_common_irq_handler, + IRQF_ONESHOT, irq_name, mcasp); + if (ret) { + dev_err(&pdev->dev, "common IRQ request failed\n"); + goto err; + } + + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; + } + irq = platform_get_irq_byname(pdev, "rx"); if (irq >= 0) { irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n", -- cgit v0.10.2 From 5396ecf7b1920595deec83b902502bd3d2da184e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 30 Dec 2014 12:11:36 -0200 Subject: ASoC: mxs-saif: Do not store the irq number in the private structure The irq number is only used inside the probe function, so there is really no need to store it in the private structure. Use a local 'irq' variable to hold the the irq number instead. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index d986508..c866ade 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -710,7 +710,7 @@ static int mxs_saif_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct resource *iores; struct mxs_saif *saif; - int ret = 0; + int irq, ret = 0; struct device_node *master; if (!np) @@ -763,16 +763,16 @@ static int mxs_saif_probe(struct platform_device *pdev) if (IS_ERR(saif->base)) return PTR_ERR(saif->base); - saif->irq = platform_get_irq(pdev, 0); - if (saif->irq < 0) { - ret = saif->irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; dev_err(&pdev->dev, "failed to get irq resource: %d\n", ret); return ret; } saif->dev = &pdev->dev; - ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, + ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, dev_name(&pdev->dev), saif); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h index fbaf7ba..9a4c0b2 100644 --- a/sound/soc/mxs/mxs-saif.h +++ b/sound/soc/mxs/mxs-saif.h @@ -116,7 +116,6 @@ struct mxs_saif { unsigned int mclk; unsigned int mclk_in_use; void __iomem *base; - int irq; unsigned int id; unsigned int master_id; unsigned int cur_rate; -- cgit v0.10.2 From a56257c657eab392d579e6be70e2f8430eef1aa3 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 30 Dec 2014 10:55:43 +0000 Subject: ASoC: dwc: Switch to managed clock resource Simplify error handling during probe by using managed clock resources. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 23a7c13..10219b5 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -396,13 +396,13 @@ static int dw_i2s_probe(struct platform_device *pdev) dev->capability = pdata->cap; dev->i2s_clk_cfg = pdata->i2s_clk_cfg; - dev->clk = clk_get(&pdev->dev, NULL); + dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); ret = clk_enable(dev->clk); if (ret < 0) - goto err_clk_put; + return ret; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, @@ -416,19 +416,13 @@ static int dw_i2s_probe(struct platform_device *pdev) err_clk_disable: clk_disable(dev->clk); -err_clk_put: - clk_put(dev->clk); return ret; } static int dw_i2s_remove(struct platform_device *pdev) { - struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - clk_put(dev->clk); - return 0; } -- cgit v0.10.2 From b226efe5818bf01cecc8a3e0fbd0def4ebbcedaa Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 30 Dec 2014 10:55:45 +0000 Subject: ASoC: dwc: Read I2S block configuration from registers The I2S block provides component parameter registers which describe how the block is instantiated. Use these registers to extract the block's configuration rather than relying on platform data. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 10219b5..d3bdc68 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -54,6 +54,31 @@ #define I2S_COMP_VERSION 0x01F8 #define I2S_COMP_TYPE 0x01FC +/* + * Component parameter register fields - define the I2S block's + * configuration. + */ +#define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25) +#define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22) +#define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19) +#define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16) +#define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9) +#define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7) +#define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6) +#define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5) +#define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4) +#define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2) +#define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0) + +#define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10) +#define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7) +#define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3) +#define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0) + +/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */ +#define COMP_MAX_WORDSIZE (1 << 3) +#define COMP_MAX_DATA_WIDTH (1 << 2) + #define MAX_CHANNEL_NUM 8 #define MIN_CHANNEL_NUM 2 @@ -324,11 +349,50 @@ static int dw_i2s_resume(struct snd_soc_dai *dai) #define dw_i2s_resume NULL #endif -static void dw_configure_dai_by_pd(struct dw_i2s_dev *dev, +/* + * The following tables allow a direct lookup of various parameters + * defined in the I2S block's configuration in terms of sound system + * parameters. Each table is sized to the number of entries possible + * according to the number of configuration bits describing an I2S + * block parameter. + */ + +/* Width of (DMA) bus */ +static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = { + DMA_SLAVE_BUSWIDTH_1_BYTE, + DMA_SLAVE_BUSWIDTH_2_BYTES, + DMA_SLAVE_BUSWIDTH_4_BYTES, + DMA_SLAVE_BUSWIDTH_UNDEFINED +}; + +/* PCM format to support channel resolution */ +static const u32 formats[COMP_MAX_WORDSIZE] = { + SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S32_LE, + 0, + 0, + 0 +}; + +static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, struct snd_soc_dai_driver *dw_i2s_dai, struct resource *res, const struct i2s_platform_data *pdata) { + /* + * Read component parameter registers to extract + * the I2S block's configuration. + */ + u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); + u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 idx = COMP1_APB_DATA_WIDTH(comp1); + + if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) + return -EINVAL; + /* Set DMA slaves info */ dev->play_dma_data.data = pdata->play_dma_data; @@ -337,26 +401,36 @@ static void dw_configure_dai_by_pd(struct dw_i2s_dev *dev, dev->capture_dma_data.addr = res->start + I2S_RXDMA; dev->play_dma_data.max_burst = 16; dev->capture_dma_data.max_burst = 16; - dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + dev->play_dma_data.addr_width = bus_widths[idx]; + dev->capture_dma_data.addr_width = bus_widths[idx]; dev->play_dma_data.filter = pdata->filter; dev->capture_dma_data.filter = pdata->filter; - if (pdata->cap & DWC_I2S_PLAY) { + if (COMP1_TX_ENABLED(comp1)) { dev_dbg(dev->dev, " designware: play supported\n"); + idx = COMP1_TX_WORDSIZE_0(comp1); + if (WARN_ON(idx >= ARRAY_SIZE(formats))) + return -EINVAL; dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->playback.channels_max = pdata->channel; - dw_i2s_dai->playback.formats = pdata->snd_fmts; + dw_i2s_dai->playback.channels_max = + 1 << (COMP1_TX_CHANNELS(comp1) + 1); + dw_i2s_dai->playback.formats = formats[idx]; dw_i2s_dai->playback.rates = pdata->snd_rates; } - if (pdata->cap & DWC_I2S_RECORD) { + if (COMP1_RX_ENABLED(comp1)) { dev_dbg(dev->dev, "designware: record supported\n"); + idx = COMP2_RX_WORDSIZE_0(comp2); + if (WARN_ON(idx >= ARRAY_SIZE(formats))) + return -EINVAL; dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->capture.channels_max = pdata->channel; - dw_i2s_dai->capture.formats = pdata->snd_fmts; + dw_i2s_dai->capture.channels_max = + 1 << (COMP1_RX_CHANNELS(comp1) + 1); + dw_i2s_dai->capture.formats = formats[idx]; dw_i2s_dai->capture.rates = pdata->snd_rates; } + + return 0; } static int dw_i2s_probe(struct platform_device *pdev) @@ -392,7 +466,9 @@ static int dw_i2s_probe(struct platform_device *pdev) return PTR_ERR(dev->i2s_base); dev->dev = &pdev->dev; - dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); + ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); + if (ret < 0) + return ret; dev->capability = pdata->cap; dev->i2s_clk_cfg = pdata->i2s_clk_cfg; -- cgit v0.10.2 From 3a19272a507cd5ad214e0082c3ff7355dfe71329 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 30 Dec 2014 10:55:44 +0000 Subject: ASoC: dwc: Prepare clock before use Some I2S clocks may require some time to get the clock ready for operation and so need to be prepared before they are enabled. So, prepare the clock as well as enabling it, but combine the two through clk_prepare_enable. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index d3bdc68..a6327cc 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -476,7 +476,7 @@ static int dw_i2s_probe(struct platform_device *pdev) if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); - ret = clk_enable(dev->clk); + ret = clk_prepare_enable(dev->clk); if (ret < 0) return ret; @@ -491,13 +491,16 @@ static int dw_i2s_probe(struct platform_device *pdev) return 0; err_clk_disable: - clk_disable(dev->clk); + clk_disable_unprepare(dev->clk); return ret; } static int dw_i2s_remove(struct platform_device *pdev) { + struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + clk_disable_unprepare(dev->clk); return 0; } -- cgit v0.10.2 From 758c2debcbf1a4ba6a787d276ca0fb3333105b06 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 30 Dec 2014 10:55:46 +0000 Subject: ASoC: dwc: Register components with managed interface Register SOC component using managed interface to simplify error handling and future introduction of device tree. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index a6327cc..1b9b18b 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -481,7 +481,7 @@ static int dw_i2s_probe(struct platform_device *pdev) return ret; dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, + ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component, dw_i2s_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "not able to register dai\n"); @@ -499,7 +499,6 @@ static int dw_i2s_remove(struct platform_device *pdev) { struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); clk_disable_unprepare(dev->clk); return 0; -- cgit v0.10.2 From d8b58e0b5322f91eb6fcffc337a74083a24c7149 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 30 Dec 2014 10:55:47 +0000 Subject: ASoC: dwc: Add documentation for I2S DT Add documentation for Designware I2S hardware block. The block requires one clock (for audio sampling) and DMA channels for receive and transmit. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt new file mode 100644 index 0000000..7bb5424 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/designware-i2s.txt @@ -0,0 +1,31 @@ +DesignWare I2S controller + +Required properties: + - compatible : Must be "snps,designware-i2s" + - reg : Must contain the I2S core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's + clocks. The controller expects one clock: the clock used as the sampling + rate reference clock sample. + - clock-names : "i2sclk" for the sample rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channels that are used by + the core. The core expects one or two dma channels: one for transmit and + one for receive. + - dma-names : "tx" for the transmit channel, "rx" for the receive channel. + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' +properties please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + soc_i2s: i2s@7ff90000 { + compatible = "snps,designware-i2s"; + reg = <0x0 0x7ff90000 0x0 0x1000>; + clocks = <&scpi_i2sclk 0>; + clock-names = "i2sclk"; + #sound-dai-cells = <0>; + dmas = <&dma0 5>; + dma-names = "tx"; + }; -- cgit v0.10.2 From 0d274544bfee721b22b484a10b1480e237c0e258 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 30 Dec 2014 10:55:48 +0000 Subject: ASoC: dwc: Add devicetree support for Designware I2S Allow the driver to be configured through a device tree rather than platform data. Signed-off-by: Andrew Jackson Signed-off-by: Mark Brown diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig index e334900..d50e085 100644 --- a/sound/soc/dwc/Kconfig +++ b/sound/soc/dwc/Kconfig @@ -1,6 +1,7 @@ config SND_DESIGNWARE_I2S tristate "Synopsys I2S Device Driver" depends on CLKDEV_LOOKUP + select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for I2S driver for Synopsys desigwnware I2S device. The device supports upto diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 1b9b18b..adefdf0 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -22,6 +22,7 @@ #include #include #include +#include /* common register for all channel */ #define IER 0x000 @@ -82,6 +83,11 @@ #define MAX_CHANNEL_NUM 8 #define MIN_CHANNEL_NUM 2 +union dw_i2s_snd_dma_data { + struct i2s_dma_data pd; + struct snd_dmaengine_dai_dma_data dt; +}; + struct dw_i2s_dev { void __iomem *i2s_base; struct clk *clk; @@ -90,8 +96,8 @@ struct dw_i2s_dev { struct device *dev; /* data related to DMA transfers b/w i2s and DMAC */ - struct i2s_dma_data play_dma_data; - struct i2s_dma_data capture_dma_data; + union dw_i2s_snd_dma_data play_dma_data; + union dw_i2s_snd_dma_data capture_dma_data; struct i2s_clk_config_data config; int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); }; @@ -178,7 +184,7 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); - struct i2s_dma_data *dma_data = NULL; + union dw_i2s_snd_dma_data *dma_data = NULL; if (!(dev->capability & DWC_I2S_RECORD) && (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) @@ -270,13 +276,21 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, config->sample_rate = params_rate(params); - if (!dev->i2s_clk_cfg) - return -EINVAL; + if (dev->i2s_clk_cfg) { + ret = dev->i2s_clk_cfg(config); + if (ret < 0) { + dev_err(dev->dev, "runtime audio clk config fail\n"); + return ret; + } + } else { + u32 bitclk = config->sample_rate * config->data_width * 2; - ret = dev->i2s_clk_cfg(config); - if (ret < 0) { - dev_err(dev->dev, "runtime audio clk config fail\n"); - return ret; + ret = clk_set_rate(dev->clk, bitclk); + if (ret) { + dev_err(dev->dev, "Can't set I2S clock rate: %d\n", + ret); + return ret; + } } return 0; @@ -357,6 +371,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai) * block parameter. */ +/* Maximum bit resolution of a channel - not uniformly spaced */ +static const u32 fifo_width[COMP_MAX_WORDSIZE] = { + 12, 16, 20, 24, 32, 0, 0, 0 +}; + /* Width of (DMA) bus */ static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = { DMA_SLAVE_BUSWIDTH_1_BYTE, @@ -377,10 +396,9 @@ static const u32 formats[COMP_MAX_WORDSIZE] = { 0 }; -static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, +static int dw_configure_dai(struct dw_i2s_dev *dev, struct snd_soc_dai_driver *dw_i2s_dai, - struct resource *res, - const struct i2s_platform_data *pdata) + unsigned int rates) { /* * Read component parameter registers to extract @@ -388,23 +406,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, */ u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); - u32 idx = COMP1_APB_DATA_WIDTH(comp1); - - if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) - return -EINVAL; - - /* Set DMA slaves info */ - - dev->play_dma_data.data = pdata->play_dma_data; - dev->capture_dma_data.data = pdata->capture_dma_data; - dev->play_dma_data.addr = res->start + I2S_TXDMA; - dev->capture_dma_data.addr = res->start + I2S_RXDMA; - dev->play_dma_data.max_burst = 16; - dev->capture_dma_data.max_burst = 16; - dev->play_dma_data.addr_width = bus_widths[idx]; - dev->capture_dma_data.addr_width = bus_widths[idx]; - dev->play_dma_data.filter = pdata->filter; - dev->capture_dma_data.filter = pdata->filter; + u32 idx; if (COMP1_TX_ENABLED(comp1)) { dev_dbg(dev->dev, " designware: play supported\n"); @@ -415,7 +417,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, dw_i2s_dai->playback.channels_max = 1 << (COMP1_TX_CHANNELS(comp1) + 1); dw_i2s_dai->playback.formats = formats[idx]; - dw_i2s_dai->playback.rates = pdata->snd_rates; + dw_i2s_dai->playback.rates = rates; } if (COMP1_RX_ENABLED(comp1)) { @@ -427,10 +429,86 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, dw_i2s_dai->capture.channels_max = 1 << (COMP1_RX_CHANNELS(comp1) + 1); dw_i2s_dai->capture.formats = formats[idx]; - dw_i2s_dai->capture.rates = pdata->snd_rates; + dw_i2s_dai->capture.rates = rates; + } + + return 0; +} + +static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, + struct snd_soc_dai_driver *dw_i2s_dai, + struct resource *res, + const struct i2s_platform_data *pdata) +{ + u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); + u32 idx = COMP1_APB_DATA_WIDTH(comp1); + int ret; + + if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) + return -EINVAL; + + ret = dw_configure_dai(dev, dw_i2s_dai, pdata->snd_rates); + if (ret < 0) + return ret; + + /* Set DMA slaves info */ + dev->play_dma_data.pd.data = pdata->play_dma_data; + dev->capture_dma_data.pd.data = pdata->capture_dma_data; + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; + dev->play_dma_data.pd.max_burst = 16; + dev->capture_dma_data.pd.max_burst = 16; + dev->play_dma_data.pd.addr_width = bus_widths[idx]; + dev->capture_dma_data.pd.addr_width = bus_widths[idx]; + dev->play_dma_data.pd.filter = pdata->filter; + dev->capture_dma_data.pd.filter = pdata->filter; + + return 0; +} + +static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, + struct snd_soc_dai_driver *dw_i2s_dai, + struct resource *res) +{ + u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); + u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); + u32 idx = COMP1_APB_DATA_WIDTH(comp1); + u32 idx2; + int ret; + + if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) + return -EINVAL; + + ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000); + if (ret < 0) + return ret; + + if (COMP1_TX_ENABLED(comp1)) { + idx2 = COMP1_TX_WORDSIZE_0(comp1); + + dev->capability |= DWC_I2S_PLAY; + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; + dev->play_dma_data.dt.addr_width = bus_widths[idx]; + dev->play_dma_data.dt.chan_name = "TX"; + dev->play_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[idx2]) >> 8; + dev->play_dma_data.dt.maxburst = 16; + } + if (COMP1_RX_ENABLED(comp1)) { + idx2 = COMP2_RX_WORDSIZE_0(comp2); + + dev->capability |= DWC_I2S_RECORD; + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; + dev->capture_dma_data.dt.addr_width = bus_widths[idx]; + dev->capture_dma_data.dt.chan_name = "RX"; + dev->capture_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[idx2] >> 8); + dev->capture_dma_data.dt.maxburst = 16; } return 0; + } static int dw_i2s_probe(struct platform_device *pdev) @@ -441,11 +519,6 @@ static int dw_i2s_probe(struct platform_device *pdev) int ret; struct snd_soc_dai_driver *dw_i2s_dai; - if (!pdata) { - dev_err(&pdev->dev, "Invalid platform data\n"); - return -EINVAL; - } - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) { dev_warn(&pdev->dev, "kzalloc fail\n"); @@ -466,15 +539,28 @@ static int dw_i2s_probe(struct platform_device *pdev) return PTR_ERR(dev->i2s_base); dev->dev = &pdev->dev; - ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); - if (ret < 0) - return ret; + if (pdata) { + ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); + if (ret < 0) + return ret; + + dev->capability = pdata->cap; + dev->i2s_clk_cfg = pdata->i2s_clk_cfg; + if (!dev->i2s_clk_cfg) { + dev_err(&pdev->dev, "no clock configure method\n"); + return -ENODEV; + } + + dev->clk = devm_clk_get(&pdev->dev, NULL); + } else { + ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res); + if (ret < 0) + return ret; - dev->capability = pdata->cap; - dev->i2s_clk_cfg = pdata->i2s_clk_cfg; - dev->clk = devm_clk_get(&pdev->dev, NULL); + dev->clk = devm_clk_get(&pdev->dev, "i2sclk"); + } if (IS_ERR(dev->clk)) - return PTR_ERR(dev->clk); + return PTR_ERR(dev->clk); ret = clk_prepare_enable(dev->clk); if (ret < 0) @@ -488,6 +574,15 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_clk_disable; } + if (!pdata) { + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { + dev_err(&pdev->dev, + "Could not register PCM: %d\n", ret); + goto err_clk_disable; + } + } + return 0; err_clk_disable: @@ -504,11 +599,23 @@ static int dw_i2s_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id dw_i2s_of_match[] = { + { .compatible = "snps,designware-i2s", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dw_i2s_of_match); +#endif + static struct platform_driver dw_i2s_driver = { .probe = dw_i2s_probe, .remove = dw_i2s_remove, .driver = { .name = "designware-i2s", +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(dw_i2s_of_match), +#endif }, }; -- cgit v0.10.2 From 734d16801349fbe951d2f780191d32c5b8a892d1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 14:45:12 -0800 Subject: rcu: Make rcu_nmi_enter() handle nesting The x86 architecture has multiple types of NMI-like interrupts: real NMIs, machine checks, and, for some values of NMI-like, debugging and breakpoint interrupts. These interrupts can nest inside each other. Andy Lutomirski is adding RCU support to these interrupts, so rcu_nmi_enter() and rcu_nmi_exit() must now correctly handle nesting. This commit therefore introduces nesting, using a clever NMI-coordination algorithm suggested by Andy. The trick is to atomically increment ->dynticks (if needed) before manipulating ->dynticks_nmi_nesting on entry (and, accordingly, after on exit). In addition, ->dynticks_nmi_nesting is incremented by one if ->dynticks was incremented and by two otherwise. This means that when rcu_nmi_exit() sees ->dynticks_nmi_nesting equal to one, it knows that ->dynticks must be atomically incremented. This NMI-coordination algorithms has been validated by the following Promela model: ------------------------------------------------------------------------ /* * Promela model for Andy Lutomirski's suggested change to rcu_nmi_enter() * that allows nesting. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you can access it online at * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2014 * * Author: Paul E. McKenney */ byte dynticks_nmi_nesting = 0; byte dynticks = 0; /* * Promela verision of rcu_nmi_enter(). */ inline rcu_nmi_enter() { byte incby; byte tmp; incby = BUSY_INCBY; assert(dynticks_nmi_nesting >= 0); if :: (dynticks & 1) == 0 -> atomic { dynticks = dynticks + 1; } assert((dynticks & 1) == 1); incby = 1; :: else -> skip; fi; tmp = dynticks_nmi_nesting; tmp = tmp + incby; dynticks_nmi_nesting = tmp; assert(dynticks_nmi_nesting >= 1); } /* * Promela verision of rcu_nmi_exit(). */ inline rcu_nmi_exit() { byte tmp; assert(dynticks_nmi_nesting > 0); assert((dynticks & 1) != 0); if :: dynticks_nmi_nesting != 1 -> tmp = dynticks_nmi_nesting; tmp = tmp - BUSY_INCBY; dynticks_nmi_nesting = tmp; :: else -> dynticks_nmi_nesting = 0; atomic { dynticks = dynticks + 1; } assert((dynticks & 1) == 0); fi; } /* * Base-level NMI runs non-atomically. Crudely emulates process-level * dynticks-idle entry/exit. */ proctype base_NMI() { byte busy; busy = 0; do :: /* Emulate base-level dynticks and not. */ if :: 1 -> atomic { dynticks = dynticks + 1; } busy = 1; :: 1 -> skip; fi; /* Verify that we only sometimes have base-level dynticks. */ if :: busy == 0 -> skip; :: busy == 1 -> skip; fi; /* Model RCU's NMI entry and exit actions. */ rcu_nmi_enter(); assert((dynticks & 1) == 1); rcu_nmi_exit(); /* Emulated re-entering base-level dynticks and not. */ if :: !busy -> skip; :: busy -> atomic { dynticks = dynticks + 1; } busy = 0; fi; /* We had better now be in dyntick-idle mode. */ assert((dynticks & 1) == 0); od; } /* * Nested NMI runs atomically to emulate interrupting base_level(). */ proctype nested_NMI() { do :: /* * Use an atomic section to model a nested NMI. This is * guaranteed to interleave into base_NMI() between a pair * of base_NMI() statements, just as a nested NMI would. */ atomic { /* Verify that we only sometimes are in dynticks. */ if :: (dynticks & 1) == 0 -> skip; :: (dynticks & 1) == 1 -> skip; fi; /* Model RCU's NMI entry and exit actions. */ rcu_nmi_enter(); assert((dynticks & 1) == 1); rcu_nmi_exit(); } od; } init { run base_NMI(); run nested_NMI(); } ------------------------------------------------------------------------ The following script can be used to run this model if placed in rcu_nmi.spin: ------------------------------------------------------------------------ if ! spin -a rcu_nmi.spin then echo Spin errors!!! exit 1 fi if ! cc -DSAFETY -o pan pan.c then echo Compilation errors!!! exit 1 fi ./pan -m100000 Signed-off-by: Paul E. McKenney Reviewed-by: Lai Jiangshan diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 7680fc2..4c106fc 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -759,39 +759,71 @@ void rcu_irq_enter(void) /** * rcu_nmi_enter - inform RCU of entry to NMI context * - * If the CPU was idle with dynamic ticks active, and there is no - * irq handler running, this updates rdtp->dynticks_nmi to let the - * RCU grace-period handling know that the CPU is active. + * If the CPU was idle from RCU's viewpoint, update rdtp->dynticks and + * rdtp->dynticks_nmi_nesting to let the RCU grace-period handling know + * that the CPU is active. This implementation permits nested NMIs, as + * long as the nesting level does not overflow an int. (You will probably + * run out of stack space first.) */ void rcu_nmi_enter(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); + int incby = 2; - if (rdtp->dynticks_nmi_nesting == 0 && - (atomic_read(&rdtp->dynticks) & 0x1)) - return; - rdtp->dynticks_nmi_nesting++; - smp_mb__before_atomic(); /* Force delay from prior write. */ - atomic_inc(&rdtp->dynticks); - /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ - smp_mb__after_atomic(); /* See above. */ - WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); + /* Complain about underflow. */ + WARN_ON_ONCE(rdtp->dynticks_nmi_nesting < 0); + + /* + * If idle from RCU viewpoint, atomically increment ->dynticks + * to mark non-idle and increment ->dynticks_nmi_nesting by one. + * Otherwise, increment ->dynticks_nmi_nesting by two. This means + * if ->dynticks_nmi_nesting is equal to one, we are guaranteed + * to be in the outermost NMI handler that interrupted an RCU-idle + * period (observation due to Andy Lutomirski). + */ + if (!(atomic_read(&rdtp->dynticks) & 0x1)) { + smp_mb__before_atomic(); /* Force delay from prior write. */ + atomic_inc(&rdtp->dynticks); + /* atomic_inc() before later RCU read-side crit sects */ + smp_mb__after_atomic(); /* See above. */ + WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); + incby = 1; + } + rdtp->dynticks_nmi_nesting += incby; + barrier(); } /** * rcu_nmi_exit - inform RCU of exit from NMI context * - * If the CPU was idle with dynamic ticks active, and there is no - * irq handler running, this updates rdtp->dynticks_nmi to let the - * RCU grace-period handling know that the CPU is no longer active. + * If we are returning from the outermost NMI handler that interrupted an + * RCU-idle period, update rdtp->dynticks and rdtp->dynticks_nmi_nesting + * to let the RCU grace-period handling know that the CPU is back to + * being RCU-idle. */ void rcu_nmi_exit(void) { struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks); - if (rdtp->dynticks_nmi_nesting == 0 || - --rdtp->dynticks_nmi_nesting != 0) + /* + * Check for ->dynticks_nmi_nesting underflow and bad ->dynticks. + * (We are exiting an NMI handler, so RCU better be paying attention + * to us!) + */ + WARN_ON_ONCE(rdtp->dynticks_nmi_nesting <= 0); + WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); + + /* + * If the nesting level is not 1, the CPU wasn't RCU-idle, so + * leave it in non-RCU-idle state. + */ + if (rdtp->dynticks_nmi_nesting != 1) { + rdtp->dynticks_nmi_nesting -= 2; return; + } + + /* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ + rdtp->dynticks_nmi_nesting = 0; /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ smp_mb__before_atomic(); /* See above. */ atomic_inc(&rdtp->dynticks); -- cgit v0.10.2 From ca9558a33f658155c3b69f92897c2e6a848684f5 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Fri, 31 Oct 2014 14:55:05 +0000 Subject: rcu: Remove redundant rcu_is_cpu_rrupt_from_idle() from tiny RCU Let's start assuming that something in the idle loop posts a callback, and scheduling-clock interrupt occurs: 1. The system is idle and stays that way, no runnable tasks. 2. Scheduling-clock interrupt occurs, rcu_check_callbacks() is called as result, which in turn calls rcu_is_cpu_rrupt_from_idle(). 3. rcu_is_cpu_rrupt_from_idle() reports the CPU was interrupted from idle, which results in rcu_sched_qs() call, which does a raise_softirq(RCU_SOFTIRQ). 4. Upon return from interrupt, rcu_irq_exit() is invoked, which calls rcu_idle_enter_common(), which in turn calls rcu_sched_qs() again, which does another raise_softirq(RCU_SOFTIRQ). 5. The softirq happens shortly and invokes rcu_process_callbacks(), which invokes __rcu_process_callbacks(). 6. So now callbacks can be invoked. At least they can be if ->donetail has been updated. Which it will have been because rcu_sched_qs() invokes rcu_qsctr_help(). In the described scenario rcu_sched_qs() and raise_softirq(RCU_SOFTIRQ) get called twice in steps 3 and 4. This redundancy could be eliminated by removing rcu_is_cpu_rrupt_from_idle() function. Signed-off-by: Alexander Gordeev Cc: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 0db5649..805b6d5 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -186,16 +186,6 @@ EXPORT_SYMBOL(__rcu_is_watching); #endif /* defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ /* - * Test whether the current CPU was interrupted from idle. Nested - * interrupts don't count, we must be running at the first interrupt - * level. - */ -static int rcu_is_cpu_rrupt_from_idle(void) -{ - return rcu_dynticks_nesting <= 1; -} - -/* * Helper function for rcu_sched_qs() and rcu_bh_qs(). * Also irqs are disabled to avoid confusion due to interrupt handlers * invoking call_rcu(). @@ -250,7 +240,7 @@ void rcu_bh_qs(void) void rcu_check_callbacks(int user) { RCU_TRACE(check_cpu_stalls()); - if (user || rcu_is_cpu_rrupt_from_idle()) + if (user) rcu_sched_qs(); else if (!in_softirq()) rcu_bh_qs(); -- cgit v0.10.2 From 924df8a0117aa2725750f1ec4d282867534d9a89 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 29 Oct 2014 15:37:58 -0700 Subject: rcu: Fix invoke_rcu_callbacks() comment Despite what the comment says, it is only softirqs that are disabled, not interrupts. This commit therefore fixes the comment. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 4c106fc..9c25b99 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2601,7 +2601,7 @@ static void rcu_process_callbacks(struct softirq_action *unused) * Schedule RCU callback invocation. If the specified type of RCU * does not support RCU priority boosting, just do a direct call, * otherwise wake up the per-CPU kernel kthread. Note that because we - * are running on the current CPU with interrupts disabled, the + * are running on the current CPU with softirqs disabled, the * rcu_cpu_kthread_task cannot disappear out from under us. */ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) -- cgit v0.10.2 From 0d02e1292715d00674a49626146e3a854b504cb1 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Wed, 31 Dec 2014 23:48:32 +1300 Subject: ALSA: asihpi: fix an information leak in asihpi_hpi_ioctl() Add missing limits to keep copied data within allocated buffer. Reported-by: Dan Carpenter Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 2414d7a..2d63648 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -47,7 +47,7 @@ /* operational/messaging errors */ #define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901 - +#define HPI6000_ERROR_RESP_GET_LEN 902 #define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903 #define HPI6000_ERROR_MSG_GET_ADR 904 #define HPI6000_ERROR_RESP_GET_ADR 905 @@ -1365,7 +1365,10 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao, length = hpi_read_word(pdo, HPI_HIF_ADDR(length)); } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout); if (!timeout) - length = sizeof(struct hpi_response); + return HPI6000_ERROR_RESP_GET_LEN; + + if (length > phr->size) + return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; /* get the response */ p_data = (u32 *)phr; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 6aa677e..72af66b 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -153,6 +153,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } + res_max_size = min_t(size_t, res_max_size, sizeof(*hr)); + switch (hm->h.function) { case HPI_SUBSYS_CREATE_ADAPTER: case HPI_ADAPTER_DELETE: -- cgit v0.10.2 From 48d882978eb0a15547093b4542a82b5c22548041 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 31 Dec 2014 22:09:54 +0800 Subject: ALSA: pcm: add SNDRV_PCM_TRIGGER_DRAIN trigger Add SNDRV_PCM_TRIGGER_DRAIN trigger for pcm drain. Some audio devices require notification of drain events in order to properly drain and shutdown an audio stream. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 3652c94..bf32cea 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -106,6 +106,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4 #define SNDRV_PCM_TRIGGER_SUSPEND 5 #define SNDRV_PCM_TRIGGER_RESUME 6 +#define SNDRV_PCM_TRIGGER_DRAIN 7 #define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 1f23cd6..0e88e7a 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ #define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ typedef int __bitwise snd_pcm_state_t; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 095d957..ff3abc3 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -420,7 +420,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, hw = &substream->runtime->hw; if (!params->info) { - params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; + params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | + SNDRV_PCM_INFO_DRAIN_TRIGGER); if (!hw_support_mmap(substream)) params->info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); @@ -1566,6 +1567,13 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) snd_pcm_post_stop(substream, new_state); } } + + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + runtime->trigger_master == substream && + (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER)) + return substream->ops->trigger(substream, + SNDRV_PCM_TRIGGER_DRAIN); + return 0; } -- cgit v0.10.2 From c6068d3a7b408554a832181b98091ee5a00d8b85 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Dec 2014 17:10:34 +0100 Subject: ASoC: pcm: Fix unused variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sound/soc/soc-pcm.c: In function ‘soc_pcm_set_msb’: sound/soc/soc-pcm.c:307:11: warning: unused variable ‘i’ [-Wunused-variable] Fixes: 0e2a37513a1f ('ASoC: pcm: Use wildcard msbits constraints') Signed-off-by: Takashi Iwai diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d62d6a5..c076993 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -304,7 +304,7 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - int ret, i; + int ret; if (!bits) return; -- cgit v0.10.2 From 801a55911432f582c8ab82c895d2821dc02b70e3 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 2 Jan 2015 06:11:16 +0100 Subject: x86: init_mem_mapping(): use capital BIOS in comment Use capital BIOS in comment. Its cleaner, and allows diference between BIOS and BIOs. Signed-off-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 66dba36..452f904 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -582,7 +582,7 @@ void __init init_mem_mapping(void) * * * On x86, access has to be given to the first megabyte of ram because that area - * contains bios code and data regions used by X and dosemu and similar apps. + * contains BIOS code and data regions used by X and dosemu and similar apps. * Access has to be given to non-kernel-ram areas as well, these contain the PCI * mmio resources as well as potential bios/acpi data regions. */ -- cgit v0.10.2 From 9ed03783d37c0566673c790aa1ff3f1d02129514 Mon Sep 17 00:00:00 2001 From: Jeremiah Mahler Date: Sun, 21 Dec 2014 05:30:04 -0800 Subject: doc: usbmon: fix spelling s/unpriviledged/unprivileged/ Signed-off-by: Jeremiah Mahler Signed-off-by: Jiri Kosina diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index c42bb9c..7587d84 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -231,7 +231,7 @@ number. Number zero (/dev/usbmon0) is special and means "all buses". Note that specific naming policy is set by your Linux distribution. If you create /dev/usbmon0 by hand, make sure that it is owned by root -and has mode 0600. Otherwise, unpriviledged users will be able to snoop +and has mode 0600. Otherwise, unprivileged users will be able to snoop keyboard traffic. The following ioctl calls are available, with MON_IOC_MAGIC 0x92: -- cgit v0.10.2 From 231821d4c3fa72de8fd9981e608323529ac9ad70 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 15 Dec 2014 12:04:16 +0900 Subject: dynamic_debug: fix comment Signed-off-by: Masatake YAMATO Signed-off-by: Jiri Kosina diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index dfba055..96bc6a4 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -641,7 +641,7 @@ static __init int ddebug_setup_query(char *str) __setup("ddebug_query=", ddebug_setup_query); /* - * File_ops->write method for /dynamic_debug/conrol. Gathers the + * File_ops->write method for /dynamic_debug/control. Gathers the * command text from userspace, parses and executes it. */ #define USER_BUF_PAGE 4096 -- cgit v0.10.2 From 775c503f65679c46647c9414b218738b7062b215 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sun, 28 Dec 2014 12:44:45 +0600 Subject: mpc85xx_edac: Fix a typo in comments s/kenel/kernel/g [ Boris: massage commit message a bit ] Signed-off-by: Alexander Kuleshov Cc: Johannes Thumshirn Link: http://lkml.kernel.org/r/1419749085-7128-1-git-send-email-kuleshovmail@gmail.com Signed-off-by: Borislav Petkov diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ffb1a9a..1fa76a5 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -1,5 +1,5 @@ /* - * Freescale MPC85xx Memory Controller kenel module + * Freescale MPC85xx Memory Controller kernel module * * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. * diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 8c62564..4498baf 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -1,5 +1,5 @@ /* - * Freescale MPC85xx Memory Controller kenel module + * Freescale MPC85xx Memory Controller kernel module * Author: Dave Jiang * * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under -- cgit v0.10.2 From e9dd86267f2571a9649399c9e268266ca5aa6152 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:35 +0100 Subject: ALSA: ml403-ac97cr: Remove always NULL parameter snd_ml403_ac97cr_pcm() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index bcca825..ec01de1 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c @@ -1238,14 +1238,11 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) } static int -snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, - struct snd_pcm **rpcm) +snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1, &pcm); if (err < 0) @@ -1263,8 +1260,6 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, snd_dma_continuous_data(GFP_KERNEL), 64 * 1024, 128 * 1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1298,7 +1293,7 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev) return err; } PDEBUG(INIT_INFO, "probe(): mixer done\n"); - err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL); + err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0); if (err < 0) { snd_card_free(card); return err; -- cgit v0.10.2 From 7f605418837add961466dc66f7370332d44c1a92 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:36 +0100 Subject: ALSA: ad1816a: Remove always NULL parameters snd_ad1816a_pcm() and snd_ad1816a_timer() take a pointer to a pointer of a PCM/timer where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/ad1816a.h b/include/sound/ad1816a.h index abdf609..f2d3a6d 100644 --- a/include/sound/ad1816a.h +++ b/include/sound/ad1816a.h @@ -170,10 +170,9 @@ extern int snd_ad1816a_create(struct snd_card *card, unsigned long port, int irq, int dma1, int dma2, struct snd_ad1816a *chip); -extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm); +extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device); extern int snd_ad1816a_mixer(struct snd_ad1816a *chip); -extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, - struct snd_timer **rtimer); +extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device); #ifdef CONFIG_PM extern void snd_ad1816a_suspend(struct snd_ad1816a *chip); extern void snd_ad1816a_resume(struct snd_ad1816a *chip); diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index f481a41..7692265 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -142,7 +142,6 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, struct snd_card *card; struct snd_ad1816a *chip; struct snd_opl3 *opl3; - struct snd_timer *timer; error = snd_card_new(&pcard->card->dev, index[dev], id[dev], THIS_MODULE, @@ -172,7 +171,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - if ((error = snd_ad1816a_pcm(chip, 0, NULL)) < 0) { + if ((error = snd_ad1816a_pcm(chip, 0)) < 0) { snd_card_free(card); return error; } @@ -182,7 +181,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, return error; } - error = snd_ad1816a_timer(chip, 0, &timer); + error = snd_ad1816a_timer(chip, 0); if (error < 0) { snd_card_free(card); return error; diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 01a0798..5f99102 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -675,7 +675,7 @@ static struct snd_pcm_ops snd_ad1816a_capture_ops = { .pointer = snd_ad1816a_capture_pointer, }; -int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm) +int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device) { int error; struct snd_pcm *pcm; @@ -697,13 +697,10 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm) 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; - if (rpcm) - *rpcm = pcm; return 0; } -int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, - struct snd_timer **rtimer) +int snd_ad1816a_timer(struct snd_ad1816a *chip, int device) { struct snd_timer *timer; struct snd_timer_id tid; @@ -720,8 +717,6 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, timer->private_data = chip; chip->timer = timer; timer->hw = snd_ad1816a_timer_table; - if (rtimer) - *rtimer = timer; return 0; } -- cgit v0.10.2 From 4b8ab88518726197c8659bc9aca96c6af01dab57 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:37 +0100 Subject: ALSA: es1688: Remove almost always NULL parameter snd_es1688_pcm() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. This PCM is also available from the pcm field of the snd_es1688 struct that got passed to the same function. This patch updates all callers which passed a pointer to use that field instead and then removes the parameter from the function. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/es1688.h b/include/sound/es1688.h index 1d636a2..b34f23a 100644 --- a/include/sound/es1688.h +++ b/include/sound/es1688.h @@ -115,8 +115,7 @@ int snd_es1688_create(struct snd_card *card, int mpu_irq, int dma8, unsigned short hardware); -int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device, - struct snd_pcm **rpcm); +int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device); int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip); int snd_es1688_reset(struct snd_es1688 *chip); diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 76001fe0..1901c2b 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -138,10 +138,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n) { struct snd_es1688 *chip = card->private_data; struct snd_opl3 *opl3; - struct snd_pcm *pcm; int error; - error = snd_es1688_pcm(card, chip, 0, &pcm); + error = snd_es1688_pcm(card, chip, 0); if (error < 0) return error; @@ -150,9 +149,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n) return error; strlcpy(card->driver, "ES1688", sizeof(card->driver)); - strlcpy(card->shortname, pcm->name, sizeof(card->shortname)); + strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, + "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port, chip->irq, chip->dma8); if (fm_port[n] == SNDRV_AUTO_PORT) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index b545014..52aac84 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -728,8 +728,7 @@ static struct snd_pcm_ops snd_es1688_capture_ops = { .pointer = snd_es1688_capture_pointer, }; -int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, - int device, struct snd_pcm **rpcm) +int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device) { struct snd_pcm *pcm; int err; @@ -749,9 +748,6 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 64*1024, 64*1024); - - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 28a1693..acc65528 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -284,7 +284,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n) } gus->codec_flag = 1; - error = snd_es1688_pcm(card, es1688, 0, NULL); + error = snd_es1688_pcm(card, es1688, 0); if (error < 0) goto out; -- cgit v0.10.2 From 1a2515ac94bbb1c409dea2e4a7b011592569b239 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:38 +0100 Subject: ALSA: es18xx: Remove always NULL parameter snd_es18xx_pcm() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index b481bb8..6cc2d2b 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1687,16 +1687,13 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { .pointer = snd_es18xx_capture_pointer, }; -static int snd_es18xx_pcm(struct snd_card *card, int device, - struct snd_pcm **rpcm) +static int snd_es18xx_pcm(struct snd_card *card, int device) { struct snd_es18xx *chip = card->private_data; struct snd_pcm *pcm; char str[16]; int err; - if (rpcm) - *rpcm = NULL; sprintf(str, "ES%x", chip->version); if (chip->caps & ES18XX_PCM2) err = snd_pcm_new(card, str, device, 2, 1, &pcm); @@ -1722,9 +1719,6 @@ static int snd_es18xx_pcm(struct snd_card *card, int device, snd_dma_isa_data(), 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); - - if (rpcm) - *rpcm = pcm; return 0; } @@ -2154,7 +2148,7 @@ static int snd_audiodrive_probe(struct snd_card *card, int dev) chip->port, irq[dev], dma1[dev]); - err = snd_es18xx_pcm(card, 0, NULL); + err = snd_es18xx_pcm(card, 0); if (err < 0) return err; -- cgit v0.10.2 From db5abb3c499e553a8afedee1417d6a6308dda7bd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:39 +0100 Subject: ALSA: gus: Remove always NULL parameters snd_gf1_pcm_new() and snd_gf1_rawmidi_new() take a pointer to a pointer of a PCM/MIDI where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/gus.h b/include/sound/gus.h index 42905d8..06bbdc2 100644 --- a/include/sound/gus.h +++ b/include/sound/gus.h @@ -591,7 +591,7 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus); /* gus_pcm.c */ -int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm); +int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index); #ifdef CONFIG_SND_DEBUG extern void snd_gf1_print_voice_registers(struct snd_gus_card * gus); @@ -620,7 +620,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus); /* gus_uart.c */ -int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi **rrawmidi); +int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device); /* gus_dram.c */ int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr, diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 2dcf45b..25f6788 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -849,7 +849,7 @@ static struct snd_pcm_ops snd_gf1_pcm_capture_ops = { .pointer = snd_gf1_pcm_capture_pointer, }; -int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm) +int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) { struct snd_card *card; struct snd_kcontrol *kctl; @@ -857,8 +857,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s struct snd_pcm_substream *substream; int capture, err; - if (rpcm) - *rpcm = NULL; card = gus->card; capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0; err = snd_pcm_new(card, @@ -903,8 +901,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s return err; kctl->id.index = control_index; - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 21cc42e..3992912 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -241,13 +241,11 @@ static struct snd_rawmidi_ops snd_gf1_uart_input = .trigger = snd_gf1_uart_input_trigger, }; -int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi ** rrawmidi) +int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1"); @@ -256,7 +254,5 @@ int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmid rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = gus; gus->midi_uart = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return err; } diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index 7ce29ff..f001971 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -181,12 +181,12 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n) if (error < 0) goto out; - error = snd_gf1_pcm_new(gus, 0, 0, NULL); + error = snd_gf1_pcm_new(gus, 0, 0); if (error < 0) goto out; if (!gus->ace_flag) { - error = snd_gf1_rawmidi_new(gus, 0, NULL); + error = snd_gf1_rawmidi_new(gus, 0); if (error < 0) goto out; } diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index acc65528..693d95f 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -295,7 +295,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n) snd_component_add(card, "ES1688"); if (pcm_channels[n] > 0) { - error = snd_gf1_pcm_new(gus, 1, 1, NULL); + error = snd_gf1_pcm_new(gus, 1, 1); if (error < 0) goto out; } diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 39df36c..b2b3734 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -322,14 +322,14 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) goto _err; if (pcm_channels[dev] > 0) { - if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) + if ((err = snd_gf1_pcm_new(gus, 1, 1)) < 0) goto _err; } err = snd_gusmax_mixer(wss); if (err < 0) goto _err; - err = snd_gf1_rawmidi_new(gus, 0, NULL); + err = snd_gf1_rawmidi_new(gus, 0); if (err < 0) goto _err; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index ad55e5c..8ea54a7 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -711,7 +711,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev) return err; if (pcm_channels[dev] > 0) { - err = snd_gf1_pcm_new(gus, 1, 1, NULL); + err = snd_gf1_pcm_new(gus, 1, 1); if (err < 0) return err; } @@ -740,7 +740,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev) #endif gus->uart_enable = midi[dev]; - if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) + if ((err = snd_gf1_rawmidi_new(gus, 0)) < 0) return err; #ifndef SNDRV_STB -- cgit v0.10.2 From f6be4e624aa26699a9a89bc24089e88a227141c1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:40 +0100 Subject: ALSA: msnd: Remove always NULL parameter snd_msnd_pcm() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c index 1cee18f..835d4aa 100644 --- a/sound/isa/msnd/msnd.c +++ b/sound/isa/msnd/msnd.c @@ -679,8 +679,7 @@ static struct snd_pcm_ops snd_msnd_capture_ops = { }; -int snd_msnd_pcm(struct snd_card *card, int device, - struct snd_pcm **rpcm) +int snd_msnd_pcm(struct snd_card *card, int device) { struct snd_msnd *chip = card->private_data; struct snd_pcm *pcm; @@ -696,9 +695,6 @@ int snd_msnd_pcm(struct snd_card *card, int device, pcm->private_data = chip; strcpy(pcm->name, "Hurricane"); - - if (rpcm) - *rpcm = pcm; return 0; } EXPORT_SYMBOL(snd_msnd_pcm); diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h index dbac3a4..5f3c7dc 100644 --- a/sound/isa/msnd/msnd.h +++ b/sound/isa/msnd/msnd.h @@ -297,7 +297,7 @@ int snd_msnd_disable_irq(struct snd_msnd *chip); void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file); int snd_msnd_DAPQ(struct snd_msnd *chip, int start); int snd_msnd_DARQ(struct snd_msnd *chip, int start); -int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm); +int snd_msnd_pcm(struct snd_card *card, int device); int snd_msndmidi_new(struct snd_card *card, int device); void snd_msndmidi_input_read(void *mpu); diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 5016bf9..65b3682 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -582,7 +582,7 @@ static int snd_msnd_attach(struct snd_card *card) if (err < 0) goto err_release_region; - err = snd_msnd_pcm(card, 0, NULL); + err = snd_msnd_pcm(card, 0); if (err < 0) { printk(KERN_ERR LOGNAME ": error creating new PCM device\n"); goto err_release_region; -- cgit v0.10.2 From 8c77629996cbabee1d5b6d9b0d1e97cbca197ba1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:41 +0100 Subject: ALSA: sb8: Remove always NULL parameters snd_sb8dsp_pcm() and snd_sb8dsp_midi() take a pointer to a pointer of a PCM/MIDI where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/sb.h b/include/sound/sb.h index ba39603..13438ff 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h @@ -308,7 +308,7 @@ void snd_sbmixer_resume(struct snd_sb *chip); #endif /* sb8_init.c */ -int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm); +int snd_sb8dsp_pcm(struct snd_sb *chip, int device); /* sb8.c */ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip); int snd_sb8_playback_open(struct snd_pcm_substream *substream); @@ -317,7 +317,7 @@ int snd_sb8_playback_close(struct snd_pcm_substream *substream); int snd_sb8_capture_close(struct snd_pcm_substream *substream); /* midi8.c */ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip); -int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi); +int snd_sb8dsp_midi(struct snd_sb *chip, int device); /* sb16_init.c */ int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm); diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index 90d2eba..6b4884d 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -297,7 +297,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev) "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", port[dev], xirq, xdma8, xdma16); - err = snd_sb8dsp_pcm(chip, 0, NULL); + err = snd_sb8dsp_pcm(chip, 0); if (err < 0) goto err_free; err = snd_sbmixer_new(chip); diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 6c32b3a..b8e2391 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -157,7 +157,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) goto _err; } - if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) + if ((err = snd_sb8dsp_pcm(chip, 0)) < 0) goto _err; if ((err = snd_sbmixer_new(chip)) < 0) @@ -182,7 +182,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) goto _err; } - if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0) + if ((err = snd_sb8dsp_midi(chip, 0)) < 0) goto _err; strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8"); diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 24d4121..d4d8b0e 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -594,15 +594,13 @@ static struct snd_pcm_ops snd_sb8_capture_ops = { .pointer = snd_sb8_capture_pointer, }; -int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) +int snd_sb8dsp_pcm(struct snd_sb *chip, int device) { struct snd_card *card = chip->card; struct snd_pcm *pcm; int err; size_t max_prealloc = 64 * 1024; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0) return err; sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); @@ -618,8 +616,6 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) snd_dma_isa_data(), 64*1024, max_prealloc); - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 988a8b7..ffc71f0 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -263,13 +263,11 @@ static struct snd_rawmidi_ops snd_sb8dsp_midi_input = .trigger = snd_sb8dsp_midi_input_trigger, }; -int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi) +int snd_sb8dsp_midi(struct snd_sb *chip, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "SB8 MIDI"); @@ -280,7 +278,5 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawm rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return 0; } -- cgit v0.10.2 From 92533f188862fbefe357ada4e4af67b8e730e680 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:42 +0100 Subject: ASoC: sb16: Simplify snd_sb16dsp_pcm() All callers of snd_sb16dsp_pcm() always pass the pcm field of the first parameter as the last parameter. Simplify the function by moving this inside the function itself. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/sb.h b/include/sound/sb.h index 13438ff..33e2d11 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h @@ -320,7 +320,7 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip); int snd_sb8dsp_midi(struct snd_sb *chip, int device); /* sb16_init.c */ -int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm); +int snd_sb16dsp_pcm(struct snd_sb *chip, int device); const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction); int snd_sb16dsp_configure(struct snd_sb *chip); /* sb16.c */ diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 32d0152..bc9ea30 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -233,7 +233,7 @@ static int snd_card_als100_probe(int dev, irq[dev], dma8[dev], dma16[dev]); } - if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) { + if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 3f69454..4a7d7c8 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -374,7 +374,7 @@ static int snd_sb16_probe(struct snd_card *card, int dev) if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) return err; - if ((err = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) + if ((err = snd_sb16dsp_pcm(chip, 0)) < 0) return err; strcpy(card->driver, diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 72b10f4..63d11b7 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -860,19 +860,18 @@ static struct snd_pcm_ops snd_sb16_capture_ops = { .pointer = snd_sb16_capture_pointer, }; -int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm) +int snd_sb16dsp_pcm(struct snd_sb *chip, int device) { struct snd_card *card = chip->card; struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0) return err; sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; pcm->private_data = chip; + chip->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops); @@ -885,9 +884,6 @@ int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 64*1024, 128*1024); - - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index b102550..0a8cf94 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -223,7 +223,7 @@ static int snd_cs5530_create(struct snd_card *card, return err; } - err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm); + err = snd_sb16dsp_pcm(chip->sb, 0); if (err < 0) { dev_err(card->dev, "Could not create PCM\n"); snd_cs5530_free(chip); -- cgit v0.10.2 From fa60c065694a81e534c61809ab7dd419366e9335 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:43 +0100 Subject: ALSA: wss: Remove (almost) always NULL parameters Most callers of snd_wss_pcm(), snd_wss_timer() and snd_cs4236_pcm() pass NULL as the last parameter, some callers pass a pointer but never use it after the function has been called and only a few callers pass a pointer and actually use it. The later is only the case for snd_wss_pcm() for snd_cs4236_pcm() and it is possible to get the same PCM object by accessing the pcm field of the snd_wss struct that was passed as the first parameter. This function removes the last parameters from the functions mentioned above and updates the callers which used it to use chip->pcm instead. This allows us to slightly simplify the functions since they don't have to check and set the last parameter anymore which makes the code slightly shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/wss.h b/include/sound/wss.h index 0c7f034..1823e3a 100644 --- a/include/sound/wss.h +++ b/include/sound/wss.h @@ -154,8 +154,8 @@ int snd_wss_create(struct snd_card *card, unsigned short hardware, unsigned short hwshare, struct snd_wss **rchip); -int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm); -int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer); +int snd_wss_pcm(struct snd_wss *chip, int device); +int snd_wss_timer(struct snd_wss *chip, int device); int snd_wss_mixer(struct snd_wss *chip); const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction); @@ -167,7 +167,7 @@ int snd_cs4236_create(struct snd_card *card, unsigned short hardware, unsigned short hwshare, struct snd_wss **rchip); -int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm); +int snd_cs4236_pcm(struct snd_wss *chip, int device); int snd_cs4236_mixer(struct snd_wss *chip); /* diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index 093f22a..f159da4e 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -88,7 +88,6 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; - struct snd_pcm *pcm; int error; error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); @@ -103,7 +102,7 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n) card->private_data = chip; - error = snd_wss_pcm(chip, 0, &pcm); + error = snd_wss_pcm(chip, 0); if (error < 0) goto out; @@ -112,10 +111,10 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n) goto out; strcpy(card->driver, "AD1848"); - strcpy(card->shortname, pcm->name); + strcpy(card->shortname, chip->pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", - pcm->name, chip->port, irq[n], dma1[n]); + chip->pcm->name, chip->port, irq[n], dma1[n]); if (thinkpad[n]) strcat(card->longname, " [Thinkpad]"); diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index 0ea75fc..b8e768e 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -215,7 +215,7 @@ static int snd_card_azt2320_probe(int dev, sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - error = snd_wss_pcm(chip, 0, NULL); + error = snd_wss_pcm(chip, 0); if (error < 0) { snd_card_free(card); return error; @@ -225,7 +225,7 @@ static int snd_card_azt2320_probe(int dev, snd_card_free(card); return error; } - error = snd_wss_timer(chip, 0, NULL); + error = snd_wss_timer(chip, 0); if (error < 0) { snd_card_free(card); return error; diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index 4778852..2c89d95 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c @@ -307,7 +307,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev) if (err < 0) goto error; - err = snd_wss_pcm(cmi->wss, 0, NULL); + err = snd_wss_pcm(cmi->wss, 0); if (err < 0) goto error; @@ -318,7 +318,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev) if (err < 0) goto error; - if (snd_wss_timer(cmi->wss, 0, NULL) < 0) + if (snd_wss_timer(cmi->wss, 0) < 0) snd_printk(KERN_WARNING "error initializing WSS timer\n"); if (mpuport[ndev] == SNDRV_AUTO_PORT) { diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index 7dba07a..282cd75 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -92,7 +92,6 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; - struct snd_pcm *pcm; int error; error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); @@ -106,15 +105,15 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n) card->private_data = chip; - error = snd_wss_pcm(chip, 0, &pcm); + error = snd_wss_pcm(chip, 0); if (error < 0) goto out; strcpy(card->driver, "CS4231"); - strcpy(card->shortname, pcm->name); + strcpy(card->shortname, chip->pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", - pcm->name, chip->port, irq[n], dma1[n]); + chip->pcm->name, chip->port, irq[n], dma1[n]); if (dma2[n] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]); @@ -122,7 +121,7 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n) if (error < 0) goto out; - error = snd_wss_timer(chip, 0, NULL); + error = snd_wss_timer(chip, 0); if (error < 0) goto out; diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 750f51c..9d7582c 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -382,7 +382,6 @@ static int snd_cs423x_card_new(struct device *pdev, int dev, static int snd_cs423x_probe(struct snd_card *card, int dev) { struct snd_card_cs4236 *acard; - struct snd_pcm *pcm; struct snd_wss *chip; struct snd_opl3 *opl3; int err; @@ -404,7 +403,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) acard->chip = chip; if (chip->hardware & WSS_HW_CS4236B_MASK) { - err = snd_cs4236_pcm(chip, 0, &pcm); + err = snd_cs4236_pcm(chip, 0); if (err < 0) return err; @@ -412,7 +411,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } else { - err = snd_wss_pcm(chip, 0, &pcm); + err = snd_wss_pcm(chip, 0); if (err < 0) return err; @@ -420,17 +419,17 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } - strcpy(card->driver, pcm->name); - strcpy(card->shortname, pcm->name); + strcpy(card->driver, chip->pcm->name); + strcpy(card->shortname, chip->pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", - pcm->name, + chip->pcm->name, chip->port, irq[dev], dma1[dev]); if (dma2[dev] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) return err; diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index c5adca3..add7ffc 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -376,17 +376,14 @@ int snd_cs4236_create(struct snd_card *card, return 0; } -int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) +int snd_cs4236_pcm(struct snd_wss *chip, int device) { - struct snd_pcm *pcm; int err; - err = snd_wss_pcm(chip, device, &pcm); + err = snd_wss_pcm(chip, device); if (err < 0) return err; - pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; - if (rpcm) - *rpcm = pcm; + chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; return 0; } diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c index 1eb2b1e..3227884 100644 --- a/sound/isa/galaxy/galaxy.c +++ b/sound/isa/galaxy/galaxy.c @@ -569,7 +569,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n) if (err < 0) goto error; - err = snd_wss_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0); if (err < 0) goto error; @@ -577,7 +577,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n) if (err < 0) goto error; - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) goto error; diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index b2b3734..8216e8d 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -309,7 +309,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) goto _err; - err = snd_wss_pcm(wss, 0, NULL); + err = snd_wss_pcm(wss, 0); if (err < 0) goto _err; @@ -317,7 +317,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) goto _err; - err = snd_wss_timer(wss, 2, NULL); + err = snd_wss_timer(wss, 2); if (err < 0) goto _err; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 8ea54a7..70d0040 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -647,7 +647,6 @@ static int snd_interwave_probe(struct snd_card *card, int dev) #ifdef SNDRV_STB struct snd_i2c_bus *i2c_bus; #endif - struct snd_pcm *pcm; char *str; int err; @@ -695,14 +694,15 @@ static int snd_interwave_probe(struct snd_card *card, int dev) if (err < 0) return err; - err = snd_wss_pcm(wss, 0, &pcm); + err = snd_wss_pcm(wss, 0); if (err < 0) return err; - sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A'); - strcat(pcm->name, " (codec)"); + sprintf(wss->pcm->name + strlen(wss->pcm->name), " rev %c", + gus->revision + 'A'); + strcat(wss->pcm->name, " (codec)"); - err = snd_wss_timer(wss, 2, NULL); + err = snd_wss_timer(wss, 2); if (err < 0) return err; diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index a219bc3..d7aff52 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -684,7 +684,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev) return err; } chip->wss = wss; - err = snd_wss_pcm(wss, 0, NULL); + err = snd_wss_pcm(wss, 0); if (err < 0) return err; err = snd_wss_mixer(wss); @@ -693,7 +693,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev) err = snd_opl3sa2_mixer(card); if (err < 0) return err; - err = snd_wss_timer(wss, 0, NULL); + err = snd_wss_timer(wss, 0); if (err < 0) return err; if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c2ca681..5464528 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1270,8 +1270,6 @@ static int snd_miro_probe(struct snd_card *card) int error; struct snd_miro *miro = card->private_data; struct snd_wss *codec; - struct snd_timer *timer; - struct snd_pcm *pcm; struct snd_rawmidi *rmidi; if (!miro->res_mc_base) { @@ -1310,7 +1308,7 @@ static int snd_miro_probe(struct snd_card *card) if (error < 0) return error; - error = snd_wss_pcm(codec, 0, &pcm); + error = snd_wss_pcm(codec, 0); if (error < 0) return error; @@ -1318,11 +1316,11 @@ static int snd_miro_probe(struct snd_card *card) if (error < 0) return error; - error = snd_wss_timer(codec, 0, &timer); + error = snd_wss_timer(codec, 0); if (error < 0) return error; - miro->pcm = pcm; + miro->pcm = codec->pcm; error = snd_miro_mixer(card, miro); if (error < 0) @@ -1356,8 +1354,8 @@ static int snd_miro_probe(struct snd_card *card) strcpy(card->driver, "miro"); sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, miro->name, pcm->name, miro->wss_base + 4, - miro->irq, miro->dma1, miro->dma2); + card->shortname, miro->name, codec->pcm->name, + miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2); if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index c9b5828..840831f 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -820,10 +820,6 @@ static int snd_opti9xx_probe(struct snd_card *card) int xdma2; struct snd_opti9xx *chip = card->private_data; struct snd_wss *codec; -#ifdef CS4231 - struct snd_timer *timer; -#endif - struct snd_pcm *pcm; struct snd_rawmidi *rmidi; struct snd_hwdep *synth; @@ -855,7 +851,7 @@ static int snd_opti9xx_probe(struct snd_card *card) if (error < 0) return error; chip->codec = codec; - error = snd_wss_pcm(codec, 0, &pcm); + error = snd_wss_pcm(codec, 0); if (error < 0) return error; error = snd_wss_mixer(codec); @@ -867,7 +863,7 @@ static int snd_opti9xx_probe(struct snd_card *card) return error; #endif #ifdef CS4231 - error = snd_wss_timer(codec, 0, &timer); + error = snd_wss_timer(codec, 0); if (error < 0) return error; #endif @@ -884,11 +880,12 @@ static int snd_opti9xx_probe(struct snd_card *card) sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, pcm->name, + card->shortname, codec->pcm->name, chip->wss_base + 4, irq, dma1, xdma2); #else sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, chip->wss_base + 4, irq, dma1); + card->shortname, codec->pcm->name, chip->wss_base + 4, irq, + dma1); #endif /* CS4231 || OPTi93X */ if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 15a152e..51cfa76 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -625,7 +625,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev) if (err < 0) goto err_unmap2; - err = snd_wss_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0); if (err < 0) { snd_printk(KERN_ERR PFX "error creating new WSS PCM device\n"); diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 44405df..018ab14 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -877,7 +877,6 @@ static int create_ad1845(struct snd_card *card, unsigned port, codec_type, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; - struct snd_pcm *pcm; if (sscape->type != SSCAPE_VIVO) { /* @@ -893,7 +892,7 @@ static int create_ad1845(struct snd_card *card, unsigned port, } - err = snd_wss_pcm(chip, 0, &pcm); + err = snd_wss_pcm(chip, 0); if (err < 0) { snd_printk(KERN_ERR "sscape: No PCM device " "for AD1845 chip\n"); @@ -907,7 +906,7 @@ static int create_ad1845(struct snd_card *card, unsigned port, goto _error; } if (chip->hardware != WSS_HW_AD1848) { - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) { snd_printk(KERN_ERR "sscape: No timer device " "for AD1845 chip\n"); diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index bfbf38c..a0987a5 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -380,11 +380,11 @@ snd_wavefront_probe (struct snd_card *card, int dev) return err; } - err = snd_wss_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0); if (err < 0) return err; - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) return err; diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 347bb1b..6530d32 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1923,7 +1923,7 @@ static struct snd_pcm_ops snd_wss_capture_ops = { .pointer = snd_wss_capture_pointer, }; -int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) +int snd_wss_pcm(struct snd_wss *chip, int device) { struct snd_pcm *pcm; int err; @@ -1949,8 +1949,6 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; - if (rpcm) - *rpcm = pcm; return 0; } EXPORT_SYMBOL(snd_wss_pcm); @@ -1961,7 +1959,7 @@ static void snd_wss_timer_free(struct snd_timer *timer) chip->timer = NULL; } -int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer) +int snd_wss_timer(struct snd_wss *chip, int device) { struct snd_timer *timer; struct snd_timer_id tid; @@ -1980,8 +1978,6 @@ int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer) timer->private_free = snd_wss_timer_free; timer->hw = snd_wss_timer_table; chip->timer = timer; - if (rtimer) - *rtimer = timer; return 0; } EXPORT_SYMBOL(snd_wss_timer); -- cgit v0.10.2 From a08800940f72bb5502a8b6afb675231cef0b3a62 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:44 +0100 Subject: ASLA: ad1889: Remove always NULL parameter snd_ad1889_pcm_init() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 1610c38..547ee30 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -623,14 +623,11 @@ snd_ad1889_interrupt(int irq, void *dev_id) } static int -snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) +snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device) { int err; struct snd_pcm *pcm; - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm); if (err < 0) return err; @@ -658,9 +655,6 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) return err; } - if (rpcm) - *rpcm = pcm; - return 0; } @@ -1016,7 +1010,7 @@ snd_ad1889_probe(struct pci_dev *pci, if (err < 0) goto free_and_ret; - err = snd_ad1889_pcm_init(chip, 0, NULL); + err = snd_ad1889_pcm_init(chip, 0); if (err < 0) goto free_and_ret; -- cgit v0.10.2 From d18132aa15d2bf7a5f227b590175b73aa3591a91 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:45 +0100 Subject: ALSA: asihpi: Remove always NULL parameter snd_asihpi_hpi_new() takes a pointer to a pointer of a hwdep where if this parameter is provided the newly allocated hwdep is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index e9273fb..7a55fef 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -2832,14 +2832,11 @@ static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file, /* results in /dev/snd/hwC#D0 file for each card with index # also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card' */ -static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, - int device, struct snd_hwdep **rhwdep) +static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device) { struct snd_hwdep *hw; int err; - if (rhwdep) - *rhwdep = NULL; err = snd_hwdep_new(asihpi->card, "HPI", device, &hw); if (err < 0) return err; @@ -2849,8 +2846,6 @@ static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, hw->ops.ioctl = snd_asihpi_hpi_ioctl; hw->ops.release = snd_asihpi_hpi_release; hw->private_data = asihpi; - if (rhwdep) - *rhwdep = hw; return 0; } @@ -2993,7 +2988,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, /* always create, can be enabled or disabled dynamically by enable_hwdep module param*/ - snd_asihpi_hpi_new(asihpi, 0, NULL); + snd_asihpi_hpi_new(asihpi, 0); strcpy(card->driver, "ASIHPI"); -- cgit v0.10.2 From 3e4f4776f427ddeeba6972f34cca04df478a67b4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:46 +0100 Subject: ALSA: cs4281: Remove always NULL parameters snd_cs4281_pcm() and snd_cs4281_midi() take a pointer to a pointer of a PCM/MIDI object where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 4c49b5c..05a4337 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -973,14 +973,11 @@ static struct snd_pcm_ops snd_cs4281_capture_ops = { .pointer = snd_cs4281_pointer, }; -static int snd_cs4281_pcm(struct cs4281 *chip, int device, - struct snd_pcm **rpcm) +static int snd_cs4281_pcm(struct cs4281 *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(chip->card, "CS4281", device, 1, 1, &pcm); if (err < 0) return err; @@ -996,8 +993,6 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 512*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1788,14 +1783,11 @@ static struct snd_rawmidi_ops snd_cs4281_midi_input = .trigger = snd_cs4281_midi_input_trigger, }; -static int snd_cs4281_midi(struct cs4281 *chip, int device, - struct snd_rawmidi **rrawmidi) +static int snd_cs4281_midi(struct cs4281 *chip, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "CS4281"); @@ -1804,8 +1796,6 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device, rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return 0; } @@ -1941,11 +1931,11 @@ static int snd_cs4281_probe(struct pci_dev *pci, snd_card_free(card); return err; } - if ((err = snd_cs4281_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_cs4281_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_cs4281_midi(chip, 0, NULL)) < 0) { + if ((err = snd_cs4281_midi(chip, 0)) < 0) { snd_card_free(card); return err; } -- cgit v0.10.2 From 72134c4d9e97bcde376a8746510408da3fe039cc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:47 +0100 Subject: ALSA: cs46xx: Remove always NULL parameters The various PCM and MIDI allocation functions in this driver take a pointer to a pointer of a PCM/MIDI object where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 6a6858c..655fbea 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -100,16 +100,16 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, } card->private_data = chip; chip->accept_valid = mmap_valid[dev]; - if ((err = snd_cs46xx_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_cs46xx_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } #ifdef CONFIG_SND_CS46XX_NEW_DSP - if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) { + if ((err = snd_cs46xx_pcm_rear(chip, 1)) < 0) { snd_card_free(card); return err; } - if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) { + if ((err = snd_cs46xx_pcm_iec958(chip, 2)) < 0) { snd_card_free(card); return err; } @@ -120,13 +120,13 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, } #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs ==2) { - if ((err = snd_cs46xx_pcm_center_lfe(chip,3,NULL)) < 0) { + if ((err = snd_cs46xx_pcm_center_lfe(chip, 3)) < 0) { snd_card_free(card); return err; } } #endif - if ((err = snd_cs46xx_midi(chip, 0, NULL)) < 0) { + if ((err = snd_cs46xx_midi(chip, 0)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h index c49a082..9c9f89a 100644 --- a/sound/pci/cs46xx/cs46xx.h +++ b/sound/pci/cs46xx/cs46xx.h @@ -1737,12 +1737,12 @@ int snd_cs46xx_create(struct snd_card *card, struct snd_cs46xx **rcodec); extern const struct dev_pm_ops snd_cs46xx_pm; -int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); -int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); -int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); -int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); +int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device); +int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device); +int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device); +int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device); int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device); -int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rmidi); +int snd_cs46xx_midi(struct snd_cs46xx *chip, int device); int snd_cs46xx_start_dsp(struct snd_cs46xx *chip); int snd_cs46xx_gameport(struct snd_cs46xx *chip); diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 32b44f2..dfec84e 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1778,13 +1778,11 @@ static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = { #define MAX_PLAYBACK_CHANNELS 1 #endif -int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm) +int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0) return err; @@ -1801,23 +1799,16 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } #ifdef CONFIG_SND_CS46XX_NEW_DSP -int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, - struct snd_pcm **rpcm) +int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) return err; @@ -1833,21 +1824,14 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } -int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, - struct snd_pcm **rpcm) +int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) return err; @@ -1863,21 +1847,14 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } -int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, - struct snd_pcm **rpcm) +int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0) return err; @@ -1893,9 +1870,6 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } #endif @@ -2724,13 +2698,11 @@ static struct snd_rawmidi_ops snd_cs46xx_midi_input = .trigger = snd_cs46xx_midi_input_trigger, }; -int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi) +int snd_cs46xx_midi(struct snd_cs46xx *chip, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "CS46XX"); @@ -2739,8 +2711,6 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rr rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = NULL; return 0; } -- cgit v0.10.2 From 50b8d94e1819768e8eccae4d24698a17b8940776 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:48 +0100 Subject: ALSA: ens1370: Remove always NULL parameters The various PCM and MIDI allocation functions in this driver take a pointer to a pointer of a PCM/MIDI object where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index d94cb3c..bb1f4d2 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1268,14 +1268,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device, - struct snd_pcm **rpcm) +static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm); if (err < 0) return err; @@ -1302,22 +1299,14 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device, err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, 2, 0, NULL); #endif - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; + return err; } -static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device, - struct snd_pcm **rpcm) +static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm); if (err < 0) return err; @@ -1342,12 +1331,7 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device, err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, surround_map, 2, 0, NULL); #endif - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; + return err; } /* @@ -2362,14 +2346,11 @@ static struct snd_rawmidi_ops snd_ensoniq_midi_input = .trigger = snd_ensoniq_midi_input_trigger, }; -static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device, - struct snd_rawmidi **rrawmidi) +static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, CHIP_NAME); @@ -2379,8 +2360,6 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device, SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = ensoniq; ensoniq->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return 0; } @@ -2462,15 +2441,15 @@ static int snd_audiopci_probe(struct pci_dev *pci, return err; } #endif - if ((err = snd_ensoniq_pcm(ensoniq, 0, NULL)) < 0) { + if ((err = snd_ensoniq_pcm(ensoniq, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_ensoniq_pcm2(ensoniq, 1, NULL)) < 0) { + if ((err = snd_ensoniq_pcm2(ensoniq, 1)) < 0) { snd_card_free(card); return err; } - if ((err = snd_ensoniq_midi(ensoniq, 0, NULL)) < 0) { + if ((err = snd_ensoniq_midi(ensoniq, 0)) < 0) { snd_card_free(card); return err; } -- cgit v0.10.2 From bb814c396af777c31ed168ce57f620967dd133f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:49 +0100 Subject: ALSA: emu10k1: Remove always NULL parameters The various PCM and hwdep allocation functions in this driver take a pointer to a pointer of a PCM/hwdep where if this parameter is provided the newly allocated object is stored. All callers pass NULL though, so remove the parameter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index c46908c..7f6ab6c 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1809,17 +1809,17 @@ int snd_emu10k1_create(struct snd_card *card, uint subsystem, struct snd_emu10k1 ** remu); -int snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm); -int snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm); -int snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm); -int snd_p16v_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm); +int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device); +int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device); +int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device); +int snd_p16v_pcm(struct snd_emu10k1 *emu, int device); int snd_p16v_free(struct snd_emu10k1 * emu); int snd_p16v_mixer(struct snd_emu10k1 * emu); -int snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm); -int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm); +int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device); +int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 *emu, int device); int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device); int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device); -int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep); +int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device); irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id); diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4c17163..a3c00a6 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -132,11 +132,11 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, goto error; card->private_data = emu; emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; - if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) + if ((err = snd_emu10k1_pcm(emu, 0)) < 0) goto error; - if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) + if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0) goto error; - if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) + if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0) goto error; /* This stores the periods table. */ if (emu->card_capabilities->ca0151_chip) { /* P16V */ @@ -151,10 +151,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, if ((err = snd_emu10k1_timer(emu, 0)) < 0) goto error; - if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) + if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0) goto error; if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) + if ((err = snd_p16v_pcm(emu, 4)) < 0) goto error; } if (emu->audigy) { @@ -164,7 +164,7 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, if ((err = snd_emu10k1_midi(emu)) < 0) goto error; } - if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0) + if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0) goto error; #ifdef ENABLE_SYNTH if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 15933f9..6d1b98d 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -847,15 +847,13 @@ static const struct snd_pcm_chmap_elem clfe_map[] = { { } }; -static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm) +static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) { struct snd_pcm *pcm; const struct snd_pcm_chmap_elem *map = NULL; int err; int capture = 0; - if (rpcm) - *rpcm = NULL; if (device == 0) capture = 1; @@ -896,15 +894,8 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **r snd_dma_pci_data(emu->pci), 32*1024, 32*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, 1 << 2, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - - return 0; } static int snd_emu10k1x_create(struct snd_card *card, @@ -1583,15 +1574,15 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, return err; } - if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) { + if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) { + if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index eb5c0ab..56fc47b 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -2641,14 +2641,11 @@ static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file) return 0; } -int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, - struct snd_hwdep **rhwdep) +int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device) { struct snd_hwdep *hw; int err; - if (rhwdep) - *rhwdep = NULL; if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0) return err; strcpy(hw->name, "EMU10K1 (FX8010)"); @@ -2657,8 +2654,6 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, hw->ops.ioctl = snd_emu10k1_fx8010_ioctl; hw->ops.release = snd_emu10k1_fx8010_release; hw->private_data = emu; - if (rhwdep) - *rhwdep = hw; return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index f82481b..0dc0738 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1400,15 +1400,12 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { .page = snd_pcm_sgbuf_ops_page, }; -int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) +int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0) return err; @@ -1429,22 +1426,15 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); - if (rpcm) - *rpcm = pcm; - return 0; } -int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device, - struct snd_pcm **rpcm) +int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0) return err; @@ -1461,9 +1451,6 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device, if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) return err; - if (rpcm) - *rpcm = pcm; - return 0; } @@ -1479,15 +1466,11 @@ static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = { .pointer = snd_emu10k1_capture_pointer, }; -int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device, - struct snd_pcm **rpcm) +int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0) return err; @@ -1501,8 +1484,6 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1822,16 +1803,12 @@ static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = { .ack = snd_emu10k1_fx8010_playback_transfer, }; -int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, - struct snd_pcm **rpcm) +int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) return err; @@ -1843,8 +1820,6 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, pcm->info_flags = 0; strcpy(pcm->name, "Multichannel Capture/PT Playback"); emu->pcm_efx = pcm; - if (rpcm) - *rpcm = pcm; /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs * to these diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 7ef3898..b672755 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -640,7 +640,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip) return 0; } -int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) +int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -649,8 +649,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ emu->p16v_device_offset = device; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) return err; @@ -694,9 +692,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) */ } - if (rpcm) - *rpcm = pcm; - return 0; } -- cgit v0.10.2 From 483337f903dd39a10d4d6617cf6f30feeead061c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:50 +0100 Subject: ALSA: fm801: Remove always NULL parameter snd_fm801_pcm() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index d167aff..9a2122f 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -704,13 +704,11 @@ static struct snd_pcm_ops snd_fm801_capture_ops = { .pointer = snd_fm801_capture_pointer, }; -static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm) +static int snd_fm801_pcm(struct fm801 *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0) return err; @@ -726,16 +724,10 @@ static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm) snd_dma_pci_data(chip->pci), chip->multichannel ? 128*1024 : 64*1024, 128*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_alt_chmaps, chip->multichannel ? 6 : 2, 0, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; } /* @@ -1340,7 +1332,7 @@ static int snd_card_fm801_probe(struct pci_dev *pci, if (chip->tea575x_tuner & TUNER_ONLY) goto __fm801_tuner_only; - if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_fm801_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } -- cgit v0.10.2 From 08a4c10b58d6403ca9fe8c872e22ecad47924fec Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:51 +0100 Subject: ALSA: ice1712: Remove always NULL parameters The various PCM allocation functions in this driver take a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index b039b46..a2ee2982 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -880,13 +880,11 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = { .pointer = snd_ice1712_capture_pointer, }; -static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm); if (err < 0) return err; @@ -902,22 +900,17 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm * snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 64*1024); - if (rpcm) - *rpcm = pcm; - dev_warn(ice->card->dev, "Consumer PCM code does not work well at the moment --jk\n"); return 0; } -static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm); if (err < 0) return err; @@ -932,9 +925,6 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pc snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = pcm; - return 0; } @@ -1260,13 +1250,11 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = { .pointer = snd_ice1712_capture_pro_pointer, }; -static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm); if (err < 0) return err; @@ -1282,8 +1270,6 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd snd_dma_pci_data(ice->pci), 256*1024, 256*1024); ice->pcm_pro = pcm; - if (rpcm) - *rpcm = pcm; if (ice->cs8427) { /* assign channels to iec958 */ @@ -2691,14 +2677,14 @@ static int snd_ice1712_probe(struct pci_dev *pci, c = &no_matched; __found: - err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL); + err = snd_ice1712_pcm_profi(ice, pcm_dev++); if (err < 0) { snd_card_free(card); return err; } if (ice_has_con_ac97(ice)) { - err = snd_ice1712_pcm(ice, pcm_dev++, NULL); + err = snd_ice1712_pcm(ice, pcm_dev++); if (err < 0) { snd_card_free(card); return err; @@ -2726,7 +2712,7 @@ static int snd_ice1712_probe(struct pci_dev *pci, } if (ice_has_con_ac97(ice)) { - err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL); + err = snd_ice1712_pcm_ds(ice, pcm_dev++); if (err < 0) { snd_card_free(card); return err; -- cgit v0.10.2 From 15aded4c924ae149a38e639f421f5313125eea89 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:52 +0100 Subject: ALSA: riptide: Remove always NULL parameter snd_riptide_pcm() takes a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 6abc2ac..121f2c0 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1706,14 +1706,11 @@ static struct snd_pcm_ops snd_riptide_capture_ops = { .pointer = snd_riptide_pointer, }; -static int -snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) +static int snd_riptide_pcm(struct snd_riptide *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1, &pcm)) < 0) @@ -1729,8 +1726,6 @@ snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64 * 1024, 128 * 1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -2092,7 +2087,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err < 0) goto error; card->private_data = chip; - err = snd_riptide_pcm(chip, 0, NULL); + err = snd_riptide_pcm(chip, 0); if (err < 0) goto error; err = snd_riptide_mixer(chip); -- cgit v0.10.2 From 0f33991dd2811cb5458b1a2bc19c6aa6ff64c00b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:53 +0100 Subject: ALSA: sonicvibes: Remove always NULL parameter snd_sonicvibes_pcm() take a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 313a732..34cee5c 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -880,8 +880,7 @@ static struct snd_pcm_ops snd_sonicvibes_capture_ops = { .pointer = snd_sonicvibes_capture_pointer, }; -static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, - struct snd_pcm **rpcm) +static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device) { struct snd_pcm *pcm; int err; @@ -902,8 +901,6 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(sonic->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1491,7 +1488,7 @@ static int snd_sonic_probe(struct pci_dev *pci, (unsigned long long)pci_resource_start(pci, 1), sonic->irq); - if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) { + if ((err = snd_sonicvibes_pcm(sonic, 0)) < 0) { snd_card_free(card); return err; } -- cgit v0.10.2 From 1b16416fda21a8c5704bce809e0d7387bbfb097d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:54 +0100 Subject: ALSA: trident: Remove always NULL parameters The various PCM allocation functions in this driver take a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index a54cd68..cedf13b 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -127,21 +127,21 @@ static int snd_trident_probe(struct pci_dev *pci, sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d", card->shortname, trident->port, trident->irq); - if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) { + if ((err = snd_trident_pcm(trident, pcm_dev++)) < 0) { snd_card_free(card); return err; } switch (trident->device) { case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_NX: - if ((err = snd_trident_foldback_pcm(trident, pcm_dev++, NULL)) < 0) { + if ((err = snd_trident_foldback_pcm(trident, pcm_dev++)) < 0) { snd_card_free(card); return err; } break; } if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) { - if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) { + if ((err = snd_trident_spdif_pcm(trident, pcm_dev++)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h index 5f110eb..9624e59 100644 --- a/sound/pci/trident/trident.h +++ b/sound/pci/trident/trident.h @@ -420,9 +420,9 @@ int snd_trident_create(struct snd_card *card, struct snd_trident ** rtrident); int snd_trident_create_gameport(struct snd_trident *trident); -int snd_trident_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm); -int snd_trident_foldback_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm); -int snd_trident_spdif_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm); +int snd_trident_pcm(struct snd_trident *trident, int device); +int snd_trident_foldback_pcm(struct snd_trident *trident, int device); +int snd_trident_spdif_pcm(struct snd_trident *trident, int device); int snd_trident_attach_synthesizer(struct snd_trident * trident); struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port); diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 57cd757..c380c99 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2172,14 +2172,11 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = { ---------------------------------------------------------------------------*/ -int snd_trident_pcm(struct snd_trident *trident, - int device, struct snd_pcm **rpcm) +int snd_trident_pcm(struct snd_trident *trident, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm)) < 0) return err; @@ -2214,8 +2211,6 @@ int snd_trident_pcm(struct snd_trident *trident, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); } - if (rpcm) - *rpcm = pcm; return 0; } @@ -2230,16 +2225,13 @@ int snd_trident_pcm(struct snd_trident *trident, ---------------------------------------------------------------------------*/ -int snd_trident_foldback_pcm(struct snd_trident *trident, - int device, struct snd_pcm **rpcm) +int snd_trident_foldback_pcm(struct snd_trident *trident, int device) { struct snd_pcm *foldback; int err; int num_chan = 3; struct snd_pcm_substream *substream; - if (rpcm) - *rpcm = NULL; if (trident->device == TRIDENT_DEVICE_ID_NX) num_chan = 4; if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback)) < 0) @@ -2271,8 +2263,6 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = foldback; return 0; } @@ -2287,14 +2277,11 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, ---------------------------------------------------------------------------*/ -int snd_trident_spdif_pcm(struct snd_trident *trident, - int device, struct snd_pcm **rpcm) +int snd_trident_spdif_pcm(struct snd_trident *trident, int device) { struct snd_pcm *spdif; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif)) < 0) return err; @@ -2310,8 +2297,6 @@ int snd_trident_spdif_pcm(struct snd_trident *trident, snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = spdif; return 0; } -- cgit v0.10.2 From 38c4718121804317e00a3a905612d17485f754c0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 12:24:55 +0100 Subject: ALSA: ymfpci: Remove always NULL parameters The various PCM allocation functions in this driver take a pointer to a pointer of a PCM where if this parameter is provided the newly allocated PCM is stored. All callers pass NULL though, so remove the parameter. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 47a1923..812e27a 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -283,11 +283,11 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, card->shortname, chip->reg_area_phys, chip->irq); - if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_ymfpci_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_ymfpci_pcm_spdif(chip, 1, NULL)) < 0) { + if ((err = snd_ymfpci_pcm_spdif(chip, 1)) < 0) { snd_card_free(card); return err; } @@ -297,12 +297,12 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, return err; } if (chip->ac97->ext_id & AC97_EI_SDAC) { - err = snd_ymfpci_pcm_4ch(chip, 2, NULL); + err = snd_ymfpci_pcm_4ch(chip, 2); if (err < 0) { snd_card_free(card); return err; } - err = snd_ymfpci_pcm2(chip, 3, NULL); + err = snd_ymfpci_pcm2(chip, 3); if (err < 0) { snd_card_free(card); return err; diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h index 4631a23..149d4cb 100644 --- a/sound/pci/ymfpci/ymfpci.h +++ b/sound/pci/ymfpci/ymfpci.h @@ -379,10 +379,10 @@ void snd_ymfpci_free_gameport(struct snd_ymfpci *chip); extern const struct dev_pm_ops snd_ymfpci_pm; -int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); -int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); -int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); -int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); +int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device); +int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device); +int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device); +int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device); int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch); int snd_ymfpci_timer(struct snd_ymfpci *chip, int device); diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 81c916a..f5581a9 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1145,13 +1145,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) +int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1167,14 +1165,8 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, 2, 0, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; } static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { @@ -1188,13 +1180,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) +int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1210,8 +1200,6 @@ int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1226,14 +1214,11 @@ static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = { .pointer = snd_ymfpci_playback_pointer, }; -int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, - struct snd_pcm **rpcm) +int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1248,8 +1233,6 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1272,14 +1255,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, - struct snd_pcm **rpcm) +int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1294,14 +1274,8 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, surround_map, 2, 0, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; } static int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -- cgit v0.10.2 From ef394acb45e232e940367053896708375da1ff92 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 15:03:42 +0100 Subject: ALSA: oxygen: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 0282824..af22a74 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -676,11 +676,6 @@ static struct snd_pcm_ops oxygen_ac97_ops = { .pointer = oxygen_pointer, }; -static void oxygen_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - int oxygen_pcm_init(struct oxygen *chip) { struct snd_pcm *pcm; @@ -705,7 +700,6 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_b_ops); pcm->private_data = chip; - pcm->private_free = oxygen_pcm_free; strcpy(pcm->name, "Multichannel"); if (outs) snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -734,7 +728,6 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_c_ops); pcm->private_data = chip; - pcm->private_free = oxygen_pcm_free; strcpy(pcm->name, "Digital"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), @@ -765,7 +758,6 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_b_ops); pcm->private_data = chip; - pcm->private_free = oxygen_pcm_free; strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), -- cgit v0.10.2 From a14e7eb59bb7ce10766d4778d382ca52b235147f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 15:03:43 +0100 Subject: ALSA: ps3: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the card (and the PCM) itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 58f292a..3682425 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -1044,7 +1044,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) if (!the_card.null_buffer_start_vaddr) { pr_info("%s: nullbuffer alloc failed\n", __func__); ret = -ENOMEM; - goto clean_preallocate; + goto clean_card; } pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__, the_card.null_buffer_start_vaddr, @@ -1066,8 +1066,6 @@ clean_dma_map: PAGE_SIZE, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); -clean_preallocate: - snd_pcm_lib_preallocate_free_for_all(the_card.pcm); clean_card: snd_card_free(the_card.card); clean_irq: -- cgit v0.10.2 From 48e08d0fb265b007ebbb29a72297ff7e40938969 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 11 Nov 2014 12:49:41 -0800 Subject: x86, entry: Switch stacks on a paranoid entry from userspace This causes all non-NMI, non-double-fault kernel entries from userspace to run on the normal kernel stack. Double-fault is exempt to minimize confusion if we double-fault directly from userspace due to a bad kernel stack. This is, suprisingly, simpler and shorter than the current code. It removes the IMO rather frightening paranoid_userspace path, and it make sync_regs much simpler. There is no risk of stack overflow due to this change -- the kernel stack that we switch to is empty. This will also enable us to create non-atomic sections within machine checks from userspace, which will simplify memory failure handling. It will also allow the upcoming fsgsbase code to be simplified, because it doesn't need to worry about usergs when scheduling in paranoid_exit, as that code no longer exists. Cc: Oleg Nesterov Cc: Andi Kleen Cc: Tony Luck Acked-by: Borislav Petkov Signed-off-by: Andy Lutomirski diff --git a/Documentation/x86/entry_64.txt b/Documentation/x86/entry_64.txt index 4a1c5c2..9132b86 100644 --- a/Documentation/x86/entry_64.txt +++ b/Documentation/x86/entry_64.txt @@ -78,9 +78,6 @@ The expensive (paranoid) way is to read back the MSR_GS_BASE value xorl %ebx,%ebx 1: ret -and the whole paranoid non-paranoid macro complexity is about whether -to suffer that RDMSR cost. - If we are at an interrupt or user-trap/gate-alike boundary then we can use the faster check: the stack will be a reliable indicator of whether SWAPGS was already done: if we see that we are a secondary @@ -93,6 +90,15 @@ which might have triggered right after a normal entry wrote CS to the stack but before we executed SWAPGS, then the only safe way to check for GS is the slower method: the RDMSR. -So we try only to mark those entry methods 'paranoid' that absolutely -need the more expensive check for the GS base - and we generate all -'normal' entry points with the regular (faster) entry macros. +Therefore, super-atomic entries (except NMI, which is handled separately) +must use idtentry with paranoid=1 to handle gsbase correctly. This +triggers three main behavior changes: + + - Interrupt entry will use the slower gsbase check. + - Interrupt entry from user mode will switch off the IST stack. + - Interrupt exit to kernel mode will not attempt to reschedule. + +We try to only use IST entries and the paranoid entry code for vectors +that absolutely need the more expensive check for the GS base - and we +generate all 'normal' entry points with the regular (faster) paranoid=0 +variant. diff --git a/Documentation/x86/x86_64/kernel-stacks b/Documentation/x86/x86_64/kernel-stacks index a01eec5..e3c8a49 100644 --- a/Documentation/x86/x86_64/kernel-stacks +++ b/Documentation/x86/x86_64/kernel-stacks @@ -40,9 +40,11 @@ An IST is selected by a non-zero value in the IST field of an interrupt-gate descriptor. When an interrupt occurs and the hardware loads such a descriptor, the hardware automatically sets the new stack pointer based on the IST value, then invokes the interrupt handler. If -software wants to allow nested IST interrupts then the handler must -adjust the IST values on entry to and exit from the interrupt handler. -(This is occasionally done, e.g. for debug exceptions.) +the interrupt came from user mode, then the interrupt handler prologue +will switch back to the per-thread stack. If software wants to allow +nested IST interrupts then the handler must adjust the IST values on +entry to and exit from the interrupt handler. (This is occasionally +done, e.g. for debug exceptions.) Events with different IST codes (i.e. with different stacks) can be nested. For example, a debug interrupt can safely be interrupted by an diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 9ebaf63..931f32f 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -1048,6 +1048,11 @@ ENTRY(\sym) CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 .if \paranoid + .if \paranoid == 1 + CFI_REMEMBER_STATE + testl $3, CS(%rsp) /* If coming from userspace, switch */ + jnz 1f /* stacks. */ + .endif call save_paranoid .else call error_entry @@ -1088,6 +1093,36 @@ ENTRY(\sym) jmp error_exit /* %ebx: no swapgs flag */ .endif + .if \paranoid == 1 + CFI_RESTORE_STATE + /* + * Paranoid entry from userspace. Switch stacks and treat it + * as a normal entry. This means that paranoid handlers + * run in real process context if user_mode(regs). + */ +1: + call error_entry + + DEFAULT_FRAME 0 + + movq %rsp,%rdi /* pt_regs pointer */ + call sync_regs + movq %rax,%rsp /* switch stack */ + + movq %rsp,%rdi /* pt_regs pointer */ + + .if \has_error_code + movq ORIG_RAX(%rsp),%rsi /* get error code */ + movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */ + .else + xorl %esi,%esi /* no error code */ + .endif + + call \do_sym + + jmp error_exit /* %ebx: no swapgs flag */ + .endif + CFI_ENDPROC END(\sym) .endm @@ -1108,7 +1143,7 @@ idtentry overflow do_overflow has_error_code=0 idtentry bounds do_bounds has_error_code=0 idtentry invalid_op do_invalid_op has_error_code=0 idtentry device_not_available do_device_not_available has_error_code=0 -idtentry double_fault do_double_fault has_error_code=1 paranoid=1 +idtentry double_fault do_double_fault has_error_code=1 paranoid=2 idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0 idtentry invalid_TSS do_invalid_TSS has_error_code=1 idtentry segment_not_present do_segment_not_present has_error_code=1 @@ -1289,16 +1324,14 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector( #endif /* - * "Paranoid" exit path from exception stack. - * Paranoid because this is used by NMIs and cannot take - * any kernel state for granted. - * We don't do kernel preemption checks here, because only - * NMI should be common and it does not enable IRQs and - * cannot get reschedule ticks. + * "Paranoid" exit path from exception stack. This is invoked + * only on return from non-NMI IST interrupts that came + * from kernel space. * - * "trace" is 0 for the NMI handler only, because irq-tracing - * is fundamentally NMI-unsafe. (we cannot change the soft and - * hard flags at once, atomically) + * We may be returning to very strange contexts (e.g. very early + * in syscall entry), so checking for preemption here would + * be complicated. Fortunately, we there's no good reason + * to try to handle preemption here. */ /* ebx: no swapgs flag */ @@ -1308,43 +1341,14 @@ ENTRY(paranoid_exit) TRACE_IRQS_OFF_DEBUG testl %ebx,%ebx /* swapgs needed? */ jnz paranoid_restore - testl $3,CS(%rsp) - jnz paranoid_userspace -paranoid_swapgs: TRACE_IRQS_IRETQ 0 SWAPGS_UNSAFE_STACK RESTORE_ALL 8 - jmp irq_return + INTERRUPT_RETURN paranoid_restore: TRACE_IRQS_IRETQ_DEBUG 0 RESTORE_ALL 8 - jmp irq_return -paranoid_userspace: - GET_THREAD_INFO(%rcx) - movl TI_flags(%rcx),%ebx - andl $_TIF_WORK_MASK,%ebx - jz paranoid_swapgs - movq %rsp,%rdi /* &pt_regs */ - call sync_regs - movq %rax,%rsp /* switch stack for scheduling */ - testl $_TIF_NEED_RESCHED,%ebx - jnz paranoid_schedule - movl %ebx,%edx /* arg3: thread flags */ - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_NONE) - xorl %esi,%esi /* arg2: oldset */ - movq %rsp,%rdi /* arg1: &pt_regs */ - call do_notify_resume - DISABLE_INTERRUPTS(CLBR_NONE) - TRACE_IRQS_OFF - jmp paranoid_userspace -paranoid_schedule: - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_ANY) - SCHEDULE_USER - DISABLE_INTERRUPTS(CLBR_ANY) - TRACE_IRQS_OFF - jmp paranoid_userspace + INTERRUPT_RETURN CFI_ENDPROC END(paranoid_exit) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 88900e2..28f3e5f 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -466,27 +466,14 @@ NOKPROBE_SYMBOL(do_int3); #ifdef CONFIG_X86_64 /* - * Help handler running on IST stack to switch back to user stack - * for scheduling or signal handling. The actual stack switch is done in - * entry.S + * Help handler running on IST stack to switch off the IST stack if the + * interrupted code was in user mode. The actual stack switch is done in + * entry_64.S */ asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs) { - struct pt_regs *regs = eregs; - /* Did already sync */ - if (eregs == (struct pt_regs *)eregs->sp) - ; - /* Exception from user space */ - else if (user_mode(eregs)) - regs = task_pt_regs(current); - /* - * Exception from kernel and interrupts are enabled. Move to - * kernel process stack. - */ - else if (eregs->flags & X86_EFLAGS_IF) - regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); - if (eregs != regs) - *regs = *eregs; + struct pt_regs *regs = task_pt_regs(current); + *regs = *eregs; return regs; } NOKPROBE_SYMBOL(sync_regs); -- cgit v0.10.2 From 959274753857efe9c5f1ba35fe727f51e9aa128d Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 19 Nov 2014 17:41:09 -0800 Subject: x86, traps: Track entry into and exit from IST context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently pretend that IST context is like standard exception context, but this is incorrect. IST entries from userspace are like standard exceptions except that they use per-cpu stacks, so they are atomic. IST entries from kernel space are like NMIs from RCU's perspective -- they are not quiescent states even if they interrupted the kernel during a quiescent state. Add and use ist_enter and ist_exit to track IST context. Even though x86_32 has no IST stacks, we track these interrupts the same way. This fixes two issues: - Scheduling from an IST interrupt handler will now warn. It would previously appear to work as long as we got lucky and nothing overwrote the stack frame. (I don't know of any bugs in this that would trigger the warning, but it's good to be on the safe side.) - RCU handling in IST context was dangerous. As far as I know, only machine checks were likely to trigger this, but it's good to be on the safe side. Note that the machine check handlers appears to have been missing any context tracking at all before this patch. Cc: "Paul E. McKenney" Cc: Josh Triplett Cc: Frédéric Weisbecker Signed-off-by: Andy Lutomirski diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 707adc6..3cf525e 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -1,6 +1,7 @@ #ifndef _ASM_X86_TRAPS_H #define _ASM_X86_TRAPS_H +#include #include #include @@ -110,6 +111,9 @@ asmlinkage void smp_thermal_interrupt(void); asmlinkage void mce_threshold_interrupt(void); #endif +extern enum ctx_state ist_enter(struct pt_regs *regs); +extern void ist_exit(struct pt_regs *regs, enum ctx_state prev_state); + /* Interrupts/Exceptions */ enum { X86_TRAP_DE = 0, /* 0, Divide-by-zero */ diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index d2c6116..800d423 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -1063,6 +1064,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) { struct mca_config *cfg = &mca_cfg; struct mce m, *final; + enum ctx_state prev_state; int i; int worst = 0; int severity; @@ -1085,6 +1087,8 @@ void do_machine_check(struct pt_regs *regs, long error_code) DECLARE_BITMAP(valid_banks, MAX_NR_BANKS); char *msg = "Unknown"; + prev_state = ist_enter(regs); + this_cpu_inc(mce_exception_count); if (!cfg->banks) @@ -1216,6 +1220,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) mce_wrmsrl(MSR_IA32_MCG_STATUS, 0); out: sync_core(); + ist_exit(regs, prev_state); } EXPORT_SYMBOL_GPL(do_machine_check); diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c index a304298..ec2663a 100644 --- a/arch/x86/kernel/cpu/mcheck/p5.c +++ b/arch/x86/kernel/cpu/mcheck/p5.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -17,8 +18,11 @@ int mce_p5_enabled __read_mostly; /* Machine check handler for Pentium class Intel CPUs: */ static void pentium_machine_check(struct pt_regs *regs, long error_code) { + enum ctx_state prev_state; u32 loaddr, hi, lotype; + prev_state = ist_enter(regs); + rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi); rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi); @@ -33,6 +37,8 @@ static void pentium_machine_check(struct pt_regs *regs, long error_code) } add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); + + ist_exit(regs, prev_state); } /* Set up machine check reporting for processors with Intel style MCE: */ diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c index 7dc5564..bd5d46a 100644 --- a/arch/x86/kernel/cpu/mcheck/winchip.c +++ b/arch/x86/kernel/cpu/mcheck/winchip.c @@ -7,14 +7,19 @@ #include #include +#include #include #include /* Machine check handler for WinChip C6: */ static void winchip_machine_check(struct pt_regs *regs, long error_code) { + enum ctx_state prev_state = ist_enter(regs); + printk(KERN_EMERG "CPU0: Machine Check Exception.\n"); add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); + + ist_exit(regs, prev_state); } /* Set up machine check reporting on the Winchip C6 series */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 28f3e5f..b3a9d24 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -108,6 +108,39 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) preempt_count_dec(); } +enum ctx_state ist_enter(struct pt_regs *regs) +{ + /* + * We are atomic because we're on the IST stack (or we're on x86_32, + * in which case we still shouldn't schedule. + */ + preempt_count_add(HARDIRQ_OFFSET); + + if (user_mode_vm(regs)) { + /* Other than that, we're just an exception. */ + return exception_enter(); + } else { + /* + * We might have interrupted pretty much anything. In + * fact, if we're a machine check, we can even interrupt + * NMI processing. We don't want in_nmi() to return true, + * but we need to notify RCU. + */ + rcu_nmi_enter(); + return IN_KERNEL; /* the value is irrelevant. */ + } +} + +void ist_exit(struct pt_regs *regs, enum ctx_state prev_state) +{ + preempt_count_sub(HARDIRQ_OFFSET); + + if (user_mode_vm(regs)) + return exception_exit(prev_state); + else + rcu_nmi_exit(); +} + static nokprobe_inline int do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, struct pt_regs *regs, long error_code) @@ -251,6 +284,8 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) * end up promoting it to a doublefault. In that case, modify * the stack to make it look like we just entered the #GP * handler from user space, similar to bad_iret. + * + * No need for ist_enter here because we don't use RCU. */ if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY && regs->cs == __KERNEL_CS && @@ -263,12 +298,12 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */ regs->ip = (unsigned long)general_protection; regs->sp = (unsigned long)&normal_regs->orig_ax; + return; } #endif - exception_enter(); - /* Return not checked because double check cannot be ignored */ + ist_enter(regs); /* Discard prev_state because we won't return. */ notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); tsk->thread.error_code = error_code; @@ -434,7 +469,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) if (poke_int3_handler(regs)) return; - prev_state = exception_enter(); + prev_state = ist_enter(regs); #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, SIGTRAP) == NOTIFY_STOP) @@ -460,7 +495,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) preempt_conditional_cli(regs); debug_stack_usage_dec(); exit: - exception_exit(prev_state); + ist_exit(regs, prev_state); } NOKPROBE_SYMBOL(do_int3); @@ -541,7 +576,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code) unsigned long dr6; int si_code; - prev_state = exception_enter(); + prev_state = ist_enter(regs); get_debugreg(dr6, 6); @@ -616,7 +651,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code) debug_stack_usage_dec(); exit: - exception_exit(prev_state); + ist_exit(regs, prev_state); } NOKPROBE_SYMBOL(do_debug); -- cgit v0.10.2 From 83653c16da91112236292871b820cb8b367220e3 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 13 Nov 2014 15:57:07 -0800 Subject: x86: Clean up current_stack_pointer There's no good reason for it to be a macro, and x86_64 will want to use it, so it should be in a header. Acked-by: Borislav Petkov Signed-off-by: Andy Lutomirski diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 547e344..8b13b0fb 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -170,6 +170,17 @@ static inline struct thread_info *current_thread_info(void) return ti; } +static inline unsigned long current_stack_pointer(void) +{ + unsigned long sp; +#ifdef CONFIG_X86_64 + asm("mov %%rsp,%0" : "=g" (sp)); +#else + asm("mov %%esp,%0" : "=g" (sp)); +#endif + return sp; +} + #else /* !__ASSEMBLY__ */ /* how to get the thread information struct from ASM */ diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 63ce838..28d28f5 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -69,16 +69,9 @@ static void call_on_stack(void *func, void *stack) : "memory", "cc", "edx", "ecx", "eax"); } -/* how to get the current stack pointer from C */ -#define current_stack_pointer ({ \ - unsigned long sp; \ - asm("mov %%esp,%0" : "=g" (sp)); \ - sp; \ -}) - static inline void *current_stack(void) { - return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1)); + return (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1)); } static inline int @@ -103,7 +96,7 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) /* Save the next esp at the bottom of the stack */ prev_esp = (u32 *)irqstk; - *prev_esp = current_stack_pointer; + *prev_esp = current_stack_pointer(); if (unlikely(overflow)) call_on_stack(print_stack_overflow, isp); @@ -156,7 +149,7 @@ void do_softirq_own_stack(void) /* Push the previous esp onto the stack */ prev_esp = (u32 *)irqstk; - *prev_esp = current_stack_pointer; + *prev_esp = current_stack_pointer(); call_on_stack(__do_softirq, isp); } -- cgit v0.10.2 From bced35b65aefe53a6f77a9ed0ce1aea86e9d65a2 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 19 Nov 2014 17:59:41 -0800 Subject: x86, traps: Add ist_begin_non_atomic and ist_end_non_atomic In some IST handlers, if the interrupt came from user mode, we can safely enable preemption. Add helpers to do it safely. This is intended to be used my the memory failure code in do_machine_check. Acked-by: Borislav Petkov Signed-off-by: Andy Lutomirski diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 3cf525e..4e49d7d 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -113,6 +113,8 @@ asmlinkage void mce_threshold_interrupt(void); extern enum ctx_state ist_enter(struct pt_regs *regs); extern void ist_exit(struct pt_regs *regs, enum ctx_state prev_state); +extern void ist_begin_non_atomic(struct pt_regs *regs); +extern void ist_end_non_atomic(void); /* Interrupts/Exceptions */ enum { diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index b3a9d24..7176f84 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -141,6 +141,44 @@ void ist_exit(struct pt_regs *regs, enum ctx_state prev_state) rcu_nmi_exit(); } +/** + * ist_begin_non_atomic() - begin a non-atomic section in an IST exception + * @regs: regs passed to the IST exception handler + * + * IST exception handlers normally cannot schedule. As a special + * exception, if the exception interrupted userspace code (i.e. + * user_mode_vm(regs) would return true) and the exception was not + * a double fault, it can be safe to schedule. ist_begin_non_atomic() + * begins a non-atomic section within an ist_enter()/ist_exit() region. + * Callers are responsible for enabling interrupts themselves inside + * the non-atomic section, and callers must call is_end_non_atomic() + * before ist_exit(). + */ +void ist_begin_non_atomic(struct pt_regs *regs) +{ + BUG_ON(!user_mode_vm(regs)); + + /* + * Sanity check: we need to be on the normal thread stack. This + * will catch asm bugs and any attempt to use ist_preempt_enable + * from double_fault. + */ + BUG_ON(((current_stack_pointer() ^ this_cpu_read_stable(kernel_stack)) + & ~(THREAD_SIZE - 1)) != 0); + + preempt_count_sub(HARDIRQ_OFFSET); +} + +/** + * ist_end_non_atomic() - begin a non-atomic section in an IST exception + * + * Ends a non-atomic section started with ist_begin_non_atomic(). + */ +void ist_end_non_atomic(void) +{ + preempt_count_add(HARDIRQ_OFFSET); +} + static nokprobe_inline int do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, struct pt_regs *regs, long error_code) -- cgit v0.10.2 From adc2ae0bb6daa2287d1a6567d18be01da546f7a7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 3 Jan 2015 17:56:14 +0100 Subject: ALSA: pcm: Remove unused functions declaration Remove function declarations for functions that don't have a matching implementation. For snd_pcm_build_linear_format the implementation was removed in 64d27f96cb719cf8 ("[ALSA] Support 3-bytes 24bit format in PCM OSS emulation"). All the others never had one (as far as git history goes). Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index bf32cea..cd09c1b 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -518,7 +518,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream); int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file, struct snd_pcm_substream **rsubstream); void snd_pcm_detach_substream(struct snd_pcm_substream *substream); -void snd_pcm_vma_notify_data(void *client, void *data); int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); @@ -984,21 +983,15 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format); int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames); -snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian); void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, const struct snd_pcm_ops *ops); void snd_pcm_set_sync(struct snd_pcm_substream *substream); -int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); int snd_pcm_update_state(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime); int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); -int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); -int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); -int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream); -int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream); void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr); void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, -- cgit v0.10.2 From 57dca36ee25bcab20a71705175c00b6f114cdab4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 14:54:56 +0100 Subject: ALSA: seq: Deletion of unnecessary checks before the function call "snd_midi_event_free" The snd_midi_event_free() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 3a45696..e79cc44 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -237,8 +237,7 @@ snd_seq_oss_midi_check_exit_port(int client, int port) spin_unlock_irqrestore(®ister_lock, flags); snd_use_lock_free(&mdev->use_lock); snd_use_lock_sync(&mdev->use_lock); - if (mdev->coder) - snd_midi_event_free(mdev->coder); + snd_midi_event_free(mdev->coder); kfree(mdev); } spin_lock_irqsave(®ister_lock, flags); @@ -265,8 +264,7 @@ snd_seq_oss_midi_clear_all(void) spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { if ((mdev = midi_devs[i]) != NULL) { - if (mdev->coder) - snd_midi_event_free(mdev->coder); + snd_midi_event_free(mdev->coder); kfree(mdev); midi_devs[i] = NULL; } diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index a1fd77a..68fec77 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -268,8 +268,7 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth) snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port); } - if (msynth->parser) - snd_midi_event_free(msynth->parser); + snd_midi_event_free(msynth->parser); } /* register new midi synth port */ -- cgit v0.10.2 From d1f45e6037f1195d10cf363e94a08ee2f10f9b41 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 15:10:52 +0100 Subject: sound: oss: Deletion of unnecessary checks before the function call "vfree" The vfree() function performs also input parameter validation. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/oss/pss.c b/sound/oss/pss.c index ca0d6e9..81314f9 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -1228,7 +1228,7 @@ static void __exit cleanup_pss(void) { if(!pss_no_sound) { - if(fw_load && pss_synth) + if (fw_load) vfree(pss_synth); if(pssmss) unload_pss_mss(&cfg2); diff --git a/sound/oss/trix.c b/sound/oss/trix.c index 944e0c0..3c494dc 100644 --- a/sound/oss/trix.c +++ b/sound/oss/trix.c @@ -487,7 +487,7 @@ static int __init init_trix(void) static void __exit cleanup_trix(void) { - if (fw_load && trix_boot) + if (fw_load) vfree(trix_boot); if (sb) unload_trix_sb(&cfg2); -- cgit v0.10.2 From a827977ac31cb5d1f4720efede9bbbf241789993 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 17:06:04 +0100 Subject: ALSA: emu10k1: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index b672755..3c60b43 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -166,11 +166,8 @@ static struct snd_pcm_hardware snd_p16v_capture_hw = { static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime) { struct snd_emu10k1_pcm *epcm = runtime->private_data; - - if (epcm) { - /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */ - kfree(epcm); - } + + kfree(epcm); } /* open_playback callback */ -- cgit v0.10.2 From 1fac1686377410169952db63d282490bc0554662 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 17:37:28 +0100 Subject: ALSA: oxygen: Delete an unnecessary check before the function call "snd_pcm_suspend" The snd_pcm_suspend() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b67e306..61a62c0 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -736,8 +736,7 @@ static int oxygen_pci_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < PCM_COUNT; ++i) - if (chip->streams[i]) - snd_pcm_suspend(chip->streams[i]); + snd_pcm_suspend(chip->streams[i]); if (chip->model.suspend) chip->model.suspend(chip); -- cgit v0.10.2 From b172e0aae6d14baf646a36052d03b301535f4ef5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 18:28:21 +0100 Subject: ALSA: emux: Delete an unnecessary check before the function call "snd_sf_free" The snd_sf_free() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 9352207..f27a1c8 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -160,12 +160,8 @@ int snd_emux_free(struct snd_emux *emu) snd_emux_detach_seq_oss(emu); #endif snd_emux_detach_seq(emu); - snd_emux_delete_hwdep(emu); - - if (emu->sflist) - snd_sf_free(emu->sflist); - + snd_sf_free(emu->sflist); kfree(emu->voices); kfree(emu->name); kfree(emu); -- cgit v0.10.2 From aa57b93b27eae1156c9a66a4ea85076f9a38d135 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 20:43:01 +0100 Subject: ALSA: aoa: Delete an unnecessary check before the function call "snd_pcm_suspend_all" The snd_pcm_suspend_all() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 4e2b4fb..837ba99 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -381,10 +381,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) list_for_each_entry(i2sdev, &control->list, item) { /* Notify Alsa */ - if (i2sdev->sound.pcm) { - /* Suspend PCM streams */ - snd_pcm_suspend_all(i2sdev->sound.pcm); - } + /* Suspend PCM streams */ + snd_pcm_suspend_all(i2sdev->sound.pcm); /* Notify codecs */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { -- cgit v0.10.2 From b76c0e95ab0f535e210df588b8ac42dd75b31c75 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 21:02:32 +0100 Subject: ALSA: sb: Delete an unnecessary check before the function call "snd_emux_free" The snd_emux_free() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 95b39be..72332df 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -103,8 +103,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev) hw = dev->driver_data; if (hw->pcm) snd_device_free(dev->card, hw->pcm); - if (hw->emu) - snd_emux_free(hw->emu); + snd_emux_free(hw->emu); snd_util_memhdr_free(hw->memhdr); hw->emu = NULL; hw->memhdr = NULL; -- cgit v0.10.2 From ff6defa6a8fae12205d64f55db395b1fcf35af8e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 22:55:54 +0100 Subject: ALSA: Deletion of checks before the function call "iounmap" The iounmap() function performs also input parameter validation. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 837ba99..b9737fa 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -74,10 +74,9 @@ static void i2sbus_release_dev(struct device *dev) int i; i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev); - - if (i2sdev->intfregs) iounmap(i2sdev->intfregs); - if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); - if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); + iounmap(i2sdev->intfregs); + iounmap(i2sdev->out.dbdma); + iounmap(i2sdev->in.dbdma); for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) release_and_free_resource(i2sdev->allocated_resource[i]); free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); @@ -318,9 +317,9 @@ static int i2sbus_add_dev(struct macio_dev *macio, free_irq(dev->interrupts[i], dev); free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring); free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring); - if (dev->intfregs) iounmap(dev->intfregs); - if (dev->out.dbdma) iounmap(dev->out.dbdma); - if (dev->in.dbdma) iounmap(dev->in.dbdma); + iounmap(dev->intfregs); + iounmap(dev->out.dbdma); + iounmap(dev->in.dbdma); for (i=0;i<3;i++) release_and_free_resource(dev->allocated_resource[i]); mutex_destroy(&dev->lock); diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 0e83a73..4140b1b 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -889,8 +889,8 @@ static int aaci_probe_ac97(struct aaci *aaci) static void aaci_free_card(struct snd_card *card) { struct aaci *aaci = card->private_data; - if (aaci->base) - iounmap(aaci->base); + + iounmap(aaci->base); } static struct aaci *aaci_init_card(struct amba_device *dev) diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index ec01de1..bdcb572 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c @@ -1094,8 +1094,7 @@ static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr) if (ml403_ac97cr->capture_irq >= 0) free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr); /* give back "port" */ - if (ml403_ac97cr->port != NULL) - iounmap(ml403_ac97cr->port); + iounmap(ml403_ac97cr->port); kfree(ml403_ac97cr); PDEBUG(INIT_INFO, "free(): (done)\n"); return 0; diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 65b3682..4c07266 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -627,8 +627,7 @@ static int snd_msnd_attach(struct snd_card *card) return 0; err_release_region: - if (chip->mappedbase) - iounmap(chip->mappedbase); + iounmap(chip->mappedbase); release_mem_region(chip->base, BUFFSIZE); release_region(chip->io, DSP_NUMIO); free_irq(chip->irq, chip); diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 29604a2..f2350c1 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -893,9 +893,7 @@ snd_harmony_free(struct snd_harmony *h) if (h->irq >= 0) free_irq(h->irq, h); - if (h->iobase) - iounmap(h->iobase); - + iounmap(h->iobase); kfree(h); return 0; } diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 547ee30..0de3129 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -853,12 +853,9 @@ snd_ad1889_free(struct snd_ad1889 *chip) free_irq(chip->irq, chip); skip_hw: - if (chip->iobase) - iounmap(chip->iobase); - + iounmap(chip->iobase); pci_release_regions(chip->pci); pci_disable_device(chip->pci); - kfree(chip); return 0; } diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 72af66b..67d1133 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -541,10 +541,8 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); /* unmap PCI memory space, mapped during device init. */ - for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { - if (pci.ap_mem_base[idx]) - iounmap(pci.ap_mem_base[idx]); - } + for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx) + iounmap(pci.ap_mem_base[idx]); if (pa->irq) free_irq(pa->irq, pa); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 9c1c445..d24188f 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1585,8 +1585,7 @@ static int snd_atiixp_free(struct atiixp *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->remap_addr) - iounmap(chip->remap_addr); + iounmap(chip->remap_addr); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index b2f63e0..c321a97 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1211,8 +1211,7 @@ static int snd_atiixp_free(struct atiixp_modem *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->remap_addr) - iounmap(chip->remap_addr); + iounmap(chip->remap_addr); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index e1cf019..8d2fee7 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -229,9 +229,7 @@ static int snd_aw2_dev_free(struct snd_device *device) if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); /* release the i/o ports & memory */ - if (chip->iobase_virt) - iounmap(chip->iobase_virt); - + iounmap(chip->iobase_virt); pci_release_regions(chip->pci); /* disable the PCI entry */ pci_disable_device(chip->pci); diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 058b997..e82ceac 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -690,8 +690,7 @@ static int snd_bt87x_free(struct snd_bt87x *chip) snd_bt87x_stop(chip); if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->mmio) - iounmap(chip->mmio); + iounmap(chip->mmio); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 05a4337..ea33911 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1316,10 +1316,8 @@ static int snd_cs4281_free(struct cs4281 *chip) if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->ba0) - iounmap(chip->ba0); - if (chip->ba1) - iounmap(chip->ba1); + iounmap(chip->ba0); + iounmap(chip->ba1); pci_release_regions(chip->pci); pci_disable_device(chip->pci); diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index dfec84e..128bbfe 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2949,8 +2949,8 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) for (idx = 0; idx < 5; idx++) { struct snd_cs46xx_region *region = &chip->region.idx[idx]; - if (region->remap_addr) - iounmap(region->remap_addr); + + iounmap(region->remap_addr); release_and_free_resource(region->resource); } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index b425aa8..b8b0d8e 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1985,10 +1985,7 @@ static int hw_card_shutdown(struct hw *hw) free_irq(hw->irq, hw); hw->irq = -1; - - if (hw->mem_base) - iounmap(hw->mem_base); - + iounmap(hw->mem_base); hw->mem_base = NULL; if (hw->io_base) diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 253899d..4e16b4d 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2110,10 +2110,7 @@ static int hw_card_shutdown(struct hw *hw) free_irq(hw->irq, hw); hw->irq = -1; - - if (hw->mem_base) - iounmap(hw->mem_base); - + iounmap(hw->mem_base); hw->mem_base = NULL; if (hw->io_base) diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 21228ad..98d4f35 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1872,12 +1872,8 @@ static int snd_echo_free(struct echoaudio *chip) if (chip->comm_page) snd_dma_free_pages(&chip->commpage_dma_buf); - if (chip->dsp_registers) - iounmap(chip->dsp_registers); - + iounmap(chip->dsp_registers); release_and_free_resource(chip->iores); - - pci_disable_device(chip->pci); /* release chip data */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d426a0b..a971425 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1138,8 +1138,7 @@ static int azx_free(struct azx *chip) free_irq(chip->irq, (void*)chip); if (chip->msi) pci_disable_msi(chip->pci); - if (chip->remap_addr) - iounmap(chip->remap_addr); + iounmap(chip->remap_addr); azx_free_stream_pages(chip); if (chip->region_requested) diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 4cf4be5..9ff60008 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -551,10 +551,8 @@ static void lola_free(struct lola *chip) lola_free_mixer(chip); if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - if (chip->bar[0].remap_addr) - iounmap(chip->bar[0].remap_addr); - if (chip->bar[1].remap_addr) - iounmap(chip->bar[1].remap_addr); + iounmap(chip->bar[0].remap_addr); + iounmap(chip->bar[1].remap_addr); if (chip->rb.area) snd_dma_free_pages(&chip->rb); pci_release_regions(chip->pci); diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 1faf47e..c3a9f39 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1114,10 +1114,9 @@ static int snd_mixart_free(struct mixart_mgr *mgr) } /* release the i/o ports */ - for (i = 0; i < 2; i++) { - if (mgr->mem[i].virt) - iounmap(mgr->mem[i].virt); - } + for (i = 0; i < 2; ++i) + iounmap(mgr->mem[i].virt); + pci_release_regions(mgr->pci); /* free flowarray */ diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 4e41a4e..3f52a44 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1460,10 +1460,8 @@ static int snd_nm256_free(struct nm256 *chip) if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->cport) - iounmap(chip->cport); - if (chip->buffer) - iounmap(chip->buffer); + iounmap(chip->cport); + iounmap(chip->buffer); release_and_free_resource(chip->res_cport); release_and_free_resource(chip->res_buffer); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index cf5a6c8..fe66bcb 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5309,9 +5309,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) release_firmware(hdsp->firmware); vfree(hdsp->fw_uploaded); - - if (hdsp->iobase) - iounmap(hdsp->iobase); + iounmap(hdsp->iobase); if (hdsp->port) pci_release_regions(hdsp->pci); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 3342705..8109b8e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6965,9 +6965,7 @@ static int snd_hdspm_free(struct hdspm * hdspm) free_irq(hdspm->irq, (void *) hdspm); kfree(hdspm->mixer); - - if (hdspm->iobase) - iounmap(hdspm->iobase); + iounmap(hdspm->iobase); if (hdspm->port) pci_release_regions(hdspm->pci); diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 6521521..648911c 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1756,8 +1756,7 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652) if (rme9652->irq >= 0) free_irq(rme9652->irq, (void *)rme9652); - if (rme9652->iobase) - iounmap(rme9652->iobase); + iounmap(rme9652->iobase); if (rme9652->port) pci_release_regions(rme9652->pci); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 7f6a0a0..5e9437b 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1064,12 +1064,9 @@ static int sis_chip_free(struct sis7019 *sis) if (sis->irq >= 0) free_irq(sis->irq, sis); - if (sis->ioaddr) - iounmap(sis->ioaddr); - + iounmap(sis->ioaddr); pci_release_regions(sis->pci); pci_disable_device(sis->pci); - sis_free_suspend(sis); return 0; } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index f5581a9..de7f06f 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2246,8 +2246,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) release_and_free_resource(chip->mpu_res); release_and_free_resource(chip->fm_res); snd_ymfpci_free_gameport(chip); - if (chip->reg_area_virt) - iounmap(chip->reg_area_virt); + iounmap(chip->reg_area_virt); if (chip->work_ptr.area) snd_dma_free_pages(&chip->work_ptr); diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 5a13b22..d399df4 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -867,16 +867,11 @@ static int snd_pmac_free(struct snd_pmac *chip) snd_pmac_dbdma_free(chip, &chip->capture.cmd); snd_pmac_dbdma_free(chip, &chip->extra_dma); snd_pmac_dbdma_free(chip, &emergency_dbdma); - if (chip->macio_base) - iounmap(chip->macio_base); - if (chip->latch_base) - iounmap(chip->latch_base); - if (chip->awacs) - iounmap(chip->awacs); - if (chip->playback.dma) - iounmap(chip->playback.dma); - if (chip->capture.dma) - iounmap(chip->capture.dma); + iounmap(chip->macio_base); + iounmap(chip->latch_base); + iounmap(chip->awacs); + iounmap(chip->playback.dma); + iounmap(chip->capture.dma); if (chip->node) { int i; -- cgit v0.10.2 From 67e9a2ce6e070b1e5db2dfe9c61890fc30ae954d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 4 Jan 2015 19:34:13 +0200 Subject: hsi: nokia-modem: fix uninitialized device pointer modem->device was never initialized. This resulted in logs such as: [ 241.386322] (NULL device *): CMT rst line change detected Signed-off-by: Aaro Koskinen Signed-off-by: Sebastian Reichel diff --git a/drivers/hsi/clients/nokia-modem.c b/drivers/hsi/clients/nokia-modem.c index f0c2145..eb4dc63 100644 --- a/drivers/hsi/clients/nokia-modem.c +++ b/drivers/hsi/clients/nokia-modem.c @@ -162,6 +162,7 @@ static int nokia_modem_probe(struct device *dev) return -ENOMEM; } dev_set_drvdata(dev, modem); + modem->device = dev; irq = irq_of_parse_and_map(np, 0); if (!irq) { -- cgit v0.10.2 From 2c561bc362da5131a26ef9bd34a58918e23a019c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 5 Jan 2015 11:04:37 +0100 Subject: udf: Update Kconfig description Update description of UDF in Kconfig to mention that UDF is also suitable for removable USB disks. Signed-off-by: Jan Kara diff --git a/fs/udf/Kconfig b/fs/udf/Kconfig index 0e0e99b..c6e17a7 100644 --- a/fs/udf/Kconfig +++ b/fs/udf/Kconfig @@ -2,10 +2,12 @@ config UDF_FS tristate "UDF file system support" select CRC_ITU_T help - This is the new file system used on some CD-ROMs and DVDs. Say Y if - you intend to mount DVD discs or CDRW's written in packet mode, or - if written to by other UDF utilities, such as DirectCD. - Please read . + This is a file system used on some CD-ROMs and DVDs. Since the + file system is supported by multiple operating systems and is more + compatible with standard unix file systems, it is also suitable for + removable USB disks. Say Y if you intend to mount DVD discs or CDRW's + written in packet mode, or if you want to use UDF for removable USB + disks. Please read . To compile this file system support as a module, choose M here: the module will be called udf. -- cgit v0.10.2 From 6744e90b0fa1fc6a908fa26935a5ed9e63413063 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 27 Dec 2014 16:01:22 +0100 Subject: ext3: destroy sbi mutexes in put_super Call mutex_destroy() on superblock mutexes in ext3_put_super(). Otherwise mutex debugging code isn't able to detect that mutex is used after being freed. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9b4e7d7..d4dbf3c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -466,6 +466,8 @@ static void ext3_put_super (struct super_block * sb) } sb->s_fs_info = NULL; kfree(sbi->s_blockgroup_lock); + mutex_destroy(&sbi->s_orphan_lock); + mutex_destroy(&sbi->s_resize_lock); kfree(sbi); } -- cgit v0.10.2 From e236fe93e306055c0f927eb09b4d5b10deadbb28 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 1 Sep 2014 15:56:23 +0200 Subject: microblaze: Use empty asm-generic/linkage.h The difference between microblaze and default version in linux/linkage.h is just value stored in the padding bytes which was 0 and in generic is 0x90. Different value shouldn't have any effect. Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/linkage.h b/arch/microblaze/include/asm/linkage.h index 3a8e36d..0540bba 100644 --- a/arch/microblaze/include/asm/linkage.h +++ b/arch/microblaze/include/asm/linkage.h @@ -1,15 +1 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_LINKAGE_H -#define _ASM_MICROBLAZE_LINKAGE_H - -#define __ALIGN .align 4 -#define __ALIGN_STR ".align 4" - -#endif /* _ASM_MICROBLAZE_LINKAGE_H */ +#include -- cgit v0.10.2 From add4b1b02da7e7ec35c34dd04d351ac53f3f0dd8 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:29:54 +0100 Subject: microblaze: Wire-up execveat syscall Add new execveat syscall. Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h index 0a53362..76ed17b 100644 --- a/arch/microblaze/include/asm/unistd.h +++ b/arch/microblaze/include/asm/unistd.h @@ -38,6 +38,6 @@ #endif /* __ASSEMBLY__ */ -#define __NR_syscalls 388 +#define __NR_syscalls 389 #endif /* _ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index c712677..32850c7 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -403,5 +403,6 @@ #define __NR_getrandom 385 #define __NR_memfd_create 386 #define __NR_bpf 387 +#define __NR_execveat 388 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index 0166e89..29c8568 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -388,3 +388,4 @@ ENTRY(sys_call_table) .long sys_getrandom /* 385 */ .long sys_memfd_create .long sys_bpf + .long sys_execveat -- cgit v0.10.2 From 32db31da49ffc969d95c434cc47864b30b1bff9c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:30:49 +0100 Subject: microblaze: Remove unused prom_parse.c of_parse_dma_window is completely unused. Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index 08d50cc..f08baca 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -16,7 +16,7 @@ extra-y := head.o vmlinux.lds obj-y += dma.o exceptions.o \ hw_exception_handler.o intc.o irq.o \ - platform.o process.o prom.o prom_parse.o ptrace.o \ + platform.o process.o prom.o ptrace.o \ reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o obj-y += cpu/ diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c deleted file mode 100644 index 068762f..0000000 --- a/arch/microblaze/kernel/prom_parse.c +++ /dev/null @@ -1,35 +0,0 @@ -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include - -void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, - unsigned long *busno, unsigned long *phys, unsigned long *size) -{ - const u32 *dma_window; - u32 cells; - const unsigned char *prop; - - dma_window = dma_window_prop; - - /* busno is always one cell */ - *busno = *(dma_window++); - - prop = of_get_property(dn, "ibm,#dma-address-cells", NULL); - if (!prop) - prop = of_get_property(dn, "#address-cells", NULL); - - cells = prop ? *(u32 *)prop : of_n_addr_cells(dn); - *phys = of_read_number(dma_window, cells); - - dma_window += cells; - - prop = of_get_property(dn, "ibm,#dma-size-cells", NULL); - cells = prop ? *(u32 *)prop : of_n_size_cells(dn); - *size = of_read_number(dma_window, cells); -} -- cgit v0.10.2 From b366f11b9a81ad0cc7ed3cbdaca15bb98f96db25 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:31:59 +0100 Subject: microblaze: Remove unused prom header from reset.c Completely unused header by this file. Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c index fbe58c6..bab4c83 100644 --- a/arch/microblaze/kernel/reset.c +++ b/arch/microblaze/kernel/reset.c @@ -9,7 +9,6 @@ #include #include -#include /* Trigger specific functions */ #ifdef CONFIG_GPIOLIB -- cgit v0.10.2 From f396a4d2314bf1cb83148d9b8fc47995e6c27e1f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:32:57 +0100 Subject: microblaze: Declare microblaze_kgdb_break in header This patch removes the warning: arch/microblaze/kernel/kgdb.c:81:6: warning: no previous prototype for 'microblaze_kgdb_break' [-Wmissing-prototypes] Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/kgdb.h b/arch/microblaze/include/asm/kgdb.h index 78b17d4..ad27acb 100644 --- a/arch/microblaze/include/asm/kgdb.h +++ b/arch/microblaze/include/asm/kgdb.h @@ -23,6 +23,9 @@ static inline void arch_kgdb_breakpoint(void) __asm__ __volatile__("brki r16, 0x18;"); } +struct pt_regs; +asmlinkage void microblaze_kgdb_break(struct pt_regs *regs); + #endif /* __ASSEMBLY__ */ #endif /* __MICROBLAZE_KGDB_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c index 09a5e82..4bd44b6 100644 --- a/arch/microblaze/kernel/kgdb.c +++ b/arch/microblaze/kernel/kgdb.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define GDB_REG 0 @@ -77,7 +78,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) pt_regb[i] = gdb_regs[i]; } -void microblaze_kgdb_break(struct pt_regs *regs) +asmlinkage void microblaze_kgdb_break(struct pt_regs *regs) { if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0) return; -- cgit v0.10.2 From 8543e6c96762fcc930af5725088c2b9e4865c3aa Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:41:13 +0100 Subject: microblaze: Use unsigned return type in do_syscall_trace_enter Registers are not signed types. The patch removes warnings: arch/microblaze/kernel/ptrace.c: In function 'do_syscall_trace_enter': arch/microblaze/kernel/ptrace.c:152:14: warning: signed and unsigned type in conditional expression [-Wsign-compare] return ret ?: regs->r12; Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h index 53cfaf3..04a5bec 100644 --- a/arch/microblaze/include/asm/syscall.h +++ b/arch/microblaze/include/asm/syscall.h @@ -97,7 +97,7 @@ static inline void syscall_set_arguments(struct task_struct *task, microblaze_set_syscall_arg(regs, i++, *args++); } -asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); +asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs); asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); static inline int syscall_get_arch(void) diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index bb10637..8cfa98c 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -132,9 +132,9 @@ long arch_ptrace(struct task_struct *child, long request, return rval; } -asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) +asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs) { - long ret = 0; + unsigned long ret = 0; secure_computing_strict(regs->r12); -- cgit v0.10.2 From e14ebe417c7c4e58c50ef143d99d797757749762 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:45:38 +0100 Subject: microblaze: Mark get_frame_size as static It is used only locally in unwind.c. The patch removes warning: arch/microblaze/kernel/unwind.c:62:13: warning: no previous prototype for 'get_frame_size' [-Wmissing-prototypes] inline long get_frame_size(unsigned long instr) Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c index 1f7b8d4..61c04ee 100644 --- a/arch/microblaze/kernel/unwind.c +++ b/arch/microblaze/kernel/unwind.c @@ -59,7 +59,7 @@ struct stack_trace; * * Return - Number of stack bytes the instruction reserves or reclaims */ -inline long get_frame_size(unsigned long instr) +static inline long get_frame_size(unsigned long instr) { return abs((s16)(instr & 0xFFFF)); } -- cgit v0.10.2 From b6db0a56218c38455e52780338ad61e284a67e4c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:51:30 +0100 Subject: microblaze: Change extern inline to static inline With compilers which follow the C99 standard (like modern versions of gcc and clang), "extern inline" does the opposite thing from older versions of gcc (emits code for an externally linkable version of the inline function). "static inline" does the intended behavior in all cases instead. Description taken from: "staging, rtl8192e, LLVMLinux: Change extern inline to static inline" (sha1: 6d91857d4826b382b3fd4fad95f52713be646f96) The patch removes compilation warnings W=1: ./arch/microblaze/include/asm/delay.h:18:20: warning: no previous prototype for '__delay' [-Wmissing-prototypes] extern inline void __delay(unsigned long loops) ./arch/microblaze/include/asm/delay.h:46:20: warning: no previous prototype for '__udelay' [-Wmissing-prototypes] extern inline void __udelay(unsigned int x) ./arch/microblaze/include/asm/pgalloc.h:63:22: warning: no previous prototype for 'get_pgd_slow' [-Wmissing-prototypes] extern inline pgd_t *get_pgd_slow(void) ./arch/microblaze/include/asm/pgalloc.h:73:22: warning: no previous prototype for 'get_pgd_fast' [-Wmissing-prototypes] extern inline pgd_t *get_pgd_fast(void) ./arch/microblaze/include/asm/pgalloc.h:87:20: warning: no previous prototype for 'free_pgd_fast' [-Wmissing-prototypes] extern inline void free_pgd_fast(pgd_t *pgd) ./arch/microblaze/include/asm/pgalloc.h:94:20: warning: no previous prototype for 'free_pgd_slow' [-Wmissing-prototypes] extern inline void free_pgd_slow(pgd_t *pgd) ./arch/microblaze/include/asm/pgalloc.h:149:20: warning: no previous prototype for 'pte_free_fast' [-Wmissing-prototypes] extern inline void pte_free_fast(pte_t *pte) ./arch/microblaze/include/asm/pgalloc.h:156:20: warning: no previous prototype for 'pte_free_kernel' [-Wmissing-prototypes] extern inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) ./arch/microblaze/include/asm/pgalloc.h:161:20: warning: no previous prototype for 'pte_free_slow' [-Wmissing-prototypes] extern inline void pte_free_slow(struct page *ptepage) Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/delay.h b/arch/microblaze/include/asm/delay.h index 60cb39d..ea2a9cd 100644 --- a/arch/microblaze/include/asm/delay.h +++ b/arch/microblaze/include/asm/delay.h @@ -15,7 +15,7 @@ #include -extern inline void __delay(unsigned long loops) +static inline void __delay(unsigned long loops) { asm volatile ("# __delay \n\t" \ "1: addi %0, %0, -1\t\n" \ @@ -43,7 +43,7 @@ extern inline void __delay(unsigned long loops) extern unsigned long loops_per_jiffy; -extern inline void __udelay(unsigned int x) +static inline void __udelay(unsigned int x) { unsigned long long tmp = diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h index 7fdf7fa..61436d6 100644 --- a/arch/microblaze/include/asm/pgalloc.h +++ b/arch/microblaze/include/asm/pgalloc.h @@ -60,7 +60,7 @@ extern unsigned long get_zero_page_fast(void); extern void __bad_pte(pmd_t *pmd); -extern inline pgd_t *get_pgd_slow(void) +static inline pgd_t *get_pgd_slow(void) { pgd_t *ret; @@ -70,7 +70,7 @@ extern inline pgd_t *get_pgd_slow(void) return ret; } -extern inline pgd_t *get_pgd_fast(void) +static inline pgd_t *get_pgd_fast(void) { unsigned long *ret; @@ -84,14 +84,14 @@ extern inline pgd_t *get_pgd_fast(void) return (pgd_t *)ret; } -extern inline void free_pgd_fast(pgd_t *pgd) +static inline void free_pgd_fast(pgd_t *pgd) { *(unsigned long **)pgd = pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++; } -extern inline void free_pgd_slow(pgd_t *pgd) +static inline void free_pgd_slow(pgd_t *pgd) { free_page((unsigned long)pgd); } @@ -146,19 +146,19 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, return (pte_t *)ret; } -extern inline void pte_free_fast(pte_t *pte) +static inline void pte_free_fast(pte_t *pte) { *(unsigned long **)pte = pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) { free_page((unsigned long)pte); } -extern inline void pte_free_slow(struct page *ptepage) +static inline void pte_free_slow(struct page *ptepage) { __free_page(ptepage); } -- cgit v0.10.2 From e76fdb324844cc0367f8c6ea5d13278a81568ccb Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:56:17 +0100 Subject: microblaze: Use unsigned type for "for" loop because of comparison-kgdb.c This patch removes warnings reported by W=1: arch/microblaze/kernel/kgdb.c: In function 'pt_regs_to_gdb_regs': arch/microblaze/kernel/kgdb.c:43:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/kgdb.c:51:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/kgdb.c: In function 'gdb_regs_to_pt_regs': arch/microblaze/kernel/kgdb.c:77:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/kgdb.c: In function 'sleeping_thread_to_gdb_regs': arch/microblaze/kernel/kgdb.c:99:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/kgdb.c:103:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c index 4bd44b6..8736af5 100644 --- a/arch/microblaze/kernel/kgdb.c +++ b/arch/microblaze/kernel/kgdb.c @@ -36,9 +36,10 @@ struct pvr_s pvr; void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) { - int i; + unsigned int i; unsigned long *pt_regb = (unsigned long *)regs; int temp; + /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) gdb_regs[i] = pt_regb[i]; @@ -68,7 +69,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) { - int i; + unsigned int i; unsigned long *pt_regb = (unsigned long *)regs; /* pt_regs and gdb_regs have the same 37 values. @@ -92,7 +93,7 @@ asmlinkage void microblaze_kgdb_break(struct pt_regs *regs) /* untested */ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { - int i; + unsigned int i; unsigned long *pt_regb = (unsigned long *)(p->thread.regs); /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ -- cgit v0.10.2 From bdb96e3cad21f5973c95f0e6687db4a57eff7c53 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 16:02:00 +0100 Subject: microblaze: Use unsigned type for proper comparison in cpuinfo*.c Compare the same types together. Compilation warnings: arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c: In function 'set_cpuinfo_pvr_full': arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c:47:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c:52:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c:57:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c:94:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] arch/microblaze/kernel/cpu/cpuinfo-static.c: In function 'set_cpuinfo_static': arch/microblaze/kernel/cpu/cpuinfo-static.c:40:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index 93c26cf..a32daec9 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c @@ -33,7 +33,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) { struct pvr_s pvr; - int temp; /* for saving temp value */ + u32 temp; /* for saving temp value */ get_pvr(&pvr); CI(ver_code, VERSION); diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index 4854285..85dbda4 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -22,7 +22,7 @@ static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER; void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) { - int i = 0; + u32 i = 0; ci->use_instr = (fcpu(cpu, "xlnx,use-barrel") ? PVR0_USE_BARREL_MASK : 0) | -- cgit v0.10.2 From 62c204ddfe9649f0b1d273549f4bd68c23ed7c0d Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 18 Dec 2014 17:50:49 +0000 Subject: fs: Make efivarfs a pseudo filesystem, built by default with EFI efivars is currently enabled under MISC_FILESYSTEMS, which is decribed as "such as filesystems that came from other operating systems". In reality, it is a pseudo filesystem, providing access to the kernel UEFI variable interface. Since this is the preferred interface for accessing UEFI variables, over the legacy efivars interface, also build it by default as a module if CONFIG_EFI. Signed-off-by: Leif Lindholm Signed-off-by: Matt Fleming diff --git a/fs/Kconfig b/fs/Kconfig index 664991a..a6bb530 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -165,6 +165,7 @@ config HUGETLB_PAGE def_bool HUGETLBFS source "fs/configfs/Kconfig" +source "fs/efivarfs/Kconfig" endmenu @@ -209,7 +210,6 @@ source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/exofs/Kconfig" source "fs/f2fs/Kconfig" -source "fs/efivarfs/Kconfig" endif # MISC_FILESYSTEMS diff --git a/fs/efivarfs/Kconfig b/fs/efivarfs/Kconfig index 367bbb1..c2499ef 100644 --- a/fs/efivarfs/Kconfig +++ b/fs/efivarfs/Kconfig @@ -1,6 +1,7 @@ config EFIVAR_FS tristate "EFI Variable filesystem" depends on EFI + default m help efivarfs is a replacement filesystem for the old EFI variable support via sysfs, as it doesn't suffer from the -- cgit v0.10.2 From f595f76defe2b03c45231b9b7f8689be3d26d940 Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Fri, 26 Dec 2014 09:26:25 +0100 Subject: Update of Documentation/cgroups/00-INDEX unified-hierarchy.txt was added by 65731578 (cgroup: add documentation about unified hierarchy) Cc: Tejun Heo Cc: Li Zefan Cc: Jonathan Corbet Cc: cgroups@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Henrik Austad Signed-off-by: Tejun Heo diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX index bc461b6..96ce071 100644 --- a/Documentation/cgroups/00-INDEX +++ b/Documentation/cgroups/00-INDEX @@ -24,3 +24,5 @@ net_prio.txt - Network priority cgroups details and usages. resource_counter.txt - Resource Counter API. +unified-hierarchy.txt + - Description the new/next cgroup interface. -- cgit v0.10.2 From 650705cf73f810c8af4e65a4042a9b6c91667544 Mon Sep 17 00:00:00 2001 From: Nizam Haider Date: Mon, 5 Jan 2015 17:31:03 +0530 Subject: spi/gpio: fixed space coding style issue fixed a coding style issue Signed-off-by: Nizam Haider Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index aee4e75..702b0b8 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -92,7 +92,7 @@ struct spi_gpio { /*----------------------------------------------------------------------*/ -static inline struct spi_gpio * __pure +static inline struct spi_gpio *__pure spi_to_spi_gpio(const struct spi_device *spi) { const struct spi_bitbang *bang; @@ -103,7 +103,7 @@ spi_to_spi_gpio(const struct spi_device *spi) return spi_gpio; } -static inline struct spi_gpio_platform_data * __pure +static inline struct spi_gpio_platform_data *__pure spi_to_pdata(const struct spi_device *spi) { return &spi_to_spi_gpio(spi)->pdata; -- cgit v0.10.2 From 544c55c810a55dcfd2febbc33105642923be9192 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 19:03:55 +0100 Subject: ASoC: Intel: Delete an unnecessary check before the function call "sst_dma_free" The sst_dma_free() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 86e4108..64e9421 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c @@ -410,8 +410,7 @@ void sst_dsp_free(struct sst_dsp *sst) if (sst->ops->free) sst->ops->free(sst); - if (sst->dma) - sst_dma_free(sst->dma); + sst_dma_free(sst->dma); } EXPORT_SYMBOL_GPL(sst_dsp_free); -- cgit v0.10.2 From 180cf794d4f5e0e82a4df30b8bacd9b472f80f44 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 19:25:55 +0100 Subject: ASoC: fsi: Deletion of unnecessary checks before the function call "clk_enable" The clk_enable() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8869971..d49f25f 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -820,12 +820,9 @@ static int fsi_clk_enable(struct device *dev, return ret; } - if (clock->xck) - clk_enable(clock->xck); - if (clock->ick) - clk_enable(clock->ick); - if (clock->div) - clk_enable(clock->div); + clk_enable(clock->xck); + clk_enable(clock->ick); + clk_enable(clock->div); clock->count++; } -- cgit v0.10.2 From 4e3461d34f4cd632b403342ea1df33135e5e3ad3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 19:49:37 +0100 Subject: ASoC: Intel: Delete an unnecessary check before the function call "release_firmware" The release_firmware() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index b580f96..7888cd7 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c @@ -324,8 +324,7 @@ void sst_firmware_load_cb(const struct firmware *fw, void *context) if (ctx->sst_state != SST_RESET || ctx->fw_in_mem != NULL) { - if (fw != NULL) - release_firmware(fw); + release_firmware(fw); mutex_unlock(&ctx->sst_lock); return; } -- cgit v0.10.2 From 121b567d8f4dce55c8095a842766fc1e5523be94 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:04:19 +0100 Subject: regulator: fan53555: Constify struct regmap_config and slew_rates array The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make const also slew_rates array. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 6c43ab2..3c25db8 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -147,7 +147,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } -static int slew_rates[] = { +static const int slew_rates[] = { 64000, 32000, 16000, @@ -296,7 +296,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, return PTR_ERR_OR_ZERO(di->rdev); } -static struct regmap_config fan53555_regmap_config = { +static const struct regmap_config fan53555_regmap_config = { .reg_bits = 8, .val_bits = 8, }; -- cgit v0.10.2 From 035f3324b35296171a9e6bc5744f66daa0ebcfef Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:05:47 +0100 Subject: regulator: max8649: Constify struct regmap_config and regulator_ops The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct regulator_ops const as well. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index c8bddcc..8122957 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -115,7 +115,7 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } -static struct regulator_ops max8649_dcdc_ops = { +static const struct regulator_ops max8649_dcdc_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, @@ -143,7 +143,7 @@ static struct regulator_desc dcdc_desc = { .enable_is_inverted = true, }; -static struct regmap_config max8649_regmap_config = { +static const struct regmap_config max8649_regmap_config = { .reg_bits = 8, .val_bits = 8, }; -- cgit v0.10.2 From 4604a061e6c2462330d56bb7edcd1ca3397a4b73 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:05:48 +0100 Subject: regulator: tps65023: Constify struct regmap_config and regulator_ops The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct regulator_ops const as well. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 7380af8..b941e56 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -173,7 +173,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, } /* Operations permitted on VDCDCx */ -static struct regulator_ops tps65023_dcdc_ops = { +static const struct regulator_ops tps65023_dcdc_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -184,7 +184,7 @@ static struct regulator_ops tps65023_dcdc_ops = { }; /* Operations permitted on LDOx */ -static struct regulator_ops tps65023_ldo_ops = { +static const struct regulator_ops tps65023_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -194,7 +194,7 @@ static struct regulator_ops tps65023_ldo_ops = { .map_voltage = regulator_map_voltage_ascend, }; -static struct regmap_config tps65023_regmap_config = { +static const struct regmap_config tps65023_regmap_config = { .reg_bits = 8, .val_bits = 8, }; -- cgit v0.10.2 From 9caf5067b9cb92c4383909ad1748c804ce223c7d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:07:01 +0100 Subject: spi: meson: Constify struct regmap_config The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index 1bbac03..5468fc7 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -85,7 +85,7 @@ struct meson_spifc { struct device *dev; }; -static struct regmap_config spifc_regmap_config = { +static const struct regmap_config spifc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, -- cgit v0.10.2 From 2b730cc38d3ca592b4f9f71989e7f0c79b37b3b3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:21 +0100 Subject: ASoC: alc5632: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index d1fdbc2..0763026 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1066,7 +1066,7 @@ static int alc5632_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_device_alc5632 = { +static const struct snd_soc_codec_driver soc_codec_device_alc5632 = { .probe = alc5632_probe, .resume = alc5632_resume, .set_bias_level = alc5632_set_bias_level, @@ -1080,7 +1080,7 @@ static struct snd_soc_codec_driver soc_codec_device_alc5632 = { .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes), }; -static struct regmap_config alc5632_regmap = { +static const struct regmap_config alc5632_regmap = { .reg_bits = 8, .val_bits = 16, -- cgit v0.10.2 From d883641f87a42cffcdbbdc664fce1def20ed02b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:22 +0100 Subject: ASoC: cs35l32: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index ec55c590..f2b8aad 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -264,7 +264,7 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val); } -static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { .set_sysclk = cs35l32_codec_set_sysclk, .dapm_widgets = cs35l32_dapm_widgets, @@ -288,7 +288,7 @@ static const struct reg_default cs35l32_monitor_patch[] = { { 0x00, 0x00 }, }; -static struct regmap_config cs35l32_regmap = { +static const struct regmap_config cs35l32_regmap = { .reg_bits = 8, .val_bits = 8, -- cgit v0.10.2 From b5fbcbab50b4f8065666d3633f47722bf8969b34 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:23 +0100 Subject: ASoC: cs42l52: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 35fbef7..1589e7a 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1103,7 +1103,7 @@ static int cs42l52_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { .probe = cs42l52_probe, .remove = cs42l52_remove, .set_bias_level = cs42l52_set_bias_level, @@ -1130,7 +1130,7 @@ static const struct reg_default cs42l52_threshold_patch[] = { }; -static struct regmap_config cs42l52_regmap = { +static const struct regmap_config cs42l52_regmap = { .reg_bits = 8, .val_bits = 8, -- cgit v0.10.2 From cf0efa1c71c86b3ba731b9f3bad37ea4ceee6fbe Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:24 +0100 Subject: ASoC: cs42l56: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 2ddc7ac..cbc654f 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1164,7 +1164,7 @@ static int cs42l56_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { .probe = cs42l56_probe, .remove = cs42l56_remove, .set_bias_level = cs42l56_set_bias_level, @@ -1179,7 +1179,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { .num_controls = ARRAY_SIZE(cs42l56_snd_controls), }; -static struct regmap_config cs42l56_regmap = { +static const struct regmap_config cs42l56_regmap = { .reg_bits = 8, .val_bits = 8, -- cgit v0.10.2 From cd2ee8ad55a1728f291a760cece9ceac11462b9e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:25 +0100 Subject: ASoC: cs42l73: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 7c55537..8ecedba 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1347,7 +1347,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { .probe = cs42l73_probe, .set_bias_level = cs42l73_set_bias_level, .suspend_bias_off = true, @@ -1361,7 +1361,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { .num_controls = ARRAY_SIZE(cs42l73_snd_controls), }; -static struct regmap_config cs42l73_regmap = { +static const struct regmap_config cs42l73_regmap = { .reg_bits = 8, .val_bits = 8, -- cgit v0.10.2 From c0b363891816ea60d95a7dfcfc72f9955a7f1d32 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:26 +0100 Subject: ASoC: wm8804: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 1315f76..b2b0e68 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -648,7 +648,7 @@ static struct snd_soc_dai_driver wm8804_dai = { .symmetric_rates = 1 }; -static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .probe = wm8804_probe, .remove = wm8804_remove, .set_bias_level = wm8804_set_bias_level, @@ -664,7 +664,7 @@ static const struct of_device_id wm8804_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8804_of_match); -static struct regmap_config wm8804_regmap_config = { +static const struct regmap_config wm8804_regmap_config = { .reg_bits = 8, .val_bits = 8, -- cgit v0.10.2 From b682d7baf11ab0d29d511632eb0195b5fa004295 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:27 +0100 Subject: ASoC: wm8988: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver const as well (snd_soc_register_codec() accepts pointer to const). Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index e418199..d320c52 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -813,7 +813,7 @@ static int wm8988_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .probe = wm8988_probe, .set_bias_level = wm8988_set_bias_level, .suspend_bias_off = true, @@ -826,7 +826,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes), }; -static struct regmap_config wm8988_regmap = { +static const struct regmap_config wm8988_regmap = { .reg_bits = 7, .val_bits = 9, -- cgit v0.10.2 From 27ad02f3b6452e0b650835438eb10ba76cb7dfaf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 10:18:28 +0100 Subject: ASoC: wm8804: Constify struct regmap_config and snd_soc_codec_driver The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Make struct snd_soc_codec_driver (snd_soc_register_codec() accepts pointer to const) and array of default register values const as well. Signed-off-by: Krzysztof Kozlowski Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index c280f0a..120228b 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -44,7 +44,7 @@ static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = { "MICVDD" }; -static struct reg_default wm8995_reg_defaults[] = { +static const struct reg_default wm8995_reg_defaults[] = { { 0, 0x8995 }, { 5, 0x0100 }, { 16, 0x000b }, @@ -2190,7 +2190,7 @@ static struct snd_soc_dai_driver wm8995_dai[] = { } }; -static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .probe = wm8995_probe, .remove = wm8995_remove, .set_bias_level = wm8995_set_bias_level, @@ -2204,7 +2204,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), }; -static struct regmap_config wm8995_regmap = { +static const struct regmap_config wm8995_regmap = { .reg_bits = 16, .val_bits = 16, -- cgit v0.10.2 From de7621e870d527e949b5b2351e599398e5fac9ee Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:07 +0100 Subject: ASoC: dmaengine: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Similarly there is also no need to do it on the pcm_new() error path as the PCM will be freed if a error is returned. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index b329b84..4864392 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -200,11 +200,6 @@ static int dmaengine_pcm_open(struct snd_pcm_substream *substream) return snd_dmaengine_pcm_open(substream, chan); } -static void dmaengine_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static struct dma_chan *dmaengine_pcm_compat_request_channel( struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream) @@ -283,8 +278,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!pcm->chan[i]) { dev_err(rtd->platform->dev, "Missing dma channel for stream: %d\n", i); - ret = -EINVAL; - goto err_free; + return -EINVAL; } ret = snd_pcm_lib_preallocate_pages(substream, @@ -293,7 +287,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) prealloc_buffer_size, max_buffer_size); if (ret) - goto err_free; + return ret; /* * This will only return false if we know for sure that at least @@ -307,10 +301,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) } return 0; - -err_free: - dmaengine_pcm_free(rtd->pcm); - return ret; } static snd_pcm_uframes_t dmaengine_pcm_pointer( @@ -341,7 +331,6 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = { }, .ops = &dmaengine_pcm_ops, .pcm_new = dmaengine_pcm_new, - .pcm_free = dmaengine_pcm_free, }; static const char * const dmaengine_pcm_dma_channel_names[] = { -- cgit v0.10.2 From 12e29a075d4c0c9767261068cdcbfa4b346a451b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:08 +0100 Subject: ASoC: au1x: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index b06b8d8..dd94fea 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -315,11 +315,6 @@ static struct snd_pcm_ops au1xpsc_pcm_ops = { .pointer = au1xpsc_pcm_pointer, }; -static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -335,7 +330,6 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_platform_driver au1xpsc_soc_platform = { .ops = &au1xpsc_pcm_ops, .pcm_new = au1xpsc_pcm_new, - .pcm_free = au1xpsc_pcm_free_dma_buffers, }; static int au1xpsc_pcm_drvprobe(struct platform_device *pdev) diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 6ffaaff..24cc7f4 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -287,11 +287,6 @@ static struct snd_pcm_ops alchemy_pcm_ops = { .pointer = alchemy_pcm_pointer, }; -static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -305,7 +300,6 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_platform_driver alchemy_pcm_soc_platform = { .ops = &alchemy_pcm_ops, .pcm_new = alchemy_pcm_new, - .pcm_free = alchemy_pcm_free_dma_buffers, }; static int alchemy_pcm_drvprobe(struct platform_device *pdev) -- cgit v0.10.2 From 3a96878e6d01b70836cbf8a0e968619ef2e2aceb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:10 +0100 Subject: ASoC: nuc900: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index b779a3d..b809fa9 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -306,11 +306,6 @@ static struct snd_pcm_ops nuc900_dma_ops = { .mmap = nuc900_dma_mmap, }; -static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -330,7 +325,6 @@ static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_platform_driver nuc900_soc_platform = { .ops = &nuc900_dma_ops, .pcm_new = nuc900_dma_new, - .pcm_free = nuc900_dma_free_dma_buffers, }; static int nuc900_soc_platform_probe(struct platform_device *pdev) -- cgit v0.10.2 From ddf3335b3e716ab2161e4db5b70984aef35075a3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:11 +0100 Subject: ASoC: rcar: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 75308bb..d9c81cd 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1140,15 +1140,9 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } -static void rsnd_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static struct snd_soc_platform_driver rsnd_soc_platform = { .ops = &rsnd_pcm_ops, .pcm_new = rsnd_pcm_new, - .pcm_free = rsnd_pcm_free, }; static const struct snd_soc_component_driver rsnd_soc_component = { -- cgit v0.10.2 From 0db54e74a9e44afb92bc547277827258dbf5dc8f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:12 +0100 Subject: ASoC: sh: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index a5b2c4e..fd11404 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = { .pointer = camelot_pos, }; -static void camelot_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_platform_driver sh7760_soc_platform = { .ops = &camelot_pcm_ops, .pcm_new = camelot_pcm_new, - .pcm_free = camelot_pcm_free, }; static int sh7760_soc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8869971..422faa9 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1765,11 +1765,6 @@ static struct snd_pcm_ops fsi_pcm_ops = { #define PREALLOC_BUFFER (32 * 1024) #define PREALLOC_BUFFER_MAX (32 * 1024) -static void fsi_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) { return snd_pcm_lib_preallocate_pages_for_all( @@ -1821,7 +1816,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { static struct snd_soc_platform_driver fsi_soc_platform = { .ops = &fsi_pcm_ops, .pcm_new = fsi_pcm_new, - .pcm_free = fsi_pcm_free, }; static const struct snd_soc_component_driver fsi_soc_component = { diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 32eb6da..82902f5 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm) tasklet_kill(&port_info->playback.tasklet); siu_free_port(port_info); - snd_pcm_lib_preallocate_free_for_all(pcm); dev_dbg(pcm->card->dev, "%s\n", __func__); } -- cgit v0.10.2 From 691384503426f97f647e98eed85410eae71c2754 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:13 +0100 Subject: ASoC: txx9: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 070e44e..88eacfd 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -282,11 +282,6 @@ static struct snd_pcm_ops txx9aclc_pcm_ops = { .pointer = txx9aclc_pcm_pointer, }; -static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -412,7 +407,6 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = { .remove = txx9aclc_pcm_remove, .ops = &txx9aclc_pcm_ops, .pcm_new = txx9aclc_pcm_new, - .pcm_free = txx9aclc_pcm_free_dma_buffers, }; static int txx9aclc_soc_platform_probe(struct platform_device *pdev) -- cgit v0.10.2 From d97a552210320d3bec8ee22b8ccdb1d6d189482a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 5 Jan 2015 16:32:12 -0500 Subject: HID: wacom: use WACOM_*_FIELD macros in wacom_usage_mapping() We introduced nice macros in wacom_wac.c to check whether a field is a pen or a touch one. wacom_usage_mapping() still uses it's own tests, which are not in sync with the wacom_wac tests (.application is not checked). That means that some legitimate fields might be filtered out from the usage mapping, and thus will not be used properly while receiving the events. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 6542029..f01ab3a 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_features *features = &wacom->wacom_wac.features; - bool finger = (field->logical == HID_DG_FINGER) || - (field->physical == HID_DG_FINGER); - bool pen = (field->logical == HID_DG_STYLUS) || - (field->physical == HID_DG_STYLUS); + bool finger = WACOM_FINGER_FIELD(field); + bool pen = WACOM_PEN_FIELD(field); /* * Requiring Stylus Usage will ignore boot mouse diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ac7447c..596a6fb5 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -15,7 +15,6 @@ #include "wacom_wac.h" #include "wacom.h" #include -#include /* resolution for penabled devices */ #define WACOM_PL_RES 20 @@ -1514,13 +1513,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev, wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev); } -#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ - ((f)->physical == HID_DG_STYLUS) || \ - ((f)->application == HID_DG_PEN)) -#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ - ((f)->physical == HID_DG_FINGER) || \ - ((f)->application == HID_DG_TOUCHSCREEN)) - void wacom_wac_usage_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index bfad815..7436f2b 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -10,6 +10,7 @@ #define WACOM_WAC_H #include +#include /* maximum packet length for USB devices */ #define WACOM_PKGLEN_MAX 68 @@ -71,6 +72,13 @@ #define WACOM_QUIRK_MONITOR 0x0008 #define WACOM_QUIRK_BATTERY 0x0010 +#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_STYLUS) || \ + ((f)->application == HID_DG_PEN)) +#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ + ((f)->physical == HID_DG_FINGER) || \ + ((f)->application == HID_DG_TOUCHSCREEN)) + enum { PENPARTNER = 0, GRAPHIRE, -- cgit v0.10.2 From 61e9e7e40a93cfb4a70180beefbbb5bd0c860aeb Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 5 Jan 2015 16:32:13 -0500 Subject: HID: wacom: add support of the Pen of the Bamboo Pad Bamboo Pads are using the generic processing but their report descriptors differ from the ISDv* line. The pen fields are marked with the .physical as Digitizer_Pen, which makes also sense. Add this field to the checks and enable for free Bamboo Pads. Reported-by: Josep Sanchez Ferreres Signed-off-by: Benjamin Tissoires Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 7436f2b..7afd929 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -74,6 +74,7 @@ #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ ((f)->physical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_PEN) || \ ((f)->application == HID_DG_PEN)) #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ ((f)->physical == HID_DG_FINGER) || \ -- cgit v0.10.2 From 1540035da71ea0feecdf24eeb98471ffa08da0d3 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Tue, 6 Jan 2015 15:32:15 +0530 Subject: ahci_xgene: Implement the xgene_ahci_poll_reg_val to support PMP. This patch implements the function xgene_ahci_poll_reg_val to poll PxCI for multiple IDENTIFY DEVICE commands to finish before restarting the DMA engine. Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index cbcd208..afa9c03 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -105,17 +105,69 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) } /** + * xgene_ahci_poll_reg_val- Poll a register on a specific value. + * @ap : ATA port of interest. + * @reg : Register of interest. + * @val : Value to be attained. + * @interval : waiting interval for polling. + * @timeout : timeout for achieving the value. + */ +static int xgene_ahci_poll_reg_val(struct ata_port *ap, + void __iomem *reg, unsigned + int val, unsigned long interval, + unsigned long timeout) +{ + unsigned long deadline; + unsigned int tmp; + + tmp = ioread32(reg); + deadline = ata_deadline(jiffies, timeout); + + while (tmp != val && time_before(jiffies, deadline)) { + ata_msleep(ap, interval); + tmp = ioread32(reg); + } + + return tmp; +} + +/** * xgene_ahci_restart_engine - Restart the dma engine. * @ap : ATA port of interest * - * Restarts the dma engine inside the controller. + * Waits for completion of multiple commands and restarts + * the DMA engine inside the controller. */ static int xgene_ahci_restart_engine(struct ata_port *ap) { struct ahci_host_priv *hpriv = ap->host->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + u32 fbs; + + /* + * In case of PMP multiple IDENTIFY DEVICE commands can be + * issued inside PxCI. So need to poll PxCI for the + * completion of outstanding IDENTIFY DEVICE commands before + * we restart the DMA engine. + */ + if (xgene_ahci_poll_reg_val(ap, port_mmio + + PORT_CMD_ISSUE, 0x0, 1, 100)) + return -EBUSY; ahci_stop_engine(ap); ahci_start_fis_rx(ap); + + /* + * Enable the PxFBS.FBS_EN bit as it + * gets cleared due to stopping the engine. + */ + if (pp->fbs_supported) { + fbs = readl(port_mmio + PORT_FBS); + writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS); + fbs = readl(port_mmio + PORT_FBS); + } + hpriv->start_engine(ap); return 0; @@ -374,7 +426,7 @@ static struct ata_port_operations xgene_ahci_ops = { }; static const struct ata_port_info xgene_ahci_port_info = { - .flags = AHCI_FLAG_COMMON, + .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &xgene_ahci_ops, -- cgit v0.10.2 From a3a84bc7c885eee954f1971c43e36a3587fbf565 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Tue, 6 Jan 2015 15:32:16 +0530 Subject: ahci_xgene: Implement the workaround to support PMP enumeration and discovery. Due to H/W errata, the controller is unable to save the PMP field fetched from command header before sending the H2D FIS. When the device returns the PMP port field in the D2H FIS, there is a mismatch and results in command completion failure. The workaround is to write the pmp value to PxFBS.DEV field before issuing any command to PMP. Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index afa9c03..7f68875 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -85,6 +85,7 @@ struct xgene_ahci_context { struct ahci_host_priv *hpriv; struct device *dev; u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ + u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */ void __iomem *csr_core; /* Core CSR address of IP */ void __iomem *csr_diag; /* Diag CSR address of IP */ void __iomem *csr_axi; /* AXI CSR address of IP */ @@ -177,11 +178,17 @@ static int xgene_ahci_restart_engine(struct ata_port *ap) * xgene_ahci_qc_issue - Issue commands to the device * @qc: Command to issue * - * Due to Hardware errata for IDENTIFY DEVICE command and PACKET - * command of ATAPI protocol set, the controller cannot clear the BSY bit - * after receiving the PIO setup FIS. This results in the DMA state machine - * going into the CMFatalErrorUpdate state and locks up. By restarting the - * DMA engine, it removes the controller out of lock up state. + * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot + * clear the BSY bit after receiving the PIO setup FIS. This results in the dma + * state machine goes into the CMFatalErrorUpdate state and locks up. By + * restarting the dma engine, it removes the controller out of lock up state. + * + * Due to H/W errata, the controller is unable to save the PMP + * field fetched from command header before sending the H2D FIS. + * When the device returns the PMP port field in the D2H FIS, there is + * a mismatch and results in command completion failure. The + * workaround is to write the pmp value to PxFBS.DEV field before issuing + * any command to PMP. */ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) { @@ -189,6 +196,19 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) struct ahci_host_priv *hpriv = ap->host->private_data; struct xgene_ahci_context *ctx = hpriv->plat_data; int rc = 0; + u32 port_fbs; + void *port_mmio = ahci_port_base(ap); + + /* + * Write the pmp value to PxFBS.DEV + * for case of Port Mulitplier. + */ + if (ctx->class[ap->port_no] == ATA_DEV_PMP) { + port_fbs = readl(port_mmio + PORT_FBS); + port_fbs &= ~PORT_FBS_DEV_MASK; + port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET; + writel(port_fbs, port_mmio + PORT_FBS); + } if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) || (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET))) @@ -417,12 +437,115 @@ static void xgene_ahci_host_stop(struct ata_host *host) ahci_platform_disable_resources(hpriv); } +/** + * xgene_ahci_pmp_softreset - Issue the softreset to the drives connected + * to Port Multiplier. + * @link: link to reset + * @class: Return value to indicate class of device + * @deadline: deadline jiffies for the operation + * + * Due to H/W errata, the controller is unable to save the PMP + * field fetched from command header before sending the H2D FIS. + * When the device returns the PMP port field in the D2H FIS, there is + * a mismatch and results in command completion failure. The workaround + * is to write the pmp value to PxFBS.DEV field before issuing any command + * to PMP. + */ +static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + struct ata_port *ap = link->ap; + u32 rc; + void *port_mmio = ahci_port_base(ap); + u32 port_fbs; + + /* + * Set PxFBS.DEV field with pmp + * value. + */ + port_fbs = readl(port_mmio + PORT_FBS); + port_fbs &= ~PORT_FBS_DEV_MASK; + port_fbs |= pmp << PORT_FBS_DEV_OFFSET; + writel(port_fbs, port_mmio + PORT_FBS); + + rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); + + return rc; +} + +/** + * xgene_ahci_softreset - Issue the softreset to the drive. + * @link: link to reset + * @class: Return value to indicate class of device + * @deadline: deadline jiffies for the operation + * + * Due to H/W errata, the controller is unable to save the PMP + * field fetched from command header before sending the H2D FIS. + * When the device returns the PMP port field in the D2H FIS, there is + * a mismatch and results in command completion failure. The workaround + * is to write the pmp value to PxFBS.DEV field before issuing any command + * to PMP. Here is the algorithm to detect PMP : + * + * 1. Save the PxFBS value + * 2. Program PxFBS.DEV with pmp value send by framework. Framework sends + * 0xF for both PMP/NON-PMP initially + * 3. Issue softreset + * 4. If signature class is PMP goto 6 + * 5. restore the original PxFBS and goto 3 + * 6. return + */ +static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; + struct xgene_ahci_context *ctx = hpriv->plat_data; + void *port_mmio = ahci_port_base(ap); + u32 port_fbs; + u32 port_fbs_save; + u32 retry = 1; + u32 rc; + + port_fbs_save = readl(port_mmio + PORT_FBS); + + /* + * Set PxFBS.DEV field with pmp + * value. + */ + port_fbs = readl(port_mmio + PORT_FBS); + port_fbs &= ~PORT_FBS_DEV_MASK; + port_fbs |= pmp << PORT_FBS_DEV_OFFSET; + writel(port_fbs, port_mmio + PORT_FBS); + +softreset_retry: + rc = ahci_do_softreset(link, class, pmp, + deadline, ahci_check_ready); + + ctx->class[ap->port_no] = *class; + if (*class != ATA_DEV_PMP) { + /* + * Retry for normal drives without + * setting PxFBS.DEV field with pmp value. + */ + if (retry--) { + writel(port_fbs_save, port_mmio + PORT_FBS); + goto softreset_retry; + } + } + + return rc; +} + static struct ata_port_operations xgene_ahci_ops = { .inherits = &ahci_ops, .host_stop = xgene_ahci_host_stop, .hardreset = xgene_ahci_hardreset, .read_id = xgene_ahci_read_id, .qc_issue = xgene_ahci_qc_issue, + .softreset = xgene_ahci_softreset, + .pmp_softreset = xgene_ahci_pmp_softreset }; static const struct ata_port_info xgene_ahci_port_info = { -- cgit v0.10.2 From 6810e4a394f9d781050107529b8d1465c00b7b13 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 6 Jan 2015 10:26:10 -0500 Subject: percpu_ref: remove unnecessary ACCESS_ONCE() in percpu_ref_tryget_live() __ref_is_percpu() needs the implied ACCESS_ONCE() in lockless_dereference() on @ref->percpu_count_ptr because the value is tested for !__PERCPU_REF_ATOMIC, which may be set asynchronously, and then used as a pointer. If the compiler generates a separate fetch when using it as a pointer, __PERCPU_REF_ATOMIC may be set in between contaminating the pointer value. percpu_ref_tryget_live() also uses ACCESS_ONCE() to test __PERCPU_REF_DEAD; however, there's no reason for this. I just copied ACCESS_ONCE() usage blindly from __ref_is_percpu(). All it does is confusing people trying to understand what's going on. This patch removes the unnecessary ACCESS_ONCE() usage from percpu_ref_tryget_live() and adds a comment explaining why __ref_is_percpu() needs it. Signed-off-by: Tejun Heo Cc: Kent Overstreet diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h index b433764..6a7a670 100644 --- a/include/linux/percpu-refcount.h +++ b/include/linux/percpu-refcount.h @@ -128,8 +128,22 @@ static inline void percpu_ref_kill(struct percpu_ref *ref) static inline bool __ref_is_percpu(struct percpu_ref *ref, unsigned long __percpu **percpu_countp) { - /* paired with smp_store_release() in percpu_ref_reinit() */ - unsigned long percpu_ptr = lockless_dereference(ref->percpu_count_ptr); + unsigned long percpu_ptr; + + /* + * The value of @ref->percpu_count_ptr is tested for + * !__PERCPU_REF_ATOMIC, which may be set asynchronously, and then + * used as a pointer. If the compiler generates a separate fetch + * when using it as a pointer, __PERCPU_REF_ATOMIC may be set in + * between contaminating the pointer value, meaning that + * ACCESS_ONCE() is required when fetching it. + * + * Also, we need a data dependency barrier to be paired with + * smp_store_release() in __percpu_ref_switch_to_percpu(). + * + * Use lockless deref which contains both. + */ + percpu_ptr = lockless_dereference(ref->percpu_count_ptr); /* * Theoretically, the following could test just ATOMIC; however, @@ -233,7 +247,7 @@ static inline bool percpu_ref_tryget_live(struct percpu_ref *ref) if (__ref_is_percpu(ref, &percpu_count)) { this_cpu_inc(*percpu_count); ret = true; - } else if (!(ACCESS_ONCE(ref->percpu_count_ptr) & __PERCPU_REF_DEAD)) { + } else if (!(ref->percpu_count_ptr & __PERCPU_REF_DEAD)) { ret = atomic_long_inc_not_zero(&ref->count); } -- cgit v0.10.2 From 4c907baf36d8339f393bb576d0bab29194d0e6ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 6 Jan 2015 10:26:10 -0500 Subject: percpu_ref: implement percpu_ref_is_dying() Implement percpu_ref_is_dying() which tests whether the ref is dying or dead. This is useful to determine the current state when a percpu_ref is used as a cyclic on/off switch via kill and reinit. Signed-off-by: Tejun Heo Cc: Kent Overstreet diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h index 6a7a670..12c9b48 100644 --- a/include/linux/percpu-refcount.h +++ b/include/linux/percpu-refcount.h @@ -295,6 +295,20 @@ static inline void percpu_ref_put(struct percpu_ref *ref) } /** + * percpu_ref_is_dying - test whether a percpu refcount is dying or dead + * @ref: percpu_ref to test + * + * Returns %true if @ref is dying or dead. + * + * This function is safe to call as long as @ref is between init and exit + * and the caller is responsible for synchronizing against state changes. + */ +static inline bool percpu_ref_is_dying(struct percpu_ref *ref) +{ + return ref->percpu_count_ptr & __PERCPU_REF_DEAD; +} + +/** * percpu_ref_is_zero - test whether a percpu refcount reached zero * @ref: percpu_ref to test * -- cgit v0.10.2 From 24dab7a7b3534ef40ecec20cfd7fb3ad99d9ff33 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 6 Jan 2015 12:02:46 -0500 Subject: cgroup: reorder SUBSYS(blkio) in cgroup_subsys.h The scheduled cgroup writeback support requires blkio to be initialized before memcg as memcg needs to provide certain blkcg related functionalities. Relocate blkio so that it's right above memory. Signed-off-by: Tejun Heo diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 98c4f9b..e4a96fb 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -15,6 +15,10 @@ SUBSYS(cpu) SUBSYS(cpuacct) #endif +#if IS_ENABLED(CONFIG_BLK_CGROUP) +SUBSYS(blkio) +#endif + #if IS_ENABLED(CONFIG_MEMCG) SUBSYS(memory) #endif @@ -31,10 +35,6 @@ SUBSYS(freezer) SUBSYS(net_cls) #endif -#if IS_ENABLED(CONFIG_BLK_CGROUP) -SUBSYS(blkio) -#endif - #if IS_ENABLED(CONFIG_CGROUP_PERF) SUBSYS(perf_event) #endif -- cgit v0.10.2 From f3ba53802eff25e3eedb60d7afe5262710e20bd5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 6 Jan 2015 12:02:46 -0500 Subject: cgroup: add dummy css_put() for !CONFIG_CGROUPS This will later be depended upon by the scheduled cgroup writeback support. Signed-off-by: Tejun Heo diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index da0dae0..b9cb94c 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -943,6 +943,8 @@ struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry, #else /* !CONFIG_CGROUPS */ +struct cgroup_subsys_state; + static inline int cgroup_init_early(void) { return 0; } static inline int cgroup_init(void) { return 0; } static inline void cgroup_fork(struct task_struct *p) {} @@ -955,6 +957,8 @@ static inline int cgroupstats_build(struct cgroupstats *stats, return -EINVAL; } +static inline void css_put(struct cgroup_subsys_state *css) {} + /* No cgroups - nothing to do */ static inline int cgroup_attach_task_all(struct task_struct *from, struct task_struct *t) -- cgit v0.10.2 From 2b5e368e4195749e50188dca4394ac8d25ff39f2 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Tue, 6 Jan 2015 15:23:40 +0200 Subject: spi/dln2: simplify return flow for dln2_spi_transfer_setup and dln2_spi_enable This fixes the following kbuild test robot warnings: >> drivers/spi/spi-dln2.c:124:1-4: WARNING: end returns can be simplified if negative or 0 value >> drivers/spi/spi-dln2.c:656:1-4: WARNING: end returns can be simplified if negative or 0 value Additionally, fix a comment after switching from CONFIG_PM_RUNTIME to CONFIG_PM. Reported-by: Julia Lawall Signed-off-by: Laurentiu Palcu Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c index cede063..3b7d91d 100644 --- a/drivers/spi/spi-dln2.c +++ b/drivers/spi/spi-dln2.c @@ -103,7 +103,6 @@ struct dln2_spi { */ static int dln2_spi_enable(struct dln2_spi *dln2, bool enable) { - int ret; u16 cmd; struct { u8 port; @@ -121,11 +120,7 @@ static int dln2_spi_enable(struct dln2_spi *dln2, bool enable) cmd = DLN2_SPI_DISABLE; } - ret = dln2_transfer_tx(dln2->pdev, cmd, &tx, len); - if (ret < 0) - return ret; - - return 0; + return dln2_transfer_tx(dln2->pdev, cmd, &tx, len); } /* @@ -653,11 +648,7 @@ static int dln2_spi_transfer_setup(struct dln2_spi *dln2, u32 speed, dln2->bpw = bpw; } - ret = dln2_spi_enable(dln2, true); - if (ret < 0) - return ret; - - return 0; + return dln2_spi_enable(dln2, true); } static int dln2_spi_transfer_one(struct spi_master *master, @@ -866,7 +857,7 @@ static int dln2_spi_runtime_resume(struct device *dev) return dln2_spi_enable(dln2, true); } -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ static const struct dev_pm_ops dln2_spi_pm = { SET_SYSTEM_SLEEP_PM_OPS(dln2_spi_suspend, dln2_spi_resume) -- cgit v0.10.2 From 38455d7ac2e383d747ddee0189c7d8c078b29b09 Mon Sep 17 00:00:00 2001 From: Esben Haabendal Date: Tue, 6 Jan 2015 14:07:34 +0100 Subject: spi: fsl-(e)spi: Support compile as module Signed-off-by: Esben Haabendal Signed-off-by: Mark Brown diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9982998..468d13c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -279,7 +279,7 @@ config SPI_FSL_CPM depends on FSL_SOC config SPI_FSL_SPI - bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller" + tristate "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller" depends on OF select SPI_FSL_LIB select SPI_FSL_CPM if FSL_SOC @@ -300,7 +300,7 @@ config SPI_FSL_DSPI mode. VF610 platform uses the controller. config SPI_FSL_ESPI - bool "Freescale eSPI controller" + tristate "Freescale eSPI controller" depends on FSL_SOC select SPI_FSL_LIB help diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index e85ab1c..9c46a30 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) } } } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_reinit_txrx); static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) { @@ -162,6 +164,7 @@ err_rx_dma: dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); return -ENOMEM; } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs); void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { @@ -174,6 +177,7 @@ void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); mspi->xfer_in_progress = NULL; } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete); void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { @@ -198,6 +202,7 @@ void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) else complete(&mspi->done); } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_irq); static void *fsl_spi_alloc_dummy_rx(void) { @@ -375,6 +380,7 @@ err_pram: fsl_spi_free_dummy_rx(); return -ENOMEM; } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_init); void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) { @@ -389,3 +395,6 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) cpm_muram_free(cpm_muram_offset(mspi->pram)); fsl_spi_free_dummy_rx(); } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_free); + +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 9d3f9e0..cb35d2f 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_FSL_SOC @@ -35,7 +36,8 @@ void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ type *rx = mpc8xxx_spi->rx; \ *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ mpc8xxx_spi->rx = rx; \ -} +} \ +EXPORT_SYMBOL_GPL(mpc8xxx_spi_rx_buf_##type); #define MPC8XXX_SPI_TX_BUF(type) \ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ @@ -47,7 +49,8 @@ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ data = *tx++ << mpc8xxx_spi->tx_shift; \ mpc8xxx_spi->tx = tx; \ return data; \ -} +} \ +EXPORT_SYMBOL_GPL(mpc8xxx_spi_tx_buf_##type); MPC8XXX_SPI_RX_BUF(u8) MPC8XXX_SPI_RX_BUF(u16) @@ -60,6 +63,7 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata) { return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); } +EXPORT_SYMBOL_GPL(to_of_pinfo); const char *mpc8xxx_spi_strmode(unsigned int flags) { @@ -75,6 +79,7 @@ const char *mpc8xxx_spi_strmode(unsigned int flags) } return "CPU"; } +EXPORT_SYMBOL_GPL(mpc8xxx_spi_strmode); void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) @@ -107,6 +112,7 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, init_completion(&mpc8xxx_spi->done); } +EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe); int mpc8xxx_spi_remove(struct device *dev) { @@ -125,6 +131,7 @@ int mpc8xxx_spi_remove(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove); int of_mpc8xxx_spi_probe(struct platform_device *ofdev) { @@ -171,3 +178,6 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) return 0; } +EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe); + +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index b4ed04e..1326a39 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -28,7 +28,7 @@ struct mpc8xxx_spi { /* rx & tx bufs from the spi_transfer */ const void *tx; void *rx; -#ifdef CONFIG_SPI_FSL_ESPI +#if IS_ENABLED(CONFIG_SPI_FSL_ESPI) int len; #endif @@ -68,7 +68,7 @@ struct mpc8xxx_spi { unsigned int flags; -#ifdef CONFIG_SPI_FSL_SPI +#if IS_ENABLED(CONFIG_SPI_FSL_SPI) int type; int native_chipselects; u8 max_bits_per_word; -- cgit v0.10.2 From 057a1573fd1309a6b3a039f9cd75b4e90f7f6cf4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 11:30:35 +0100 Subject: ASoC: broadwell: Drop unnecessary snd_soc_dapm_enable() calls DAPM widgets are enabled by default, there is no need to enable them unless they have previously been explicitly disabled. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 7cf95d5..9cf7d01 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -140,8 +140,6 @@ static struct snd_soc_ops broadwell_rt286_ops = { static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); struct sst_hsw *broadwell = pdata->dsp; int ret; @@ -155,14 +153,6 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - /* always connected - check HP for jack detect */ - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - snd_soc_dapm_enable_pin(dapm, "Line Jack"); - snd_soc_dapm_enable_pin(dapm, "DMIC1"); - snd_soc_dapm_enable_pin(dapm, "DMIC2"); - return 0; } -- cgit v0.10.2 From 7a81140b0ead01fcb27e6167b1015b06c36acbd0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 11:23:44 +0100 Subject: ASoC: byt-rt5640: Fix snd_soc_dapm_ignore_suspend() calls To work properly snd_soc_dapm_ignore_suspend() needs to be called on endpoint widgets. In this case those are the board level Speaker and Headphone widgets and not the CODEC output widgets that are connected to them. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 0cba783..a51856e 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -171,13 +171,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; } - snd_soc_dapm_ignore_suspend(dapm, "HPOL"); - snd_soc_dapm_ignore_suspend(dapm, "HPOR"); - - snd_soc_dapm_ignore_suspend(dapm, "SPOLP"); - snd_soc_dapm_ignore_suspend(dapm, "SPOLN"); - snd_soc_dapm_ignore_suspend(dapm, "SPORP"); - snd_soc_dapm_ignore_suspend(dapm, "SPORN"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); return ret; } -- cgit v0.10.2 From b93673be48cef887551d109683922bcc15f40d27 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 11:23:45 +0100 Subject: ASoC: byt-rt5640: Register microphone routes with the card DAPM context Board level DAPM elements should be registered with the card's DAPM context rather than the CODEC's DAPM context. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index a51856e..354eaad 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -132,7 +132,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_codec *codec = runtime->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = runtime->card; const struct snd_soc_dapm_route *custom_map; int num_routes; @@ -161,7 +160,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); } - ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); if (ret) return ret; -- cgit v0.10.2 From 8686f251e4823a4196bae86f22dab8cfd3b454cc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:09 +0100 Subject: ASoC: intel: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 3bb6288..224c49c 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c @@ -320,11 +320,6 @@ static struct snd_pcm_ops sst_byt_pcm_ops = { .mmap = sst_byt_pcm_mmap, }; -static void sst_byt_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -403,7 +398,6 @@ static struct snd_soc_platform_driver byt_soc_platform = { .remove = sst_byt_pcm_remove, .ops = &sst_byt_pcm_ops, .pcm_new = sst_byt_pcm_new, - .pcm_free = sst_byt_pcm_free, }; static const struct snd_soc_component_driver byt_dai_component = { diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 6195252..13f156b 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -735,11 +735,6 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) } } -static void hsw_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -936,7 +931,6 @@ static struct snd_soc_platform_driver hsw_soc_platform = { .remove = hsw_pcm_remove, .ops = &hsw_pcm_ops, .pcm_new = hsw_pcm_new, - .pcm_free = hsw_pcm_free, }; static const struct snd_soc_component_driver hsw_dai_component = { diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index a1a8d9d..7523cbe 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -643,12 +643,6 @@ static struct snd_pcm_ops sst_platform_ops = { .pointer = sst_platform_pcm_pointer, }; -static void sst_pcm_free(struct snd_pcm *pcm) -{ - dev_dbg(pcm->dev, "sst_pcm_free called\n"); - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; @@ -679,7 +673,6 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = { .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, - .pcm_free = sst_pcm_free, }; static const struct snd_soc_component_driver sst_component = { -- cgit v0.10.2 From 059d3dc6e5e8d4a62803eb3ad01b34fa3f714675 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:10 +0100 Subject: ASoC: sam9g20_wm8731: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Acked-by: Bo Shen Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 66b66d0..98ca634 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -64,33 +64,6 @@ static struct clk *mclk; -static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops at91sam9g20ek_ops = { - .hw_params = at91sam9g20ek_hw_params, -}; - static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) @@ -173,7 +146,8 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { .init = at91sam9g20ek_wm8731_init, .platform_name = "at91rm9200_ssc.0", .codec_name = "wm8731.0-001b", - .ops = &at91sam9g20ek_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }; static struct snd_soc_card snd_soc_at91sam9g20ek = { -- cgit v0.10.2 From b4508d0f95fa4aaed889549e31391641d675d4bb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:11 +0100 Subject: ASoC: db1200: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index a747ac0..c75995f 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -91,27 +91,12 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret; /* WM8731 has its own 12MHz crystal */ snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, 12000000, SND_SOC_CLOCK_IN); - /* codec is bitclock and lrclk master */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - goto out; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - goto out; - - ret = 0; -out: - return ret; + return 0; } static struct snd_soc_ops db1200_i2s_wm8731_ops = { @@ -125,6 +110,8 @@ static struct snd_soc_dai_link db1200_i2s_dai = { .cpu_dai_name = "au1xpsc_i2s.1", .platform_name = "au1xpsc-pcm.1", .codec_name = "wm8731.0-001b", + .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &db1200_i2s_wm8731_ops, }; -- cgit v0.10.2 From 4de59dbd28565ad1074d2bcf294a0a4b41c64e07 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:12 +0100 Subject: ASoC: eureka-tlv320: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 9ce70fc..8c9e900 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -42,25 +42,6 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - /* fsl_ssi lacks the set_fmt ops. */ - if (ret && ret != -ENOTSUPP) { - dev_err(cpu_dai->dev, - "Failed to set the cpu dai format.\n"); - return ret; - } - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret) { - dev_err(cpu_dai->dev, - "Failed to set the codec format.\n"); - return ret; - } - ret = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_OUT); if (ret) { @@ -91,6 +72,8 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", .codec_dai_name = "tlv320aic23-hifi", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &eukrea_tlv320_snd_ops, }; -- cgit v0.10.2 From dea53bd36811d6b117a497eb91b2e4a54ef73548 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:13 +0100 Subject: ASoC: mx27vis-aci32x4: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c index b1ced7b..198eeb3 100644 --- a/sound/soc/fsl/mx27vis-aic32x4.c +++ b/sound/soc/fsl/mx27vis-aic32x4.c @@ -55,16 +55,6 @@ static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - u32 dai_format; - - dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; - - /* set codec DAI configuration */ - snd_soc_dai_set_fmt(codec_dai, dai_format); - - /* set cpu DAI configuration */ - snd_soc_dai_set_fmt(cpu_dai, dai_format); ret = snd_soc_dai_set_sysclk(codec_dai, 0, 25000000, SND_SOC_CLOCK_OUT); @@ -164,6 +154,8 @@ static struct snd_soc_dai_link mx27vis_aic32x4_dai = { .platform_name = "imx-ssi.0", .codec_name = "tlv320aic32x4.0-0018", .cpu_dai_name = "imx-ssi.0", + .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &mx27vis_aic32x4_snd_ops, }; -- cgit v0.10.2 From 734890a6c99ee81b935164963c03fc8bbf3f821b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:14 +0100 Subject: ASoC: wm1133-ev1: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index 804749a..d072bd1 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -87,7 +87,6 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t format = params_format(params); unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); - u32 dai_format; /* find the correct audio parameters */ for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) { @@ -104,15 +103,6 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream, /* codec FLL input is 14.75 MHz from MCLK */ snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk); - dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; - - /* set codec DAI configuration */ - snd_soc_dai_set_fmt(codec_dai, dai_format); - - /* set cpu DAI configuration */ - snd_soc_dai_set_fmt(cpu_dai, dai_format); - /* TODO: The SSI driver should figure this out for us */ switch (channels) { case 2: @@ -244,6 +234,8 @@ static struct snd_soc_dai_link wm1133_ev1_dai = { .init = wm1133_ev1_init, .ops = &wm1133_ev1_ops, .symmetric_rates = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }; static struct snd_soc_card wm1133_ev1 = { -- cgit v0.10.2 From bc6a5d649bda56c579853bfe710db88bf38da522 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:15 +0100 Subject: ASoC: mxs-sgtl5000: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 6f1916b..6e6fce6 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -36,7 +36,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; unsigned int rate = params_rate(params); - u32 dai_format, mclk; + u32 mclk; int ret; /* sgtl5000 does not support 512*rate when in 96000 fs */ @@ -65,26 +65,6 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, return ret; } - /* set codec to slave mode */ - dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, dai_format); - if (ret) { - dev_err(codec_dai->dev, "Failed to set dai format to %08x\n", - dai_format); - return ret; - } - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); - if (ret) { - dev_err(cpu_dai->dev, "Failed to set dai format to %08x\n", - dai_format); - return ret; - } - return 0; } @@ -92,17 +72,22 @@ static struct snd_soc_ops mxs_sgtl5000_hifi_ops = { .hw_params = mxs_sgtl5000_hw_params, }; +#define MXS_SGTL5000_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS) + static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { { .name = "HiFi Tx", .stream_name = "HiFi Playback", .codec_dai_name = "sgtl5000", + .dai_fmt = MXS_SGTL5000_DAI_FMT, .ops = &mxs_sgtl5000_hifi_ops, .playback_only = true, }, { .name = "HiFi Rx", .stream_name = "HiFi Capture", .codec_dai_name = "sgtl5000", + .dai_fmt = MXS_SGTL5000_DAI_FMT, .ops = &mxs_sgtl5000_hifi_ops, .capture_only = true, }, -- cgit v0.10.2 From 3aa273e3f65455066aa7338845e11910ba2bae12 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:16 +0100 Subject: ASoC: ams-delta: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 4c6afb7..7066130 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -412,21 +412,7 @@ static struct tty_ldisc_ops cx81801_ops = { * over the modem port. */ -static int ams_delta_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* Set cpu DAI configuration */ - return snd_soc_dai_set_fmt(rtd->cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); -} - -static struct snd_soc_ops ams_delta_ops = { - .hw_params = ams_delta_hw_params, -}; +static struct snd_soc_ops ams_delta_ops; /* Digital mute implemented using modem/CPU multiplexer. @@ -546,6 +532,8 @@ static struct snd_soc_dai_link ams_delta_dai_link = { .platform_name = "omap-mcbsp.1", .codec_name = "cx20442-codec", .ops = &ams_delta_ops, + .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }; /* Audio card driver */ -- cgit v0.10.2 From a8bd0ee5587148cd1a23302ef37bf3f236fe6705 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:17 +0100 Subject: ASoC: raumfeld: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index 0837065..552b763 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -88,7 +88,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - unsigned int fmt, clk = 0; + unsigned int clk = 0; int ret = 0; switch (params_rate(params)) { @@ -112,15 +112,6 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; - - /* setup the CODEC DAI */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0); if (ret < 0) return ret; @@ -130,10 +121,6 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4); if (ret < 0) return ret; @@ -169,9 +156,8 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int fmt, ret = 0, clk = 0; + int ret = 0, clk = 0; switch (params_rate(params)) { case 44100: @@ -194,22 +180,11 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; - - /* setup the CODEC DAI */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - /* setup the CPU DAI */ ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk); if (ret < 0) return ret; - ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4); if (ret < 0) return ret; @@ -233,6 +208,9 @@ static struct snd_soc_ops raumfeld_ak4104_ops = { .platform_name = "pxa-pcm-audio", \ .codec_dai_name = "cs4270-hifi", \ .codec_name = "cs4270.0-0048", \ + .dai_fmt = SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS, \ .ops = &raumfeld_cs4270_ops, \ } @@ -243,6 +221,9 @@ static struct snd_soc_ops raumfeld_ak4104_ops = { .cpu_dai_name = "pxa-ssp-dai.1", \ .codec_dai_name = "ak4104-hifi", \ .platform_name = "pxa-pcm-audio", \ + .dai_fmt = SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS, \ .ops = &raumfeld_ak4104_ops, \ .codec_name = "spi0.0", \ } -- cgit v0.10.2 From 132c30969b9346a628f597804d2343b6df493693 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:18 +0100 Subject: ASoC: zylonite: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 23bf991..8f301c7 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -130,16 +130,6 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - return 0; } @@ -172,6 +162,8 @@ static struct snd_soc_dai_link zylonite_dai[] = { .platform_name = "pxa-pcm-audio", .cpu_dai_name = "pxa-ssp-dai.2", .codec_dai_name = "wm9713-voice", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &zylonite_voice_ops, }, }; -- cgit v0.10.2 From 0af76f918adb8487a911bc136a6f1b12c46cd056 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:19 +0100 Subject: ASoC: goni_wm8994: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index 3b527dc..fad56b9 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -136,22 +136,9 @@ static int goni_hifi_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; unsigned int pll_out = 24000000; int ret = 0; - /* set the cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - /* set the codec FLL */ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out, params_rate(params) * 256); @@ -182,12 +169,6 @@ static int goni_voice_hw_params(struct snd_pcm_substream *substream, if (params_rate(params) != 8000) return -EINVAL; - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J | - SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - /* set the codec FLL */ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out, params_rate(params) * 256); @@ -234,6 +215,8 @@ static struct snd_soc_dai_link goni_dai[] = { .codec_dai_name = "wm8994-aif1", .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec.0-001a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .init = goni_wm8994_init, .ops = &goni_hifi_ops, }, { @@ -242,6 +225,8 @@ static struct snd_soc_dai_link goni_dai[] = { .cpu_dai_name = "goni-voice-dai", .codec_dai_name = "wm8994-aif2", .codec_name = "wm8994-codec.0-001a", + .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_IB_IF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &goni_voice_ops, }, }; -- cgit v0.10.2 From 5cc10b9b77c234e89e7c4aca56d8a3c571111955 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:20 +0100 Subject: ASoC: h1940_uda1380: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index f2d7980..59b0442 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -76,7 +76,6 @@ static int h1940_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; int div; int ret; unsigned int rate = params_rate(params); @@ -95,18 +94,6 @@ static int h1940_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - /* select clock source */ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate, SND_SOC_CLOCK_OUT); @@ -207,6 +194,8 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = { .init = h1940_uda1380_init, .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &h1940_ops, }, }; -- cgit v0.10.2 From 72303cafcb5cc9fd1227d0edd458f62bef1a397e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:21 +0100 Subject: ASoC: jive_wm8750: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c index b5f6abd..6c3b359 100644 --- a/sound/soc/samsung/jive_wm8750.c +++ b/sound/soc/samsung/jive_wm8750.c @@ -61,20 +61,6 @@ static int jive_hw_params(struct snd_pcm_substream *substream, s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), s3c_i2sv2_get_clock(cpu_dai)); - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - /* set the codec system clock for DAC and ADC */ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, SND_SOC_CLOCK_IN); @@ -121,6 +107,8 @@ static struct snd_soc_dai_link jive_dai = { .platform_name = "s3c2412-i2s", .codec_name = "wm8750.0-001a", .init = jive_wm8750_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &jive_ops, }; -- cgit v0.10.2 From e16514d931635640906ab2810c98f6a9047cb87a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:22 +0100 Subject: ASoC: neo1973_wm8753: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 9b4a09f..65602b9 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -70,20 +70,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, break; } - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - /* set the codec system clock for DAC and ADC */ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, SND_SOC_CLOCK_IN); @@ -151,13 +137,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ - /* todo: gg check mode (DSP_B) against CSR datasheet */ - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - /* set the codec system clock for DAC and ADC */ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, SND_SOC_CLOCK_IN); @@ -300,6 +279,8 @@ static struct snd_soc_dai_link neo1973_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "wm8753-hifi", .codec_name = "wm8753.0-001a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .init = neo1973_wm8753_init, .ops = &neo1973_hifi_ops, }, @@ -309,6 +290,8 @@ static struct snd_soc_dai_link neo1973_dai[] = { .cpu_dai_name = "bt-sco-pcm", .codec_dai_name = "wm8753-voice", .codec_name = "wm8753.0-001a", + .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &neo1973_voice_ops, }, }; -- cgit v0.10.2 From 5f0acedddf533c086edf29eefdc743dc1e756b5d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:23 +0100 Subject: ASoC: rx1950_uda1380: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 37688eb..873f2cb 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -89,6 +89,8 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = { .init = rx1950_uda1380_init, .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &rx1950_ops, }, }; @@ -154,7 +156,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; int div; int ret; unsigned int rate = params_rate(params); @@ -181,18 +182,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - /* select clock source */ ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate, SND_SOC_CLOCK_OUT); -- cgit v0.10.2 From d27e51dade482acdf67021c12d692041a35bea77 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:24 +0100 Subject: ASoC: s3c24xx_simtec: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c index 2c015f6..dcc008d 100644 --- a/sound/soc/samsung/s3c24xx_simtec.c +++ b/sound/soc/samsung/s3c24xx_simtec.c @@ -169,24 +169,6 @@ static int simtec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - /* Set the CODEC as the bus clock master, I2S */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret) { - pr_err("%s: failed set cpu dai format\n", __func__); - return ret; - } - - /* Set the CODEC as the bus clock master */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret) { - pr_err("%s: failed set codec dai format\n", __func__); - return ret; - } - ret = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); if (ret) { @@ -320,6 +302,8 @@ int simtec_audio_core_probe(struct platform_device *pdev, int ret; card->dai_link->ops = &simtec_snd_ops; + card->dai_link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; pdata = pdev->dev.platform_data; if (!pdata) { -- cgit v0.10.2 From 517b9a2a90676aeeefc7e2b8508fe4260e02c432 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:25 +0100 Subject: ASoC: s3c24xx_uda134x: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 9c6f7db..50849e1 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -173,16 +173,6 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk, SND_SOC_CLOCK_IN); if (ret < 0) @@ -223,6 +213,8 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .codec_name = "uda134x-codec", .codec_dai_name = "uda134x-hifi", .cpu_dai_name = "s3c24xx-iis", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &s3c24xx_uda134x_ops, .platform_name = "s3c24xx-iis", }; -- cgit v0.10.2 From 10756c2770d7f4758e36d2a9e37ff2637001d610 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:26 +0100 Subject: ASoC: smartq_wm8987: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index 9b0ffac..8291d2a 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -56,20 +56,6 @@ static int smartq_hifi_hw_params(struct snd_pcm_substream *substream, break; } - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - /* Use PCLK for I2S signal generation */ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); @@ -199,6 +185,8 @@ static struct snd_soc_dai_link smartq_dai[] = { .platform_name = "samsung-i2s.0", .codec_name = "wm8750.0-0x1a", .init = smartq_wm8987_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &smartq_hifi_ops, }, }; -- cgit v0.10.2 From 7a57ca2362a55c34b96d90539dd8b7cb6c1c09a1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:27 +0100 Subject: ASoC: smdk_wm8580: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index b1a519f..17a2f71 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -32,7 +32,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; unsigned int pll_out; int bfs, rfs, ret; @@ -77,20 +76,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, } pll_out = params_rate(params) * rfs; - /* Set the Codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* Set the AP DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - /* Set WM8580 to drive MCLK from its PLLA */ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, WM8580_CLKSRC_PLLA); @@ -168,6 +153,9 @@ enum { SEC_PLAYBACK, }; +#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBM_CFM) + static struct snd_soc_dai_link smdk_dai[] = { [PRI_PLAYBACK] = { /* Primary Playback i/f */ .name = "WM8580 PAIF RX", @@ -176,6 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8580-hifi-playback", .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", + .dai_fmt = SMDK_DAI_FMT, .ops = &smdk_ops, }, [PRI_CAPTURE] = { /* Primary Capture i/f */ @@ -185,6 +174,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8580-hifi-capture", .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", + .dai_fmt = SMDK_DAI_FMT, .init = smdk_wm8580_init_paiftx, .ops = &smdk_ops, }, @@ -195,6 +185,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8580-hifi-playback", .platform_name = "samsung-i2s-sec", .codec_name = "wm8580.0-001b", + .dai_fmt = SMDK_DAI_FMT, .ops = &smdk_ops, }, }; -- cgit v0.10.2 From 6a5794f2c653e78127123b3cd266b3c4d4c50606 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:28 +0100 Subject: ASoC: smdk_wm8570pcm: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c index 05c609c..6deec52 100644 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -62,20 +62,6 @@ static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream, rfs = mclk_freq / params_rate(params) / 2; - /* Set the codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B - | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* Set the cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B - | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - if (mclk_freq == xtal_freq) { ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK, mclk_freq, SND_SOC_CLOCK_IN); @@ -121,6 +107,9 @@ static struct snd_soc_ops smdk_wm8580_pcm_ops = { .hw_params = smdk_wm8580_pcm_hw_params, }; +#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \ + SND_SOC_DAIFMT_CBS_CFS) + static struct snd_soc_dai_link smdk_dai[] = { { .name = "WM8580 PAIF PCM RX", @@ -129,6 +118,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8580-hifi-playback", .platform_name = "samsung-audio", .codec_name = "wm8580.0-001b", + .dai_fmt = SMDK_DAI_FMT, .ops = &smdk_wm8580_pcm_ops, }, { .name = "WM8580 PAIF PCM TX", @@ -137,6 +127,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8580-hifi-capture", .platform_name = "samsung-pcm.0", .codec_name = "wm8580.0-001b", + .dai_fmt = SMDK_DAI_FMT, .ops = &smdk_wm8580_pcm_ops, }, }; -- cgit v0.10.2 From fce20bf879dd5ce309c593c91bbb7b5e6ffd22e7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:29 +0100 Subject: ASoC: smdk_wm8994pcm: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index c470e8e..b1c89ec 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -68,20 +68,6 @@ static int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream, mclk_freq = params_rate(params) * rfs; - /* Set the codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B - | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* Set the cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B - | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, mclk_freq, SND_SOC_CLOCK_IN); if (ret < 0) @@ -118,6 +104,8 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8994-aif1", .platform_name = "samsung-pcm.0", .codec_name = "wm8994-codec", + .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS, .ops = &smdk_wm8994_pcm_ops, }, }; -- cgit v0.10.2 From 9cb2a25ce68aec15d5d940f5d3040bd66ca688c7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 17:16:30 +0100 Subject: ASoC: migor: Use static DAI format setup Set the dai_fmt field in the dai_link struct instead of manually calling snd_soc_dai_fmt(). This makes the code cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c index c58c252..82f5823 100644 --- a/sound/soc/sh/migor.c +++ b/sound/soc/sh/migor.c @@ -63,16 +63,6 @@ static int migor_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - codec_freq = rate * 512; /* * This propagates the parent frequency change to children and @@ -144,6 +134,8 @@ static struct snd_soc_dai_link migor_dai = { .codec_dai_name = "wm8978-hifi", .platform_name = "siu-pcm-audio", .codec_name = "wm8978.0-001a", + .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBS_CFS, .ops = &migor_dai_ops, }; -- cgit v0.10.2 From 29104c748d52d579b291ca029f4714bca7765241 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Sat, 3 Jan 2015 17:04:44 +0800 Subject: spi: sirf: drop redundant sirf,marco-spi compatible string "sirf,marco-spi" is redundant as all SPI controllers in CSR SiRFSoC are compatible with prima2-spi. at the same time, the whole marco project was dropped and its replacement atlas7 is also compatible with prima2 in SPI. Signed-off-by: Barry Song Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index d075191..f5715c9 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -818,7 +818,6 @@ static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend, static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, - { .compatible = "sirf,marco-spi", }, {} }; MODULE_DEVICE_TABLE(of, spi_sirfsoc_of_match); -- cgit v0.10.2 From 7491831f4f034e2d76326518145da9525dd90932 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 6 Jan 2015 10:21:20 +0100 Subject: ASoC: atmel: sam9g20_wm8731: remove useless include A mach/ header is included but never used. Simply remove it. Signed-off-by: Alexandre Belloni Acked-by: Bo Shen Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 66b66d0..5317289 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -47,7 +47,6 @@ #include #include -#include #include "../codecs/wm8731.h" #include "atmel-pcm.h" -- cgit v0.10.2 From fcf6c5ea7abd42cfc2dde0ff0451b209951de9b4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Dec 2014 13:08:48 +0000 Subject: ASoC: dapm: Don't use async I/O The only user of the async I/O support in ASoC is SPI which was using it to avoid needless context thrashing and minimise controller runtime PM bounces. The SPI framework has now been enhanced so that even normal spi_sync() calls won't suffer these effects so we don't need to handle this in ASoC and in fact it can be more efficient not to since we don't need to set up and tear down the buffers needed to manage asynchronous I/O. The async completions that DAPM does are left in place so drivers can use them, they are very cheap if there is no asynchronous work queued. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ea49684..0be3ca5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -517,8 +517,8 @@ static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm, { if (!dapm->component) return -EIO; - return snd_soc_component_update_bits_async(dapm->component, reg, - mask, value); + return snd_soc_component_update_bits(dapm->component, reg, + mask, value); } static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm, -- cgit v0.10.2 From fce091ee0a7f25108c7ab3eb06b9e436b7aeac11 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 19 Dec 2014 14:55:21 +0100 Subject: ASoC: samsung: i2s: Remove unused gpios field from struct i2s The 'gpios' field in 'struct i2s' is now unused, this change seems to be missing in commit 0429ffeff460c4302bd1520e6 ("ASoC: samsung: Remove obsolete GPIO based DT pinmuxing"). Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b5a80c5..86491c9 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -95,7 +95,6 @@ struct i2s_dai { u32 suspend_i2smod; u32 suspend_i2scon; u32 suspend_i2spsr; - unsigned long gpios[7]; /* i2s gpio line numbers */ const struct samsung_i2s_variant_regs *variant_regs; }; -- cgit v0.10.2 From 84596ccbf102644c846e050caf4714447f083206 Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 11 Nov 2014 12:03:26 +0800 Subject: documentation: Update sysfs path for rcu_cpu_stall_timeout Commit 6bfc09e2327d ("rcu: Provide RCU CPU stall warnings for tiny RCU") moved the rcu_cpu_stall_timeout module parameter from rcutree.c to rcupdate.c, but failed to update Documentation/RCU/stallwarn.txt. This commit therefore repairs this omission. commit 96224daa16d6 ("documentation: Update sysfs path for rcu_cpu_stall_suppress") updated the path for rcu_cpu_stall_suppress, but failed to update for rcu_cpu_stall_timeout. Signed-off-by: Xie XiuQi Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index ed186a9..4f8e339 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -15,7 +15,7 @@ CONFIG_RCU_CPU_STALL_TIMEOUT 21 seconds. This configuration parameter may be changed at runtime via the - /sys/module/rcutree/parameters/rcu_cpu_stall_timeout, however + /sys/module/rcupdate/parameters/rcu_cpu_stall_timeout, however this parameter is checked only at the beginning of a cycle. So if you are 10 seconds into a 40-second stall, setting this sysfs parameter to (say) five will shorten the timeout for the -- cgit v0.10.2 From 536fa402221f09633e7c5801b327055ab716a363 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 5 Sep 2014 11:14:48 -0700 Subject: compiler: Allow 1- and 2-byte smp_load_acquire() and smp_store_release() CPUs without single-byte and double-byte loads and stores place some "interesting" requirements on concurrent code. For example (adapted from Peter Hurley's test code), suppose we have the following structure: struct foo { spinlock_t lock1; spinlock_t lock2; char a; /* Protected by lock1. */ char b; /* Protected by lock2. */ }; struct foo *foop; Of course, it is common (and good) practice to place data protected by different locks in separate cache lines. However, if the locks are rarely acquired (for example, only in rare error cases), and there are a great many instances of the data structure, then memory footprint can trump false-sharing concerns, so that it can be better to place them in the same cache cache line as above. But if the CPU does not support single-byte loads and stores, a store to foop->a will do a non-atomic read-modify-write operation on foop->b, which will come as a nasty surprise to someone holding foop->lock2. So we now require CPUs to support single-byte and double-byte loads and stores. Therefore, this commit adjusts the definition of __native_word() to allow these sizes to be used by smp_load_acquire() and smp_store_release(). Signed-off-by: Paul E. McKenney Cc: Peter Zijlstra diff --git a/include/linux/compiler.h b/include/linux/compiler.h index a1c81f8..49811cd 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -385,7 +385,7 @@ static __always_inline void __assign_once_size(volatile void *p, void *res, int /* Is this type a native word size -- useful for atomic operations */ #ifndef __native_word -# define __native_word(t) (sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) +# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) #endif /* Compile time object size, -1 for unknown */ -- cgit v0.10.2 From ac59853c06993a442e8060bc19040b2ca3025aec Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 13 Nov 2014 14:24:14 -0500 Subject: rcupdate: Replace smp_read_barrier_depends() with lockless_dereference() Recently lockless_dereference() was added which can be used in place of hard-coding smp_read_barrier_depends(). The following PATCH makes the change. Signed-off-by: Pranith Kumar Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index ed4f593..386ba28 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -582,11 +582,11 @@ static inline void rcu_preempt_sleep_check(void) }) #define __rcu_dereference_check(p, c, space) \ ({ \ - typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \ + /* Dependency order vs. p above. */ \ + typeof(*p) *________p1 = (typeof(*p) *__force)lockless_dereference(p); \ rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \ rcu_dereference_sparse(p, space); \ - smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ - ((typeof(*p) __force __kernel *)(_________p1)); \ + ((typeof(*p) __force __kernel *)(________p1)); \ }) #define __rcu_dereference_protected(p, c, space) \ ({ \ @@ -603,10 +603,10 @@ static inline void rcu_preempt_sleep_check(void) }) #define __rcu_dereference_index_check(p, c) \ ({ \ - typeof(p) _________p1 = ACCESS_ONCE(p); \ + /* Dependency order vs. p above. */ \ + typeof(p) _________p1 = lockless_dereference(p); \ rcu_lockdep_assert(c, \ "suspicious rcu_dereference_index_check() usage"); \ - smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ (_________p1); \ }) -- cgit v0.10.2 From 5f6130fa52ee0df0b1da4518c5bbef42bcfe7d83 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 9 Dec 2014 17:53:34 +0800 Subject: tiny_rcu: Directly force QS when call_rcu_[bh|sched]() on idle_task For RCU in UP, context-switch = QS = GP, thus we can force a context-switch when any call_rcu_[bh|sched]() is happened on idle_task. After doing so, rcu_idle/irq_enter/exit() are useless, so we can simply make these functions empty. More important, this change does not change the functionality logically. Note: raise_softirq(RCU_SOFTIRQ)/rcu_sched_qs() in rcu_idle_enter() and outmost rcu_irq_exit() will have to wake up the ksoftirqd (due to in_interrupt() == 0). Before this patch After this patch: call_rcu_sched() in idle; call_rcu_sched() in idle set resched do other stuffs; do other stuffs outmost rcu_irq_exit() outmost rcu_irq_exit() (empty function) (or rcu_idle_enter()) (or rcu_idle_enter(), also empty function) start to resched. (see above) rcu_sched_qs() rcu_sched_qs() QS,and GP and advance cb QS,and GP and advance cb wake up the ksoftirqd wake up the ksoftirqd set resched resched to ksoftirqd (or other) resched to ksoftirqd (or other) These two code patches are almost the same. Size changed after patched: size kernel/rcu/tiny-old.o kernel/rcu/tiny-patched.o text data bss dec hex filename 3449 206 8 3663 e4f kernel/rcu/tiny-old.o 2406 144 8 2558 9fe kernel/rcu/tiny-patched.o Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index 07bb02e..80adef7 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -137,4 +137,10 @@ int rcu_jiffies_till_stall_check(void); void rcu_early_boot_tests(void); +/* + * This function really isn't for public consumption, but RCU is special in + * that context switches can allow the state machine to make progress. + */ +extern void resched_cpu(int cpu); + #endif /* __LINUX_RCU_H */ diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 805b6d5..85287ec 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -47,54 +47,14 @@ static void __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), struct rcu_ctrlblk *rcp); -static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; - #include "tiny_plugin.h" -/* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcu/tree.c. */ -static void rcu_idle_enter_common(long long newval) -{ - if (newval) { - RCU_TRACE(trace_rcu_dyntick(TPS("--="), - rcu_dynticks_nesting, newval)); - rcu_dynticks_nesting = newval; - return; - } - RCU_TRACE(trace_rcu_dyntick(TPS("Start"), - rcu_dynticks_nesting, newval)); - if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) { - struct task_struct *idle __maybe_unused = idle_task(smp_processor_id()); - - RCU_TRACE(trace_rcu_dyntick(TPS("Entry error: not idle task"), - rcu_dynticks_nesting, newval)); - ftrace_dump(DUMP_ALL); - WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s", - current->pid, current->comm, - idle->pid, idle->comm); /* must be idle task! */ - } - rcu_sched_qs(); /* implies rcu_bh_inc() */ - barrier(); - rcu_dynticks_nesting = newval; -} - /* * Enter idle, which is an extended quiescent state if we have fully - * entered that mode (i.e., if the new value of dynticks_nesting is zero). + * entered that mode. */ void rcu_idle_enter(void) { - unsigned long flags; - long long newval; - - local_irq_save(flags); - WARN_ON_ONCE((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == 0); - if ((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == - DYNTICK_TASK_NEST_VALUE) - newval = 0; - else - newval = rcu_dynticks_nesting - DYNTICK_TASK_NEST_VALUE; - rcu_idle_enter_common(newval); - local_irq_restore(flags); } EXPORT_SYMBOL_GPL(rcu_idle_enter); @@ -103,55 +63,14 @@ EXPORT_SYMBOL_GPL(rcu_idle_enter); */ void rcu_irq_exit(void) { - unsigned long flags; - long long newval; - - local_irq_save(flags); - newval = rcu_dynticks_nesting - 1; - WARN_ON_ONCE(newval < 0); - rcu_idle_enter_common(newval); - local_irq_restore(flags); } EXPORT_SYMBOL_GPL(rcu_irq_exit); -/* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcu/tree.c. */ -static void rcu_idle_exit_common(long long oldval) -{ - if (oldval) { - RCU_TRACE(trace_rcu_dyntick(TPS("++="), - oldval, rcu_dynticks_nesting)); - return; - } - RCU_TRACE(trace_rcu_dyntick(TPS("End"), oldval, rcu_dynticks_nesting)); - if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) { - struct task_struct *idle __maybe_unused = idle_task(smp_processor_id()); - - RCU_TRACE(trace_rcu_dyntick(TPS("Exit error: not idle task"), - oldval, rcu_dynticks_nesting)); - ftrace_dump(DUMP_ALL); - WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s", - current->pid, current->comm, - idle->pid, idle->comm); /* must be idle task! */ - } -} - /* * Exit idle, so that we are no longer in an extended quiescent state. */ void rcu_idle_exit(void) { - unsigned long flags; - long long oldval; - - local_irq_save(flags); - oldval = rcu_dynticks_nesting; - WARN_ON_ONCE(rcu_dynticks_nesting < 0); - if (rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) - rcu_dynticks_nesting += DYNTICK_TASK_NEST_VALUE; - else - rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; - rcu_idle_exit_common(oldval); - local_irq_restore(flags); } EXPORT_SYMBOL_GPL(rcu_idle_exit); @@ -160,15 +79,6 @@ EXPORT_SYMBOL_GPL(rcu_idle_exit); */ void rcu_irq_enter(void) { - unsigned long flags; - long long oldval; - - local_irq_save(flags); - oldval = rcu_dynticks_nesting; - rcu_dynticks_nesting++; - WARN_ON_ONCE(rcu_dynticks_nesting == 0); - rcu_idle_exit_common(oldval); - local_irq_restore(flags); } EXPORT_SYMBOL_GPL(rcu_irq_enter); @@ -179,7 +89,7 @@ EXPORT_SYMBOL_GPL(rcu_irq_enter); */ bool notrace __rcu_is_watching(void) { - return rcu_dynticks_nesting; + return true; } EXPORT_SYMBOL(__rcu_is_watching); @@ -347,6 +257,11 @@ static void __call_rcu(struct rcu_head *head, rcp->curtail = &head->next; RCU_TRACE(rcp->qlen++); local_irq_restore(flags); + + if (unlikely(is_idle_task(current))) { + /* force scheduling for rcu_sched_qs() */ + resched_cpu(0); + } } /* diff --git a/kernel/rcu/tiny_plugin.h b/kernel/rcu/tiny_plugin.h index 858c565..b5fc5e5 100644 --- a/kernel/rcu/tiny_plugin.h +++ b/kernel/rcu/tiny_plugin.h @@ -147,7 +147,7 @@ static void check_cpu_stall(struct rcu_ctrlblk *rcp) js = ACCESS_ONCE(rcp->jiffies_stall); if (*rcp->curtail && ULONG_CMP_GE(j, js)) { pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n", - rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting, + rcp->name, rcp->ticks_this_gp, DYNTICK_TASK_EXIT_IDLE, jiffies - rcp->gp_start, rcp->qlen); dump_stack(); } diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 9c25b99..203b50d 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -935,12 +935,6 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp, } /* - * This function really isn't for public consumption, but RCU is special in - * that context switches can allow the state machine to make progress. - */ -extern void resched_cpu(int cpu); - -/* * Return true if the specified CPU has passed through a quiescent * state by virtue of being in or having passed through an dynticks * idle state since the last call to dyntick_save_progress_counter() -- cgit v0.10.2 From f520c98e3e5212d8c282a86d9b7697dd70326192 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Fri, 12 Dec 2014 09:36:14 +0800 Subject: rculist: Fix sparse warning This fixes the following sparse warnings: make C=1 CF=-D__CHECK_ENDIAN__ net/ipv6/addrconf.o net/ipv6/addrconf.c:3495:9: error: incompatible types in comparison expression (different address spaces) net/ipv6/addrconf.c:3495:9: error: incompatible types in comparison expression (different address spaces) net/ipv6/addrconf.c:3495:9: error: incompatible types in comparison expression (different address spaces) net/ipv6/addrconf.c:3495:9: error: incompatible types in comparison expression (different address spaces) To silence these spare complaints, an RCU annotation should be added to "next" pointer of hlist_node structure through hlist_next_rcu() macro when iterating over a hlist with hlist_for_each_entry_continue_rcu_bh(). By the way, this commit also resolves the same error appearing in hlist_for_each_entry_continue_rcu(). Signed-off-by: Ying Xue Signed-off-by: Paul E. McKenney diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 529bc94..a18b16f 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -524,11 +524,11 @@ static inline void hlist_add_behind_rcu(struct hlist_node *n, * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue_rcu(pos, member) \ - for (pos = hlist_entry_safe(rcu_dereference((pos)->member.next),\ - typeof(*(pos)), member); \ + for (pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member); \ pos; \ - pos = hlist_entry_safe(rcu_dereference((pos)->member.next),\ - typeof(*(pos)), member)) + pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member)) /** * hlist_for_each_entry_continue_rcu_bh - iterate over a hlist continuing after current point @@ -536,11 +536,11 @@ static inline void hlist_add_behind_rcu(struct hlist_node *n, * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue_rcu_bh(pos, member) \ - for (pos = hlist_entry_safe(rcu_dereference_bh((pos)->member.next),\ - typeof(*(pos)), member); \ + for (pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member); \ pos; \ - pos = hlist_entry_safe(rcu_dereference_bh((pos)->member.next),\ - typeof(*(pos)), member)) + pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member)) /** * hlist_for_each_entry_from_rcu - iterate over a hlist continuing from current point -- cgit v0.10.2 From 87af9e7ff9d909e70a006ca0974466e2a1d8db0a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 12 Dec 2014 10:11:44 +0100 Subject: hotplugcpu: Avoid deadlocks by waking active_writer Commit b2c4623dcd07 ("rcu: More on deadlock between CPU hotplug and expedited grace periods") introduced another problem that can easily be reproduced by starting/stopping cpus in a loop. E.g.: for i in `seq 5000`; do echo 1 > /sys/devices/system/cpu/cpu1/online echo 0 > /sys/devices/system/cpu/cpu1/online done Will result in: INFO: task /cpu_start_stop:1 blocked for more than 120 seconds. Call Trace: ([<00000000006a028e>] __schedule+0x406/0x91c) [<0000000000130f60>] cpu_hotplug_begin+0xd0/0xd4 [<0000000000130ff6>] _cpu_up+0x3e/0x1c4 [<0000000000131232>] cpu_up+0xb6/0xd4 [<00000000004a5720>] device_online+0x80/0xc0 [<00000000004a57f0>] online_store+0x90/0xb0 ... And a deadlock. Problem is that if the last ref in put_online_cpus() can't get the cpu_hotplug.lock the puts_pending count is incremented, but a sleeping active_writer might never be woken up, therefore never exiting the loop in cpu_hotplug_begin(). This fix removes puts_pending and turns refcount into an atomic variable. We also introduce a wait queue for the active_writer, to avoid possible races and use-after-free. There is no need to take the lock in put_online_cpus() anymore. Can't reproduce it with this fix. Signed-off-by: David Hildenbrand Signed-off-by: Paul E. McKenney diff --git a/kernel/cpu.c b/kernel/cpu.c index 5d22023..1972b16 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -58,22 +58,23 @@ static int cpu_hotplug_disabled; static struct { struct task_struct *active_writer; - struct mutex lock; /* Synchronizes accesses to refcount, */ + /* wait queue to wake up the active_writer */ + wait_queue_head_t wq; + /* verifies that no writer will get active while readers are active */ + struct mutex lock; /* * Also blocks the new readers during * an ongoing cpu hotplug operation. */ - int refcount; - /* And allows lockless put_online_cpus(). */ - atomic_t puts_pending; + atomic_t refcount; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif } cpu_hotplug = { .active_writer = NULL, + .wq = __WAIT_QUEUE_HEAD_INITIALIZER(cpu_hotplug.wq), .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock), - .refcount = 0, #ifdef CONFIG_DEBUG_LOCK_ALLOC .dep_map = {.name = "cpu_hotplug.lock" }, #endif @@ -86,15 +87,6 @@ static struct { #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) -static void apply_puts_pending(int max) -{ - int delta; - - if (atomic_read(&cpu_hotplug.puts_pending) >= max) { - delta = atomic_xchg(&cpu_hotplug.puts_pending, 0); - cpu_hotplug.refcount -= delta; - } -} void get_online_cpus(void) { @@ -103,8 +95,7 @@ void get_online_cpus(void) return; cpuhp_lock_acquire_read(); mutex_lock(&cpu_hotplug.lock); - apply_puts_pending(65536); - cpu_hotplug.refcount++; + atomic_inc(&cpu_hotplug.refcount); mutex_unlock(&cpu_hotplug.lock); } EXPORT_SYMBOL_GPL(get_online_cpus); @@ -116,8 +107,7 @@ bool try_get_online_cpus(void) if (!mutex_trylock(&cpu_hotplug.lock)) return false; cpuhp_lock_acquire_tryread(); - apply_puts_pending(65536); - cpu_hotplug.refcount++; + atomic_inc(&cpu_hotplug.refcount); mutex_unlock(&cpu_hotplug.lock); return true; } @@ -125,20 +115,18 @@ EXPORT_SYMBOL_GPL(try_get_online_cpus); void put_online_cpus(void) { + int refcount; + if (cpu_hotplug.active_writer == current) return; - if (!mutex_trylock(&cpu_hotplug.lock)) { - atomic_inc(&cpu_hotplug.puts_pending); - cpuhp_lock_release(); - return; - } - if (WARN_ON(!cpu_hotplug.refcount)) - cpu_hotplug.refcount++; /* try to fix things up */ + refcount = atomic_dec_return(&cpu_hotplug.refcount); + if (WARN_ON(refcount < 0)) /* try to fix things up */ + atomic_inc(&cpu_hotplug.refcount); + + if (refcount <= 0 && waitqueue_active(&cpu_hotplug.wq)) + wake_up(&cpu_hotplug.wq); - if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer)) - wake_up_process(cpu_hotplug.active_writer); - mutex_unlock(&cpu_hotplug.lock); cpuhp_lock_release(); } @@ -168,18 +156,20 @@ EXPORT_SYMBOL_GPL(put_online_cpus); */ void cpu_hotplug_begin(void) { - cpu_hotplug.active_writer = current; + DEFINE_WAIT(wait); + cpu_hotplug.active_writer = current; cpuhp_lock_acquire(); + for (;;) { mutex_lock(&cpu_hotplug.lock); - apply_puts_pending(1); - if (likely(!cpu_hotplug.refcount)) - break; - __set_current_state(TASK_UNINTERRUPTIBLE); + prepare_to_wait(&cpu_hotplug.wq, &wait, TASK_UNINTERRUPTIBLE); + if (likely(!atomic_read(&cpu_hotplug.refcount))) + break; mutex_unlock(&cpu_hotplug.lock); schedule(); } + finish_wait(&cpu_hotplug.wq, &wait); } void cpu_hotplug_done(void) -- cgit v0.10.2 From 41050a009640f9f330a5b916563ca7faf853a98c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 18 Dec 2014 12:31:27 -0800 Subject: rcu: Fix rcu_barrier() race that could result in too-short wait The rcu_barrier() no-callbacks check for no-CBs CPUs has race conditions. It checks a given CPU's lists of callbacks, and if all three no-CBs lists are empty, ignores that CPU. However, these three lists could potentially be empty even when callbacks are present if the check executed just as the callbacks were being moved from one list to another. It turns out that recent versions of rcutorture can spot this race. This commit plugs this hole by consolidating the per-list counts of no-CBs callbacks into a single count, which is incremented before the corresponding callback is posted and after it is invoked. Then rcu_barrier() checks this single count to reliably determine whether the corresponding CPU has no-CBs callbacks. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 203b50d..5b9f3b9 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3344,6 +3344,7 @@ static void _rcu_barrier(struct rcu_state *rsp) } else { _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, rsp->n_barrier_done); + smp_mb__before_atomic(); atomic_inc(&rsp->barrier_cpu_count); __call_rcu(&rdp->barrier_head, rcu_barrier_callback, rsp, cpu, 0); diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 8e7b184..cb59086 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -340,14 +340,10 @@ struct rcu_data { #ifdef CONFIG_RCU_NOCB_CPU struct rcu_head *nocb_head; /* CBs waiting for kthread. */ struct rcu_head **nocb_tail; - atomic_long_t nocb_q_count; /* # CBs waiting for kthread */ - atomic_long_t nocb_q_count_lazy; /* (approximate). */ + atomic_long_t nocb_q_count; /* # CBs waiting for nocb */ + atomic_long_t nocb_q_count_lazy; /* invocation (all stages). */ struct rcu_head *nocb_follower_head; /* CBs ready to invoke. */ struct rcu_head **nocb_follower_tail; - atomic_long_t nocb_follower_count; /* # CBs ready to invoke. */ - atomic_long_t nocb_follower_count_lazy; /* (approximate). */ - int nocb_p_count; /* # CBs being invoked by kthread */ - int nocb_p_count_lazy; /* (approximate). */ wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */ struct task_struct *nocb_kthread; int nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */ @@ -356,8 +352,6 @@ struct rcu_data { struct rcu_head *nocb_gp_head ____cacheline_internodealigned_in_smp; /* CBs waiting for GP. */ struct rcu_head **nocb_gp_tail; - long nocb_gp_count; - long nocb_gp_count_lazy; bool nocb_leader_sleep; /* Is the nocb leader thread asleep? */ struct rcu_data *nocb_next_follower; /* Next follower in wakeup chain. */ @@ -622,24 +616,15 @@ static void rcu_dynticks_task_exit(void); #endif /* #ifndef RCU_TREE_NONCORE */ #ifdef CONFIG_RCU_TRACE -#ifdef CONFIG_RCU_NOCB_CPU -/* Sum up queue lengths for tracing. */ +/* Read out queue lengths for tracing. */ static inline void rcu_nocb_q_lengths(struct rcu_data *rdp, long *ql, long *qll) { - *ql = atomic_long_read(&rdp->nocb_q_count) + - rdp->nocb_p_count + - atomic_long_read(&rdp->nocb_follower_count) + - rdp->nocb_p_count + rdp->nocb_gp_count; - *qll = atomic_long_read(&rdp->nocb_q_count_lazy) + - rdp->nocb_p_count_lazy + - atomic_long_read(&rdp->nocb_follower_count_lazy) + - rdp->nocb_p_count_lazy + rdp->nocb_gp_count_lazy; -} +#ifdef CONFIG_RCU_NOCB_CPU + *ql = atomic_long_read(&rdp->nocb_q_count); + *qll = atomic_long_read(&rdp->nocb_q_count_lazy); #else /* #ifdef CONFIG_RCU_NOCB_CPU */ -static inline void rcu_nocb_q_lengths(struct rcu_data *rdp, long *ql, long *qll) -{ *ql = 0; *qll = 0; -} #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ +} #endif /* #ifdef CONFIG_RCU_TRACE */ diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 3ec85cb..e5c43b7 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -2056,9 +2056,26 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force) static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu) { struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); + unsigned long ret; +#ifdef CONFIG_PROVE_RCU struct rcu_head *rhp; +#endif /* #ifdef CONFIG_PROVE_RCU */ + + /* + * Check count of all no-CBs callbacks awaiting invocation. + * There needs to be a barrier before this function is called, + * but associated with a prior determination that no more + * callbacks would be posted. In the worst case, the first + * barrier in _rcu_barrier() suffices (but the caller cannot + * necessarily rely on this, not a substitute for the caller + * getting the concurrency design right!). There must also be + * a barrier between the following load an posting of a callback + * (if a callback is in fact needed). This is associated with an + * atomic_inc() in the caller. + */ + ret = atomic_long_read(&rdp->nocb_q_count); - /* No-CBs CPUs might have callbacks on any of three lists. */ +#ifdef CONFIG_PROVE_RCU rhp = ACCESS_ONCE(rdp->nocb_head); if (!rhp) rhp = ACCESS_ONCE(rdp->nocb_gp_head); @@ -2072,8 +2089,9 @@ static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu) cpu, rhp->func); WARN_ON_ONCE(1); } +#endif /* #ifdef CONFIG_PROVE_RCU */ - return !!rhp; + return !!ret; } /* @@ -2095,9 +2113,10 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, struct task_struct *t; /* Enqueue the callback on the nocb list and update counts. */ + atomic_long_add(rhcount, &rdp->nocb_q_count); + /* rcu_barrier() relies on ->nocb_q_count add before xchg. */ old_rhpp = xchg(&rdp->nocb_tail, rhtp); ACCESS_ONCE(*old_rhpp) = rhp; - atomic_long_add(rhcount, &rdp->nocb_q_count); atomic_long_add(rhcount_lazy, &rdp->nocb_q_count_lazy); smp_mb__after_atomic(); /* Store *old_rhpp before _wake test. */ @@ -2288,9 +2307,6 @@ wait_again: /* Move callbacks to wait-for-GP list, which is empty. */ ACCESS_ONCE(rdp->nocb_head) = NULL; rdp->nocb_gp_tail = xchg(&rdp->nocb_tail, &rdp->nocb_head); - rdp->nocb_gp_count = atomic_long_xchg(&rdp->nocb_q_count, 0); - rdp->nocb_gp_count_lazy = - atomic_long_xchg(&rdp->nocb_q_count_lazy, 0); gotcbs = true; } @@ -2338,9 +2354,6 @@ wait_again: /* Append callbacks to follower's "done" list. */ tail = xchg(&rdp->nocb_follower_tail, rdp->nocb_gp_tail); *tail = rdp->nocb_gp_head; - atomic_long_add(rdp->nocb_gp_count, &rdp->nocb_follower_count); - atomic_long_add(rdp->nocb_gp_count_lazy, - &rdp->nocb_follower_count_lazy); smp_mb__after_atomic(); /* Store *tail before wakeup. */ if (rdp != my_rdp && tail == &rdp->nocb_follower_head) { /* @@ -2415,13 +2428,11 @@ static int rcu_nocb_kthread(void *arg) trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, "WokeNonEmpty"); ACCESS_ONCE(rdp->nocb_follower_head) = NULL; tail = xchg(&rdp->nocb_follower_tail, &rdp->nocb_follower_head); - c = atomic_long_xchg(&rdp->nocb_follower_count, 0); - cl = atomic_long_xchg(&rdp->nocb_follower_count_lazy, 0); - rdp->nocb_p_count += c; - rdp->nocb_p_count_lazy += cl; /* Each pass through the following loop invokes a callback. */ - trace_rcu_batch_start(rdp->rsp->name, cl, c, -1); + trace_rcu_batch_start(rdp->rsp->name, + atomic_long_read(&rdp->nocb_q_count_lazy), + atomic_long_read(&rdp->nocb_q_count), -1); c = cl = 0; while (list) { next = list->next; @@ -2443,9 +2454,9 @@ static int rcu_nocb_kthread(void *arg) list = next; } trace_rcu_batch_end(rdp->rsp->name, c, !!list, 0, 0, 1); - ACCESS_ONCE(rdp->nocb_p_count) = rdp->nocb_p_count - c; - ACCESS_ONCE(rdp->nocb_p_count_lazy) = - rdp->nocb_p_count_lazy - cl; + smp_mb__before_atomic(); /* _add after CB invocation. */ + atomic_long_add(-c, &rdp->nocb_q_count); + atomic_long_add(-cl, &rdp->nocb_q_count_lazy); rdp->n_nocbs_invoked += c; } return 0; -- cgit v0.10.2 From 5a43b88e98eaca88fa12abcacd0000adc879dd2c Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Wed, 24 Dec 2014 17:55:28 +0800 Subject: rcu: Remove "select IRQ_WORK" from config TREE_RCU The 48a7639ce80c ("rcu: Make callers awaken grace-period kthread") removed the irq_work_queue(), so the TREE_RCU doesn't need irq work any more. This commit therefore updates RCU's Kconfig and Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney diff --git a/init/Kconfig b/init/Kconfig index 9afb971..39b4313 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -470,7 +470,6 @@ choice config TREE_RCU bool "Tree-based hierarchical RCU" depends on !PREEMPT && SMP - select IRQ_WORK help This option selects the RCU implementation that is designed for very large SMP system with hundreds or @@ -480,7 +479,6 @@ config TREE_RCU config PREEMPT_RCU bool "Preemptible tree-based hierarchical RCU" depends on PREEMPT - select IRQ_WORK help This option selects the RCU implementation that is designed for very large SMP systems with hundreds or diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index cb59086..41860b9 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -27,7 +27,6 @@ #include #include #include -#include /* * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and -- cgit v0.10.2 From b08ea27d95bcaee6d9cf4edd64f373006661424a Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 29 Oct 2014 15:39:39 -0700 Subject: rcu: Protect rcu_boost() lockless accesses with ACCESS_ONCE() This commit prevents random compiler optimizations by applying ACCESS_ONCE() to lockless accesses. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 3ec85cb..d59913e 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1127,7 +1127,8 @@ static int rcu_boost(struct rcu_node *rnp) struct task_struct *t; struct list_head *tb; - if (rnp->exp_tasks == NULL && rnp->boost_tasks == NULL) + if (ACCESS_ONCE(rnp->exp_tasks) == NULL && + ACCESS_ONCE(rnp->boost_tasks) == NULL) return 0; /* Nothing left to boost. */ raw_spin_lock_irqsave(&rnp->lock, flags); -- cgit v0.10.2 From 74e871ac6cb17f67cbefb569d98a8d05de666e07 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Oct 2014 21:08:53 -0700 Subject: rcu: Rename "empty" to "empty_norm" in preparation for boost rework This commit undertakes a simple variable renaming to make way for some rework of RCU priority boosting. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index d59913e..3d22f0b 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -313,8 +313,8 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t, */ void rcu_read_unlock_special(struct task_struct *t) { - int empty; int empty_exp; + int empty_norm; int empty_exp_now; unsigned long flags; struct list_head *np; @@ -367,7 +367,7 @@ void rcu_read_unlock_special(struct task_struct *t) break; raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ } - empty = !rcu_preempt_blocked_readers_cgp(rnp); + empty_norm = !rcu_preempt_blocked_readers_cgp(rnp); empty_exp = !rcu_preempted_readers_exp(rnp); smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ np = rcu_next_node_entry(t, rnp); @@ -393,7 +393,7 @@ void rcu_read_unlock_special(struct task_struct *t) * so we must take a snapshot of the expedited state. */ empty_exp_now = !rcu_preempted_readers_exp(rnp); - if (!empty && !rcu_preempt_blocked_readers_cgp(rnp)) { + if (!empty_norm && !rcu_preempt_blocked_readers_cgp(rnp)) { trace_rcu_quiescent_state_report(TPS("preempt_rcu"), rnp->gpnum, 0, rnp->qsmask, -- cgit v0.10.2 From 8af3a5e78cfb63abe8813743946b7bd5a8a3134c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Oct 2014 11:22:37 -0700 Subject: rcu: Abstract rcu_cleanup_dead_rnp() from rcu_cleanup_dead_cpu() This commit abstracts rcu_cleanup_dead_rnp() from rcu_cleanup_dead_cpu() in preparation for the rework of RCU priority boosting. This new function will be invoked from rcu_read_unlock_special() in the reworked scheme, which is why rcu_cleanup_dead_rnp() assumes that the leaf rcu_node structure's ->qsmaskinit field has already been updated. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 4c106fc..75c6b33 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2227,6 +2227,46 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp) } /* + * All CPUs for the specified rcu_node structure have gone offline, + * and all tasks that were preempted within an RCU read-side critical + * section while running on one of those CPUs have since exited their RCU + * read-side critical section. Some other CPU is reporting this fact with + * the specified rcu_node structure's ->lock held and interrupts disabled. + * This function therefore goes up the tree of rcu_node structures, + * clearing the corresponding bits in the ->qsmaskinit fields. Note that + * the leaf rcu_node structure's ->qsmaskinit field has already been + * updated + * + * This function does check that the specified rcu_node structure has + * all CPUs offline and no blocked tasks, so it is OK to invoke it + * prematurely. That said, invoking it after the fact will cost you + * a needless lock acquisition. So once it has done its work, don't + * invoke it again. + */ +static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf) +{ + long mask; + struct rcu_node *rnp = rnp_leaf; + + if (rnp->qsmaskinit || rcu_preempt_has_tasks(rnp)) + return; + for (;;) { + mask = rnp->grpmask; + rnp = rnp->parent; + if (!rnp) + break; + raw_spin_lock(&rnp->lock); /* irqs already disabled. */ + smp_mb__after_unlock_lock(); /* GP memory ordering. */ + rnp->qsmaskinit &= ~mask; + if (rnp->qsmaskinit) { + raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ + return; + } + raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ + } +} + +/* * The CPU has been completely removed, and some other CPU is reporting * this fact from process context. Do the remainder of the cleanup, * including orphaning the outgoing CPU's RCU callbacks, and also @@ -2236,7 +2276,6 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp) static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) { unsigned long flags; - unsigned long mask; int need_report = 0; struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_node *rnp = rdp->mynode; /* Outgoing CPU's rdp & rnp. */ @@ -2252,24 +2291,14 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) rcu_send_cbs_to_orphanage(cpu, rsp, rnp, rdp); rcu_adopt_orphan_cbs(rsp, flags); - /* Remove the outgoing CPU from the masks in the rcu_node hierarchy. */ - mask = rdp->grpmask; /* rnp->grplo is constant. */ - do { - raw_spin_lock(&rnp->lock); /* irqs already disabled. */ - smp_mb__after_unlock_lock(); - rnp->qsmaskinit &= ~mask; - if (rnp->qsmaskinit != 0) { - if (rnp != rdp->mynode) - raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ - break; - } - if (rnp == rdp->mynode) - need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp); - else - raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ - mask = rnp->grpmask; - rnp = rnp->parent; - } while (rnp != NULL); + /* Remove outgoing CPU from mask in the leaf rcu_node structure. */ + raw_spin_lock(&rnp->lock); /* irqs already disabled. */ + smp_mb__after_unlock_lock(); /* Enforce GP memory-order guarantee. */ + rnp->qsmaskinit &= ~rdp->grpmask; + if (rnp->qsmaskinit == 0) { + need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp); + rcu_cleanup_dead_rnp(rnp); + } /* * We still hold the leaf rcu_node structure lock here, and diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 8e7b184..9315477 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -552,6 +552,7 @@ static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags); +static bool rcu_preempt_has_tasks(struct rcu_node *rnp); #endif /* #ifdef CONFIG_HOTPLUG_CPU */ static void rcu_print_detail_task_stall(struct rcu_state *rsp); static int rcu_print_task_stall(struct rcu_node *rnp); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 3d22f0b..d044b9c 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -307,6 +307,15 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t, } /* + * Return true if the specified rcu_node structure has tasks that were + * preempted within an RCU read-side critical section. + */ +static bool rcu_preempt_has_tasks(struct rcu_node *rnp) +{ + return !list_empty(&rnp->blkd_tasks); +} + +/* * Handle special cases during rcu_read_unlock(), such as needing to * notify RCU core processing or task having blocked during the RCU * read-side critical section. @@ -967,6 +976,14 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) raw_spin_unlock_irqrestore(&rnp->lock, flags); } +/* + * Because there is no preemptible RCU, there can be no readers blocked. + */ +static bool rcu_preempt_has_tasks(struct rcu_node *rnp) +{ + return false; +} + #endif /* #ifdef CONFIG_HOTPLUG_CPU */ /* -- cgit v0.10.2 From b6a932d1d9840727eee619d455bdeeedaa205be9 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Oct 2014 12:05:04 -0700 Subject: rcu: Make rcu_read_unlock_special() propagate ->qsmaskinit bit clearing This commit causes rcu_read_unlock_special() to propagate ->qsmaskinit bit clearing up the rcu_node tree once a given rcu_node structure's blkd_tasks list becomes empty. This is the final commit in preparation for the rework of RCU priority boosting: It enables preempted tasks to remain queued on their rcu_node structure even after all of that rcu_node structure's CPUs have gone offline. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 75c6b33..6625a1b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2329,6 +2329,10 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp) { } +static void __maybe_unused rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf) +{ +} + static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) { } diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index d044b9c..8a2b841 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -322,9 +322,10 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp) */ void rcu_read_unlock_special(struct task_struct *t) { - int empty_exp; - int empty_norm; - int empty_exp_now; + bool empty; + bool empty_exp; + bool empty_norm; + bool empty_exp_now; unsigned long flags; struct list_head *np; #ifdef CONFIG_RCU_BOOST @@ -376,6 +377,7 @@ void rcu_read_unlock_special(struct task_struct *t) break; raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ } + empty = !rcu_preempt_has_tasks(rnp); empty_norm = !rcu_preempt_blocked_readers_cgp(rnp); empty_exp = !rcu_preempted_readers_exp(rnp); smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ @@ -396,6 +398,14 @@ void rcu_read_unlock_special(struct task_struct *t) #endif /* #ifdef CONFIG_RCU_BOOST */ /* + * If this was the last task on the list, go see if we + * need to propagate ->qsmaskinit bit clearing up the + * rcu_node tree. + */ + if (!empty && !rcu_preempt_has_tasks(rnp)) + rcu_cleanup_dead_rnp(rnp); + + /* * If this was the last task on the current list, and if * we aren't waiting on any CPUs, report the quiescent state. * Note that rcu_report_unblock_qs_rnp() releases rnp->lock, -- cgit v0.10.2 From d19fb8d1f3f66cc342d30aa48f090c70afb753ed Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Oct 2014 12:56:16 -0700 Subject: rcu: Don't migrate blocked tasks even if all corresponding CPUs offline When the last CPU associated with a given leaf rcu_node structure goes offline, something must be done about the tasks queued on that rcu_node structure. Each of these tasks has been preempted on one of the leaf rcu_node structure's CPUs while in an RCU read-side critical section that it have not yet exited. Handling these tasks is the job of rcu_preempt_offline_tasks(), which migrates them from the leaf rcu_node structure to the root rcu_node structure. Unfortunately, this migration has to be done one task at a time because each tasks allegiance must be shifted from the original leaf rcu_node to the root, so that future attempts to deal with these tasks will acquire the root rcu_node structure's ->lock rather than that of the leaf. Worse yet, this migration must be done with interrupts disabled, which is not so good for realtime response, especially given that there is no bound on the number of tasks on a given rcu_node structure's list. (OK, OK, there is a bound, it is just that it is unreasonably large, especially on 64-bit systems.) This was not considered a problem back when rcu_preempt_offline_tasks() was first written because realtime systems were assumed not to do CPU-hotplug operations while real-time applications were running. This assumption has proved of dubious validity given that people are starting to run multiple realtime applications on a single SMP system and that it is common practice to offline then online a CPU before starting its real-time application in order to clear extraneous processing off of that CPU. So we now need CPU hotplug operations to avoid undue latencies. This commit therefore avoids migrating these tasks, instead letting them be dequeued one by one from the original leaf rcu_node structure by rcu_read_unlock_special(). This means that the clearing of bits from the upper-level rcu_node structures must be deferred until the last such task has been dequeued, because otherwise subsequent grace periods won't wait on them. This commit has the beneficial side effect of simplifying the CPU-hotplug code for TREE_PREEMPT_RCU, especially in CONFIG_RCU_BOOST builds. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 6625a1b..84f16cf 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2276,7 +2276,6 @@ static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf) static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) { unsigned long flags; - int need_report = 0; struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_node *rnp = rdp->mynode; /* Outgoing CPU's rdp & rnp. */ @@ -2295,25 +2294,10 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) raw_spin_lock(&rnp->lock); /* irqs already disabled. */ smp_mb__after_unlock_lock(); /* Enforce GP memory-order guarantee. */ rnp->qsmaskinit &= ~rdp->grpmask; - if (rnp->qsmaskinit == 0) { - need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp); + if (rnp->qsmaskinit == 0 && !rcu_preempt_has_tasks(rnp)) rcu_cleanup_dead_rnp(rnp); - } - - /* - * We still hold the leaf rcu_node structure lock here, and - * irqs are still disabled. The reason for this subterfuge is - * because invoking rcu_report_unblock_qs_rnp() with ->orphan_lock - * held leads to deadlock. - */ raw_spin_unlock(&rsp->orphan_lock); /* irqs remain disabled. */ - rnp = rdp->mynode; - if (need_report & RCU_OFL_TASKS_NORM_GP) - rcu_report_unblock_qs_rnp(rnp, flags); - else - raw_spin_unlock_irqrestore(&rnp->lock, flags); - if (need_report & RCU_OFL_TASKS_EXP_GP) - rcu_report_exp_rnp(rsp, rnp, true); + raw_spin_unlock_irqrestore(&rnp->lock, flags); WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL, "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n", cpu, rdp->qlen, rdp->nxtlist); diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 9315477..883ebc8 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -514,13 +514,6 @@ extern struct list_head rcu_struct_flavors; #define for_each_rcu_flavor(rsp) \ list_for_each_entry((rsp), &rcu_struct_flavors, flavors) -/* Return values for rcu_preempt_offline_tasks(). */ - -#define RCU_OFL_TASKS_NORM_GP 0x1 /* Tasks blocking normal */ - /* GP were moved to root. */ -#define RCU_OFL_TASKS_EXP_GP 0x2 /* Tasks blocking expedited */ - /* GP were moved to root. */ - /* * RCU implementation internal declarations: */ @@ -550,24 +543,13 @@ long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(void); static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU -static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, - unsigned long flags); static bool rcu_preempt_has_tasks(struct rcu_node *rnp); #endif /* #ifdef CONFIG_HOTPLUG_CPU */ static void rcu_print_detail_task_stall(struct rcu_state *rsp); static int rcu_print_task_stall(struct rcu_node *rnp); static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp); -#ifdef CONFIG_HOTPLUG_CPU -static int rcu_preempt_offline_tasks(struct rcu_state *rsp, - struct rcu_node *rnp, - struct rcu_data *rdp); -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ static void rcu_preempt_check_callbacks(void); void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); -#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PREEMPT_RCU) -static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, - bool wake); -#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PREEMPT_RCU) */ static void __init __rcu_init_preempt(void); static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags); static void rcu_preempt_boost_start_gp(struct rcu_node *rnp); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 8a2b841..d594da4 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -103,6 +103,8 @@ RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu); static struct rcu_state *rcu_state_p = &rcu_preempt_state; static int rcu_preempted_readers_exp(struct rcu_node *rnp); +static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, + bool wake); /* * Tell them what RCU they are running. @@ -545,92 +547,6 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) #ifdef CONFIG_HOTPLUG_CPU -/* - * Handle tasklist migration for case in which all CPUs covered by the - * specified rcu_node have gone offline. Move them up to the root - * rcu_node. The reason for not just moving them to the immediate - * parent is to remove the need for rcu_read_unlock_special() to - * make more than two attempts to acquire the target rcu_node's lock. - * Returns true if there were tasks blocking the current RCU grace - * period. - * - * Returns 1 if there was previously a task blocking the current grace - * period on the specified rcu_node structure. - * - * The caller must hold rnp->lock with irqs disabled. - */ -static int rcu_preempt_offline_tasks(struct rcu_state *rsp, - struct rcu_node *rnp, - struct rcu_data *rdp) -{ - struct list_head *lp; - struct list_head *lp_root; - int retval = 0; - struct rcu_node *rnp_root = rcu_get_root(rsp); - struct task_struct *t; - - if (rnp == rnp_root) { - WARN_ONCE(1, "Last CPU thought to be offlined?"); - return 0; /* Shouldn't happen: at least one CPU online. */ - } - - /* If we are on an internal node, complain bitterly. */ - WARN_ON_ONCE(rnp != rdp->mynode); - - /* - * Move tasks up to root rcu_node. Don't try to get fancy for - * this corner-case operation -- just put this node's tasks - * at the head of the root node's list, and update the root node's - * ->gp_tasks and ->exp_tasks pointers to those of this node's, - * if non-NULL. This might result in waiting for more tasks than - * absolutely necessary, but this is a good performance/complexity - * tradeoff. - */ - if (rcu_preempt_blocked_readers_cgp(rnp) && rnp->qsmask == 0) - retval |= RCU_OFL_TASKS_NORM_GP; - if (rcu_preempted_readers_exp(rnp)) - retval |= RCU_OFL_TASKS_EXP_GP; - lp = &rnp->blkd_tasks; - lp_root = &rnp_root->blkd_tasks; - while (!list_empty(lp)) { - t = list_entry(lp->next, typeof(*t), rcu_node_entry); - raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ - smp_mb__after_unlock_lock(); - list_del(&t->rcu_node_entry); - t->rcu_blocked_node = rnp_root; - list_add(&t->rcu_node_entry, lp_root); - if (&t->rcu_node_entry == rnp->gp_tasks) - rnp_root->gp_tasks = rnp->gp_tasks; - if (&t->rcu_node_entry == rnp->exp_tasks) - rnp_root->exp_tasks = rnp->exp_tasks; -#ifdef CONFIG_RCU_BOOST - if (&t->rcu_node_entry == rnp->boost_tasks) - rnp_root->boost_tasks = rnp->boost_tasks; -#endif /* #ifdef CONFIG_RCU_BOOST */ - raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */ - } - - rnp->gp_tasks = NULL; - rnp->exp_tasks = NULL; -#ifdef CONFIG_RCU_BOOST - rnp->boost_tasks = NULL; - /* - * In case root is being boosted and leaf was not. Make sure - * that we boost the tasks blocking the current grace period - * in this case. - */ - raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ - smp_mb__after_unlock_lock(); - if (rnp_root->boost_tasks != NULL && - rnp_root->boost_tasks != rnp_root->gp_tasks && - rnp_root->boost_tasks != rnp_root->exp_tasks) - rnp_root->boost_tasks = rnp_root->gp_tasks; - raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */ -#endif /* #ifdef CONFIG_RCU_BOOST */ - - return retval; -} - #endif /* #ifdef CONFIG_HOTPLUG_CPU */ /* @@ -979,13 +895,6 @@ static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp) #ifdef CONFIG_HOTPLUG_CPU -/* Because preemptible RCU does not exist, no quieting of tasks. */ -static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) - __releases(rnp->lock) -{ - raw_spin_unlock_irqrestore(&rnp->lock, flags); -} - /* * Because there is no preemptible RCU, there can be no readers blocked. */ @@ -1023,23 +932,6 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) WARN_ON_ONCE(rnp->qsmask); } -#ifdef CONFIG_HOTPLUG_CPU - -/* - * Because preemptible RCU does not exist, it never needs to migrate - * tasks that were blocked within RCU read-side critical sections, and - * such non-existent tasks cannot possibly have been blocking the current - * grace period. - */ -static int rcu_preempt_offline_tasks(struct rcu_state *rsp, - struct rcu_node *rnp, - struct rcu_data *rdp) -{ - return 0; -} - -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ - /* * Because preemptible RCU does not exist, it never has any callbacks * to check. @@ -1058,20 +950,6 @@ void synchronize_rcu_expedited(void) } EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); -#ifdef CONFIG_HOTPLUG_CPU - -/* - * Because preemptible RCU does not exist, there is never any need to - * report on tasks preempted in RCU read-side critical sections during - * expedited RCU grace periods. - */ -static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, - bool wake) -{ -} - -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ - /* * Because preemptible RCU does not exist, rcu_barrier() is just * another name for rcu_barrier_sched(). -- cgit v0.10.2 From a8f4cbadfb5c5f7f5d9eef70821276a4e2e9289d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Oct 2014 13:48:41 -0700 Subject: rcu: Shorten irq-disable region in rcu_cleanup_dead_cpu() Now that we are not migrating callbacks, there is no need to hold the ->orphan_lock across the the ->qsmaskinit bit-clearing process. This commit therefore releases ->orphan_lock immediately after adopting the orphaned RCU callbacks. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 84f16cf..990b406 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2289,14 +2289,14 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) /* Orphan the dead CPU's callbacks, and adopt them if appropriate. */ rcu_send_cbs_to_orphanage(cpu, rsp, rnp, rdp); rcu_adopt_orphan_cbs(rsp, flags); + raw_spin_unlock_irqrestore(&rsp->orphan_lock, flags); /* Remove outgoing CPU from mask in the leaf rcu_node structure. */ - raw_spin_lock(&rnp->lock); /* irqs already disabled. */ + raw_spin_lock_irqsave(&rnp->lock, flags); smp_mb__after_unlock_lock(); /* Enforce GP memory-order guarantee. */ rnp->qsmaskinit &= ~rdp->grpmask; if (rnp->qsmaskinit == 0 && !rcu_preempt_has_tasks(rnp)) rcu_cleanup_dead_rnp(rnp); - raw_spin_unlock(&rsp->orphan_lock); /* irqs remain disabled. */ raw_spin_unlock_irqrestore(&rnp->lock, flags); WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL, "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n", -- cgit v0.10.2 From 96e92021d4fad8543d598b5e4926cb34fd40c4c4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Oct 2014 14:09:23 -0700 Subject: rcu: Make use of rcu_preempt_has_tasks() Given that there is now arcu_preempt_has_tasks() function that checks to see if the ->blkd_tasks list is non-empty, this commit makes use of it. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index d594da4..bcc6d91 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -540,7 +540,7 @@ static int rcu_print_task_stall(struct rcu_node *rnp) static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) { WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp)); - if (!list_empty(&rnp->blkd_tasks)) + if (rcu_preempt_has_tasks(rnp)) rnp->gp_tasks = rnp->blkd_tasks.next; WARN_ON_ONCE(rnp->qsmask); } @@ -706,7 +706,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) raw_spin_lock_irqsave(&rnp->lock, flags); smp_mb__after_unlock_lock(); - if (list_empty(&rnp->blkd_tasks)) { + if (!rcu_preempt_has_tasks(rnp)) { raw_spin_unlock_irqrestore(&rnp->lock, flags); } else { rnp->exp_tasks = rnp->blkd_tasks.next; @@ -985,7 +985,7 @@ void exit_rcu(void) static void rcu_initiate_boost_trace(struct rcu_node *rnp) { - if (list_empty(&rnp->blkd_tasks)) + if (!rcu_preempt_has_tasks(rnp)) rnp->n_balk_blkd_tasks++; else if (rnp->exp_tasks == NULL && rnp->gp_tasks == NULL) rnp->n_balk_exp_gp_tasks++; -- cgit v0.10.2 From 3e9f5c70d85060ff0db71826e2048daffec336e7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 3 Nov 2014 18:15:17 -0800 Subject: rcu: Don't spawn rcub kthreads on root rcu_node structure Now that offlining CPUs no longer moves leaf rcu_node structures' ->blkd_tasks lists to the root, there is no way for the root rcu_node structure's ->blkd_task list to be nonempty, unless the root node is also the sole leaf node. This commit therefore refrains from creating an rcub kthread for the root rcu_node structure unless it is also the sole leaf. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index bcc6d91..3e64bb1 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1352,12 +1352,8 @@ static void __init rcu_spawn_boost_kthreads(void) for_each_possible_cpu(cpu) per_cpu(rcu_cpu_has_work, cpu) = 0; BUG_ON(smpboot_register_percpu_thread(&rcu_cpu_thread_spec)); - rnp = rcu_get_root(rcu_state_p); - (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp); - if (NUM_RCU_NODES > 1) { - rcu_for_each_leaf_node(rcu_state_p, rnp) - (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp); - } + rcu_for_each_leaf_node(rcu_state_p, rnp) + (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp); } static void rcu_prepare_kthreads(int cpu) -- cgit v0.10.2 From 1be0085b515e786e962b9f2d03616209eb6eb9a7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 3 Nov 2014 18:20:20 -0800 Subject: rcu: Don't initiate RCU priority boosting on root rcu_node Because there is no longer any preempted tasks on the root rcu_node, and because there is no longer ever an rcub kthread for the root rcu_node, this commit drops the code in force_qs_rnp() that attempts to awaken the non-existent root rcub kthread. This is strictly a performance enhancement, removing a root rcu_node ->lock acquisition and release along with some tests in rcu_initiate_boost(), ending with the test that notes that there is no rcub kthread. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 990b406..5a0a4c96 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2513,12 +2513,6 @@ static void force_qs_rnp(struct rcu_state *rsp, } raw_spin_unlock_irqrestore(&rnp->lock, flags); } - rnp = rcu_get_root(rsp); - if (rnp->qsmask == 0) { - raw_spin_lock_irqsave(&rnp->lock, flags); - smp_mb__after_unlock_lock(); - rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */ - } } /* -- cgit v0.10.2 From 5d0b024973027556b48a09bb36b55dc853ec7c6e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 10 Nov 2014 08:07:08 -0800 Subject: rcu: Don't bother affinitying rcub kthreads away from offline CPUs When rcu_boost_kthread_setaffinity() sees that all CPUs for a given rcu_node structure are now offline, it affinities the corresponding RCU-boost ("rcub") kthread away from those CPUs. This is pointless because the kthread cannot run on those offline CPUs in any case. This commit therefore removes this unneeded code. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 3e64bb1..1fac682 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1322,12 +1322,8 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) if ((mask & 0x1) && cpu != outgoingcpu) cpumask_set_cpu(cpu, cm); - if (cpumask_weight(cm) == 0) { + if (cpumask_weight(cm) == 0) cpumask_setall(cm); - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++) - cpumask_clear_cpu(cpu, cm); - WARN_ON_ONCE(cpumask_weight(cm) == 0); - } set_cpus_allowed_ptr(t, cm); free_cpumask_var(cm); } -- cgit v0.10.2 From 3ba4d0e09bf965297e97adf195e0ea246cfe5c74 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 12 Nov 2014 09:57:51 -0800 Subject: rcu: Note quiescent state when CPU goes offline The rcu_cleanup_dead_cpu() function (called after a CPU has gone completely offline) has not reported a quiescent state because there was probably at least one synchronize_rcu() between the time the CPU went offline and the CPU_DEAD notifier, and this would have detected the CPU's offline state via quiescent-state forcing. However, the plan is for CPUs to take themselves offline, at which point it makes sense for them to report their own quiescent state. This commit makes this change in preparation for the new CPU-hotplug setup. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 5a0a4c96..24d3c67 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2297,7 +2297,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) rnp->qsmaskinit &= ~rdp->grpmask; if (rnp->qsmaskinit == 0 && !rcu_preempt_has_tasks(rnp)) rcu_cleanup_dead_rnp(rnp); - raw_spin_unlock_irqrestore(&rnp->lock, flags); + rcu_report_qs_rnp(rdp->grpmask, rsp, rnp, flags); /* Rlses rnp->lock. */ WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL, "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n", cpu, rdp->qlen, rdp->nxtlist); -- cgit v0.10.2 From abaf3f9d275b8d856ae5e47531e40c0bfeac012b Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 18 Nov 2014 16:30:01 +0800 Subject: rcu: Revert "Allow post-unlock reference for rt_mutex" to avoid priority-inversion The patch dfeb9765ce3c ("Allow post-unlock reference for rt_mutex") ensured rcu-boost safe even the rt_mutex has post-unlock reference. But rt_mutex allowing post-unlock reference is definitely a bug and it was fixed by the commit 27e35715df54 ("rtmutex: Plug slow unlock race"). This fix made the previous patch (dfeb9765ce3c) useless. And even worse, the priority-inversion introduced by the the previous patch still exists. rcu_read_unlock_special() { rt_mutex_unlock(&rnp->boost_mtx); /* Priority-Inversion: * the current task had been deboosted and preempted as a low * priority task immediately, it could wait long before reschedule in, * and the rcu-booster also waits on this low priority task and sleeps. * This priority-inversion makes rcu-booster can't work * as expected. */ complete(&rnp->boost_completion); } Just revert the patch to avoid it. Cc: Thomas Gleixner Cc: Steven Rostedt Cc: Peter Zijlstra Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 883ebc8..9535647 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -172,11 +172,6 @@ struct rcu_node { /* queued on this rcu_node structure that */ /* are blocking the current grace period, */ /* there can be no such task. */ - struct completion boost_completion; - /* Used to ensure that the rt_mutex used */ - /* to carry out the boosting is fully */ - /* released with no future boostee accesses */ - /* before that rt_mutex is re-initialized. */ struct rt_mutex boost_mtx; /* Used only for the priority-boosting */ /* side effect, not as a lock. */ diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 1fac682..625e260 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -429,10 +429,8 @@ void rcu_read_unlock_special(struct task_struct *t) #ifdef CONFIG_RCU_BOOST /* Unboost if we were boosted. */ - if (drop_boost_mutex) { + if (drop_boost_mutex) rt_mutex_unlock(&rnp->boost_mtx); - complete(&rnp->boost_completion); - } #endif /* #ifdef CONFIG_RCU_BOOST */ /* @@ -1081,15 +1079,11 @@ static int rcu_boost(struct rcu_node *rnp) */ t = container_of(tb, struct task_struct, rcu_node_entry); rt_mutex_init_proxy_locked(&rnp->boost_mtx, t); - init_completion(&rnp->boost_completion); raw_spin_unlock_irqrestore(&rnp->lock, flags); /* Lock only for side effect: boosts task t's priority. */ rt_mutex_lock(&rnp->boost_mtx); rt_mutex_unlock(&rnp->boost_mtx); /* Then keep lockdep happy. */ - /* Wait for boostee to be done w/boost_mtx before reinitializing. */ - wait_for_completion(&rnp->boost_completion); - return ACCESS_ONCE(rnp->exp_tasks) != NULL || ACCESS_ONCE(rnp->boost_tasks) != NULL; } -- cgit v0.10.2 From 6cd534ef8bfe422a5a847b953d1039841509c374 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 10 Dec 2014 07:45:13 -0800 Subject: rcu: Don't scan root rcu_node structure for stalled tasks Now that blocked tasks are no longer migrated to the root rcu_node structure, there is no need to scan the root rcu_node structure for blocked tasks stalling the current grace period. This commit therefore removes this scan. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 24d3c67..4ed2c28 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1107,15 +1107,6 @@ static void print_other_cpu_stall(struct rcu_state *rsp) raw_spin_unlock_irqrestore(&rnp->lock, flags); } - /* - * Now rat on any tasks that got kicked up to the root rcu_node - * due to CPU offlining. - */ - rnp = rcu_get_root(rsp); - raw_spin_lock_irqsave(&rnp->lock, flags); - ndetected += rcu_print_task_stall(rnp); - raw_spin_unlock_irqrestore(&rnp->lock, flags); - print_cpu_stall_info_end(); for_each_possible_cpu(cpu) totqlen += per_cpu_ptr(rsp->rda, cpu)->qlen; -- cgit v0.10.2 From ab954c167ed9ac107a8beb1d6e1745ae698a3421 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 17 Dec 2014 18:25:59 -0800 Subject: rcu: Remove redundant callback-list initialization The RCU callback lists are initialized in both rcu_boot_init_percpu_data() and rcu_init_percpu_data(). The former is intended for initializing immutable data, so this commit removes the initialization from rcu_boot_init_percpu_data() and leaves it in rcu_init_percpu_data(). This change prepares for permitting callbacks to be queued very early in boot. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 4ed2c28..febd0f7 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3419,9 +3419,6 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) /* Set up local state, ensuring consistent view of global state. */ raw_spin_lock_irqsave(&rnp->lock, flags); rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); - init_callback_list(rdp); - rdp->qlen_lazy = 0; - ACCESS_ONCE(rdp->qlen) = 0; rdp->dynticks = &per_cpu(rcu_dynticks, cpu); WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE); WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1); -- cgit v0.10.2 From a5c198f4f7da6cc48116ca239c59c9f44b753364 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 23 Nov 2014 20:30:06 -0800 Subject: rcu: Expand SRCU ->completed to 64 bits When rcutorture used only the low-order 32 bits of the grace-period number, it was not a problem for SRCU to use a 32-bit completed field. However, rcutorture now uses the full 64 bits on 64-bit systems, so this commit converts SRCU's ->completed field to unsigned long so as to provide 64 bits on 64-bit systems. Signed-off-by: Paul E. McKenney diff --git a/include/linux/srcu.h b/include/linux/srcu.h index a2783cb..ef923dd 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -45,7 +45,7 @@ struct rcu_batch { #define RCU_BATCH_INIT(name) { NULL, &(name.head) } struct srcu_struct { - unsigned completed; + unsigned long completed; struct srcu_struct_array __percpu *per_cpu_ref; spinlock_t queue_lock; /* protect ->batch_queue, ->running */ bool running; @@ -135,7 +135,7 @@ int __srcu_read_lock(struct srcu_struct *sp) __acquires(sp); void __srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); void synchronize_srcu(struct srcu_struct *sp); void synchronize_srcu_expedited(struct srcu_struct *sp); -long srcu_batches_completed(struct srcu_struct *sp); +unsigned long srcu_batches_completed(struct srcu_struct *sp); void srcu_barrier(struct srcu_struct *sp); #ifdef CONFIG_DEBUG_LOCK_ALLOC diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index e037f3e..445bf8f 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -546,7 +546,7 @@ EXPORT_SYMBOL_GPL(srcu_barrier); * Report the number of batches, correlated with, but not necessarily * precisely the same as, the number of grace periods that have elapsed. */ -long srcu_batches_completed(struct srcu_struct *sp) +unsigned long srcu_batches_completed(struct srcu_struct *sp) { return sp->completed; } -- cgit v0.10.2 From 9735af5c78599703be633c057af3faee26482028 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 26 Nov 2014 10:42:50 -0800 Subject: rcu: Combine DEFINE_SRCU() and DEFINE_STATIC_SRCU() The DEFINE_SRCU() and DEFINE_STATIC_SRCU() definitions are quite similar, so this commit combines them, saving a bit of code and removing redundancy. Signed-off-by: Paul E. McKenney diff --git a/include/linux/srcu.h b/include/linux/srcu.h index ef923dd..9cfd962 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -102,13 +102,11 @@ void process_srcu(struct work_struct *work); * define and init a srcu struct at build time. * dont't call init_srcu_struct() nor cleanup_srcu_struct() on it. */ -#define DEFINE_SRCU(name) \ +#define __DEFINE_SRCU(name, is_static) \ static DEFINE_PER_CPU(struct srcu_struct_array, name##_srcu_array);\ - struct srcu_struct name = __SRCU_STRUCT_INIT(name); - -#define DEFINE_STATIC_SRCU(name) \ - static DEFINE_PER_CPU(struct srcu_struct_array, name##_srcu_array);\ - static struct srcu_struct name = __SRCU_STRUCT_INIT(name); + is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name) +#define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) +#define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) /** * call_srcu() - Queue a callback for invocation after an SRCU grace period -- cgit v0.10.2 From 83fe27ea531161a655f02dc7732d14cfaa27fd5d Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 5 Dec 2014 11:24:45 -0500 Subject: rcu: Make SRCU optional by using CONFIG_SRCU SRCU is not necessary to be compiled by default in all cases. For tinification efforts not compiling SRCU unless necessary is desirable. The current patch tries to make compiling SRCU optional by introducing a new Kconfig option CONFIG_SRCU which is selected when any of the components making use of SRCU are selected. If we do not select CONFIG_SRCU, srcu.o will not be compiled at all. text data bss dec hex filename 2007 0 0 2007 7d7 kernel/rcu/srcu.o Size of arch/powerpc/boot/zImage changes from text data bss dec hex filename 831552 64180 23944 919676 e087c arch/powerpc/boot/zImage : before 829504 64180 23952 917636 e0084 arch/powerpc/boot/zImage : after so the savings are about ~2000 bytes. Signed-off-by: Pranith Kumar CC: Paul E. McKenney CC: Josh Triplett CC: Lai Jiangshan Signed-off-by: Paul E. McKenney [ paulmck: resolve conflict due to removal of arch/ia64/kvm/Kconfig. ] diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig index 466bd29..3afee5f 100644 --- a/arch/arm/kvm/Kconfig +++ b/arch/arm/kvm/Kconfig @@ -23,6 +23,7 @@ config KVM select HAVE_KVM_CPU_RELAX_INTERCEPT select KVM_MMIO select KVM_ARM_HOST + select SRCU depends on ARM_VIRT_EXT && ARM_LPAE ---help--- Support hosting virtualized guest machines. You will also diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 8ba85e9..b334084 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -26,6 +26,7 @@ config KVM select KVM_ARM_HOST select KVM_ARM_VGIC select KVM_ARM_TIMER + select SRCU ---help--- Support hosting virtualized guest machines. diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig index 30e334e..2ae1282 100644 --- a/arch/mips/kvm/Kconfig +++ b/arch/mips/kvm/Kconfig @@ -20,6 +20,7 @@ config KVM select PREEMPT_NOTIFIERS select ANON_INODES select KVM_MMIO + select SRCU ---help--- Support for hosting Guest kernels. Currently supported on MIPS32 processors. diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index f5769f1..11850f3 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM select PREEMPT_NOTIFIERS select ANON_INODES select HAVE_KVM_EVENTFD + select SRCU config KVM_BOOK3S_HANDLER bool diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 646db9c..5fce52c 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -28,6 +28,7 @@ config KVM select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING + select SRCU ---help--- Support hosting paravirtualized guest machines using the SIE virtualization capability on the mainframe. This should work diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig index 2298cb1..1e968f7 100644 --- a/arch/tile/kvm/Kconfig +++ b/arch/tile/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM depends on HAVE_KVM && MODULES select PREEMPT_NOTIFIERS select ANON_INODES + select SRCU ---help--- Support hosting paravirtualized guest machines. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ba397bd..6612699 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -138,6 +138,7 @@ config X86 select HAVE_ACPI_APEI_NMI if ACPI select ACPI_LEGACY_TABLES_LOOKUP if ACPI select X86_FEATURE_NAMES if PROC_FS + select SRCU config INSTRUCTION_DECODER def_bool y diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index f9d16ff..7dc7ba5 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -40,6 +40,7 @@ config KVM select HAVE_KVM_MSI select HAVE_KVM_CPU_RELAX_INTERCEPT select KVM_VFIO + select SRCU ---help--- Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3f44f29..91f8613 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -13,6 +13,7 @@ config COMMON_CLK bool select HAVE_CLK_PREPARE select CLKDEV_LOOKUP + select SRCU ---help--- The common clock framework is a single definition of struct clk, useful across many platforms, as well as an diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 29b2ef5..a171fef 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -2,6 +2,7 @@ menu "CPU Frequency scaling" config CPU_FREQ bool "CPU Frequency scaling" + select SRCU help CPU Frequency scaling allows you to change the clock speed of CPUs on the fly. This is a nice method to save power, because diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index faf4e70..3891f67 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -1,5 +1,6 @@ menuconfig PM_DEVFREQ bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support" + select SRCU help A device may have a list of frequencies and voltages available. devfreq, a generic DVFS framework can be registered for a device diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 5bdedf6..c355a22 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -5,6 +5,7 @@ menuconfig MD bool "Multiple devices driver support (RAID and LVM)" depends on BLOCK + select SRCU help Support multiple physical spindles through a single logical device. Required for RAID and logical volume management. diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d6607ee..84673eb 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -197,6 +197,7 @@ config NETCONSOLE_DYNAMIC config NETPOLL def_bool NETCONSOLE + select SRCU config NET_POLL_CONTROLLER def_bool NETPOLL diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index a66768e..80e9c18 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig @@ -8,6 +8,7 @@ config BTRFS_FS select LZO_DECOMPRESS select RAID6_PQ select XOR_BLOCKS + select SRCU help Btrfs is a general purpose copy-on-write filesystem with extents, diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig index 22c629e..2a24249 100644 --- a/fs/notify/Kconfig +++ b/fs/notify/Kconfig @@ -1,5 +1,6 @@ config FSNOTIFY def_bool n + select SRCU source "fs/notify/dnotify/Kconfig" source "fs/notify/inotify/Kconfig" diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index c51df1d..4a09975 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig @@ -5,6 +5,7 @@ config QUOTA bool "Quota support" select QUOTACTL + select SRCU help If you say Y here, you will be able to set per user limits for disk usage (also called disk quotas). Currently, it works for the diff --git a/init/Kconfig b/init/Kconfig index 9afb971..f085969 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -501,9 +501,17 @@ config TINY_RCU endchoice +config SRCU + bool + help + This option selects the sleepable version of RCU. This version + permits arbitrary sleeping or blocking within RCU read-side critical + sections. + config TASKS_RCU bool "Task_based RCU implementation using voluntary context switch" default n + select SRCU help This option enables a task-based RCU implementation that uses only voluntary context switch (not preemption!), idle, and @@ -1595,6 +1603,7 @@ config PERF_EVENTS depends on HAVE_PERF_EVENTS select ANON_INODES select IRQ_WORK + select SRCU help Enable kernel support for various performance events provided by software and hardware. diff --git a/kernel/notifier.c b/kernel/notifier.c index 4803da6..ae9fc7c 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c @@ -402,6 +402,7 @@ int raw_notifier_call_chain(struct raw_notifier_head *nh, } EXPORT_SYMBOL_GPL(raw_notifier_call_chain); +#ifdef CONFIG_SRCU /* * SRCU notifier chain routines. Registration and unregistration * use a mutex, and call_chain is synchronized by SRCU (no locks). @@ -528,6 +529,8 @@ void srcu_init_notifier_head(struct srcu_notifier_head *nh) } EXPORT_SYMBOL_GPL(srcu_init_notifier_head); +#endif /* CONFIG_SRCU */ + static ATOMIC_NOTIFIER_HEAD(die_chain); int notrace notify_die(enum die_val val, const char *str, diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 48b28d3..7e01f78 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -251,6 +251,7 @@ config APM_EMULATION config PM_OPP bool + select SRCU ---help--- SOCs have a standard set of tuples consisting of frequency and voltage pairs that the device will support per voltage domain. This diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile index e6fae50..50a8084 100644 --- a/kernel/rcu/Makefile +++ b/kernel/rcu/Makefile @@ -1,4 +1,5 @@ -obj-y += update.o srcu.o +obj-y += update.o +obj-$(CONFIG_SRCU) += srcu.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_TREE_RCU) += tree.o obj-$(CONFIG_PREEMPT_RCU) += tree.o diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5f2ce61..7a9c93e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1215,6 +1215,7 @@ config RCU_TORTURE_TEST tristate "torture tests for RCU" depends on DEBUG_KERNEL select TORTURE_TEST + select SRCU default n help This option provides a kernel module that runs torture tests diff --git a/mm/Kconfig b/mm/Kconfig index 1d1ae6b..4395b12 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -325,6 +325,7 @@ config VIRT_TO_BUS config MMU_NOTIFIER bool + select SRCU config KSM bool "Enable KSM for page merging" diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index 8eb779b9d..604e718 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig @@ -5,6 +5,7 @@ config SECURITY_TOMOYO select SECURITYFS select SECURITY_PATH select SECURITY_NETWORK + select SRCU default n help This selects TOMOYO Linux, pathname-based access control. -- cgit v0.10.2 From 68158fe2b2aa0f0c1cf96b40020c7d180915479b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 8 Dec 2014 07:41:31 -0800 Subject: rcu: Set default to RCU_CPU_STALL_INFO=y The RCU_CPU_STALL_INFO code has been in for quite some time, and has proven reliable. This commit therefore enables it by default. Signed-off-by: Paul E. McKenney diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5f2ce61..b47d9e4 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1257,7 +1257,7 @@ config RCU_CPU_STALL_TIMEOUT config RCU_CPU_STALL_INFO bool "Print additional diagnostics on RCU CPU stall" depends on (TREE_RCU || PREEMPT_RCU) && DEBUG_KERNEL - default n + default y help For each stalled CPU that is aware of the current RCU grace period, print out additional per-CPU diagnostic information -- cgit v0.10.2 From e9408e4f278875aa5862560b4b425b27dfcb643f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 8 Dec 2014 09:13:52 -0800 Subject: rcutorture: Add checks for stall ending before dump start The current rcutorture scripting checks for actual stalls (via the "Call Trace:" check), but fails to spot the case where a stall ends just as it is being detected. This commit therefore adds a check for this case. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh index f962ba4..d8f35cf 100755 --- a/tools/testing/selftests/rcutorture/bin/parse-console.sh +++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh @@ -36,7 +36,7 @@ if grep -Pq '\x00' < $file then print_warning Console output contains nul bytes, old qemu still running? fi -egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T +egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T if test -s $T then print_warning Assertion failure in $file $title -- cgit v0.10.2 From fc908ed33e7c1428f799abb12399f906da03b397 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 8 Dec 2014 09:57:48 -0800 Subject: rcu: Make RCU_CPU_STALL_INFO include number of fqs attempts One way that an RCU CPU stall warning can happen is if the grace-period kthread is not allowed to execute. One proxy for this kthread's forward progress is the number of force-quiescent-state (fqs) scans. This commit therefore adds the number of fqs scans to the RCU CPU stall warning printouts when CONFIG_RCU_CPU_STALL_INFO=y. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 4c106fc..654b15b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1043,6 +1043,7 @@ static void record_gp_stall_check_time(struct rcu_state *rsp) j1 = rcu_jiffies_till_stall_check(); ACCESS_ONCE(rsp->jiffies_stall) = j + j1; rsp->jiffies_resched = j + j1 / 2; + rsp->n_force_qs_gpstart = ACCESS_ONCE(rsp->n_force_qs); } /* diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 8e7b184..e300848 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -492,6 +492,8 @@ struct rcu_state { /* for CPU stalls. */ unsigned long jiffies_resched; /* Time at which to resched */ /* a reluctant CPU. */ + unsigned long n_force_qs_gpstart; /* Snapshot of n_force_qs at */ + /* GP start. */ unsigned long gp_max; /* Maximum GP duration in */ /* jiffies. */ const char *name; /* Name of structure. */ diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 3ec85cb..769384d7 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1898,11 +1898,12 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) ticks_value = rsp->gpnum - rdp->gpnum; } print_cpu_stall_fast_no_hz(fast_no_hz, cpu); - pr_err("\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u %s\n", + pr_err("\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n", cpu, ticks_value, ticks_title, atomic_read(&rdtp->dynticks) & 0xfff, rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu), + ACCESS_ONCE(rsp->n_force_qs) - rsp->n_force_qs_gpstart, fast_no_hz); } -- cgit v0.10.2 From 6ccd2ecd422644277b7d8b37222e3af3f43ea9ae Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 11 Dec 2014 10:20:59 -0800 Subject: rcu: Improve diagnostics for spurious RCU CPU stall warnings The current RCU CPU stall warning code will print "Stall ended before state dump start" any time that the stall-warning code is triggered on a CPU that has already reported a quiescent state for the current grace period and if all quiescent states have been reported for the current grace period. However, a true stall can result in these symptoms, for example, by preventing RCU's grace-period kthreads from ever running This commit therefore checks for this condition, reporting the end of the stall only if one of the grace-period counters has actually advanced. Otherwise, it reports the last time that the grace-period kthread made meaningful progress. (In normal situations, the grace-period kthread should make meaningful progress at least every jiffies_till_next_fqs jiffies.) Reported-by: Miroslav Benes Signed-off-by: Paul E. McKenney Tested-by: Miroslav Benes diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index ed186a9..55f9707 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -187,6 +187,11 @@ o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the behavior, you might need to replace some of the cond_resched() calls with calls to cond_resched_rcu_qs(). +o Anything that prevents RCU's grace-period kthreads from running. + This can result in the "All QSes seen" console-log message. + This message will include information on when the kthread last + ran and how often it should be expected to run. + o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might happen to preempt a low-priority task in the middle of an RCU read-side critical section. This is especially damaging if diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 654b15b..a2ceb66 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1066,11 +1066,13 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp) } } -static void print_other_cpu_stall(struct rcu_state *rsp) +static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) { int cpu; long delta; unsigned long flags; + unsigned long gpa; + unsigned long j; int ndetected = 0; struct rcu_node *rnp = rcu_get_root(rsp); long totqlen = 0; @@ -1123,10 +1125,22 @@ static void print_other_cpu_stall(struct rcu_state *rsp) pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n", smp_processor_id(), (long)(jiffies - rsp->gp_start), (long)rsp->gpnum, (long)rsp->completed, totqlen); - if (ndetected == 0) - pr_err("INFO: Stall ended before state dump start\n"); - else + if (ndetected) { rcu_dump_cpu_stacks(rsp); + } else { + if (ACCESS_ONCE(rsp->gpnum) != gpnum || + ACCESS_ONCE(rsp->completed) == gpnum) { + pr_err("INFO: Stall ended before state dump start\n"); + } else { + j = jiffies; + gpa = ACCESS_ONCE(rsp->gp_activity); + pr_err("All QSes seen, last %s kthread activity %ld (%ld-%ld), jiffies_till_next_fqs=%ld\n", + rsp->name, j - gpa, j, gpa, + jiffies_till_next_fqs); + /* In this case, the current CPU might be at fault. */ + sched_show_task(current); + } + } /* Complain about tasks blocking the grace period. */ @@ -1226,7 +1240,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) ULONG_CMP_GE(j, js + RCU_STALL_RAT_DELAY)) { /* They had a few time units to dump stack, so complain. */ - print_other_cpu_stall(rsp); + print_other_cpu_stall(rsp, gpnum); } } @@ -1622,6 +1636,7 @@ static int rcu_gp_init(struct rcu_state *rsp) struct rcu_data *rdp; struct rcu_node *rnp = rcu_get_root(rsp); + ACCESS_ONCE(rsp->gp_activity) = jiffies; rcu_bind_gp_kthread(); raw_spin_lock_irq(&rnp->lock); smp_mb__after_unlock_lock(); @@ -1682,6 +1697,7 @@ static int rcu_gp_init(struct rcu_state *rsp) rnp->grphi, rnp->qsmask); raw_spin_unlock_irq(&rnp->lock); cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; } mutex_unlock(&rsp->onoff_mutex); @@ -1698,6 +1714,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in) unsigned long maxj; struct rcu_node *rnp = rcu_get_root(rsp); + ACCESS_ONCE(rsp->gp_activity) = jiffies; rsp->n_force_qs++; if (fqs_state == RCU_SAVE_DYNTICK) { /* Collect dyntick-idle snapshots. */ @@ -1736,6 +1753,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) struct rcu_data *rdp; struct rcu_node *rnp = rcu_get_root(rsp); + ACCESS_ONCE(rsp->gp_activity) = jiffies; raw_spin_lock_irq(&rnp->lock); smp_mb__after_unlock_lock(); gp_duration = jiffies - rsp->gp_start; @@ -1772,6 +1790,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) nocb += rcu_future_gp_cleanup(rsp, rnp); raw_spin_unlock_irq(&rnp->lock); cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; } rnp = rcu_get_root(rsp); raw_spin_lock_irq(&rnp->lock); @@ -1821,6 +1840,7 @@ static int __noreturn rcu_gp_kthread(void *arg) if (rcu_gp_init(rsp)) break; cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; WARN_ON(signal_pending(current)); trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), @@ -1864,9 +1884,11 @@ static int __noreturn rcu_gp_kthread(void *arg) ACCESS_ONCE(rsp->gpnum), TPS("fqsend")); cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; } else { /* Deal with stray signal. */ cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; WARN_ON(signal_pending(current)); trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index e300848..5ec81cf 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -488,6 +488,8 @@ struct rcu_state { /* due to no GP active. */ unsigned long gp_start; /* Time at which GP started, */ /* but in jiffies. */ + unsigned long gp_activity; /* Time of last GP kthread */ + /* activity in jiffies. */ unsigned long jiffies_stall; /* Time at which to check */ /* for CPU stalls. */ unsigned long jiffies_resched; /* Time at which to resched */ -- cgit v0.10.2 From e3663b1024d1f94688e5233440ad67a9bc10b94e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 8 Dec 2014 20:26:55 -0800 Subject: rcu: Handle gpnum/completed wrap while dyntick idle Subtle race conditions can result if a CPU stays in dyntick-idle mode long enough for the ->gpnum and ->completed fields to wrap. For example, consider the following sequence of events: o CPU 1 encounters a quiescent state while waiting for grace period 5 to complete, but then enters dyntick-idle mode. o While CPU 1 is in dyntick-idle mode, the grace-period counters wrap around so that the grace period number is now 4. o Just as CPU 1 exits dyntick-idle mode, grace period 4 completes and grace period 5 begins. o The quiescent state that CPU 1 passed through during the old grace period 5 looks like it applies to the new grace period 5. Therefore, the new grace period 5 completes without CPU 1 having passed through a quiescent state. This could clearly be a fatal surprise to any long-running RCU read-side critical section that happened to be running on CPU 1 at the time. At one time, this was not a problem, given that it takes significant time for the grace-period counters to overflow even on 32-bit systems. However, with the advent of NO_HZ_FULL and SMP embedded systems, arbitrarily long idle periods are now becoming quite feasible. It is therefore time to close this race. This commit therefore avoids this race condition by having the quiescent-state forcing code detect when a CPU is falling too far behind, and setting a new rcu_data field ->gpwrap when this happens. Whenever this new ->gpwrap field is set, the CPU's ->gpnum and ->completed fields are known to be untrustworthy, and can be ignored, along with any associated quiescent states. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index a2ceb66..5987fdc 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -930,6 +930,9 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp, trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti")); return 1; } else { + if (ULONG_CMP_LT(ACCESS_ONCE(rdp->gpnum) + ULONG_MAX / 4, + rdp->mynode->gpnum)) + ACCESS_ONCE(rdp->gpwrap) = true; return 0; } } @@ -1577,7 +1580,8 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, bool ret; /* Handle the ends of any preceding grace periods first. */ - if (rdp->completed == rnp->completed) { + if (rdp->completed == rnp->completed && + !unlikely(ACCESS_ONCE(rdp->gpwrap))) { /* No grace period end, so just accelerate recent callbacks. */ ret = rcu_accelerate_cbs(rsp, rnp, rdp); @@ -1592,7 +1596,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuend")); } - if (rdp->gpnum != rnp->gpnum) { + if (rdp->gpnum != rnp->gpnum || unlikely(ACCESS_ONCE(rdp->gpwrap))) { /* * If the current grace period is waiting for this CPU, * set up to detect a quiescent state, otherwise don't @@ -1603,6 +1607,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, rdp->passed_quiesce = 0; rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask); zero_cpu_stall_ticks(rdp); + ACCESS_ONCE(rdp->gpwrap) = false; } return ret; } @@ -1616,7 +1621,8 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp) local_irq_save(flags); rnp = rdp->mynode; if ((rdp->gpnum == ACCESS_ONCE(rnp->gpnum) && - rdp->completed == ACCESS_ONCE(rnp->completed)) || /* w/out lock. */ + rdp->completed == ACCESS_ONCE(rnp->completed) && + !unlikely(ACCESS_ONCE(rdp->gpwrap))) || /* w/out lock. */ !raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */ local_irq_restore(flags); return; @@ -2066,7 +2072,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp) raw_spin_lock_irqsave(&rnp->lock, flags); smp_mb__after_unlock_lock(); if (rdp->passed_quiesce == 0 || rdp->gpnum != rnp->gpnum || - rnp->completed == rnp->gpnum) { + rnp->completed == rnp->gpnum || rdp->gpwrap) { /* * The grace period in which this quiescent state was @@ -3190,7 +3196,8 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) } /* Has a new RCU grace period started? */ - if (ACCESS_ONCE(rnp->gpnum) != rdp->gpnum) { /* outside lock */ + if (ACCESS_ONCE(rnp->gpnum) != rdp->gpnum || + unlikely(ACCESS_ONCE(rdp->gpwrap))) { /* outside lock */ rdp->n_rp_gp_started++; return 1; } diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 5ec81cf..7472ff3 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -260,6 +260,7 @@ struct rcu_data { bool passed_quiesce; /* User-mode/idle loop etc. */ bool qs_pending; /* Core waits for quiesc state. */ bool beenonline; /* CPU online at least once. */ + bool gpwrap; /* Possible gpnum/completed wrap. */ struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ unsigned long grpmask; /* Mask to apply to leaf qsmask. */ #ifdef CONFIG_RCU_CPU_STALL_INFO diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 769384d7..81ff8b9 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1605,7 +1605,8 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void) * completed since we last checked and there are * callbacks not yet ready to invoke. */ - if (rdp->completed != rnp->completed && + if ((rdp->completed != rnp->completed || + unlikely(ACCESS_ONCE(rdp->gpwrap))) && rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_NEXT_TAIL]) note_gp_changes(rsp, rdp); -- cgit v0.10.2 From 83ac237a950e130c974d0170cce30891dcd8f250 Mon Sep 17 00:00:00 2001 From: Christoph Jaeger Date: Mon, 5 Jan 2015 22:34:09 -0500 Subject: livepatch: kconfig: use bool instead of boolean Keyword 'boolean' for type definition attributes is considered deprecated and should not be used anymore. No functional changes. Reference: http://lkml.kernel.org/r/cover.1418003065.git.cj@linux.com Reference: http://lkml.kernel.org/r/1419108071-11607-1-git-send-email-cj@linux.com Signed-off-by: Christoph Jaeger Reviewed-by: Petr Mladek Reviewed-by: Jingoo Han Acked-by: Josh Poimboeuf Signed-off-by: Jiri Kosina diff --git a/kernel/livepatch/Kconfig b/kernel/livepatch/Kconfig index 96da00f..66797aa 100644 --- a/kernel/livepatch/Kconfig +++ b/kernel/livepatch/Kconfig @@ -1,10 +1,10 @@ config ARCH_HAVE_LIVE_PATCHING - boolean + bool help Arch supports kernel live patching config LIVE_PATCHING - boolean "Kernel Live Patching" + bool "Kernel Live Patching" depends on DYNAMIC_FTRACE_WITH_REGS depends on MODULES depends on SYSFS -- cgit v0.10.2 From 6ce901eb61aa30ba8565c62049ee80c90728ef14 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 29 Dec 2014 15:21:26 +0100 Subject: HID: input: fix confusion on conflicting mappings On an PC-101/103/104 keyboard (American layout) the 'Enter' key and its neighbours look like this: +---+ +---+ +-------+ | 1 | | 2 | | 5 | +---+ +---+ +-------+ +---+ +-----------+ | 3 | | 4 | +---+ +-----------+ On a PC-102/105 keyboard (European layout) it looks like this: +---+ +---+ +-------+ | 1 | | 2 | | | +---+ +---+ +-+ 4 | +---+ +---+ | | | 3 | | 5 | | | +---+ +---+ +-----+ (Note that the number of keys is the same, but key '5' is moved down and the shape of key '4' is changed. Keys '1' to '3' are exactly the same.) The keys 1-4 report the same scan-code in HID in both layouts, even though the keysym they produce is usually different depending on the XKB-keymap used by user-space. However, key '5' (US 'backslash'/'pipe') reports 0x31 for the upper layout and 0x32 for the lower layout, as defined by the HID spec. This is highly confusing as the linux-input API uses a single keycode for both. So far, this was never a problem as there never has been a keyboard with both of those keys present at the same time. It would have to look something like this: +---+ +---+ +-------+ | 1 | | 2 | | x31 | +---+ +---+ +-------+ +---+ +---+ +-----+ | 3 | |x32| | 4 | +---+ +---+ +-----+ HID can represent such a keyboard, but the linux-input API cannot. Furthermore, any user-space mapping would be confused by this and, luckily, no-one ever produced such hardware. Now, the HID input layer fixed this mess by mapping both 0x31 and 0x32 to the same keycode (KEY_BACKSLASH==0x2b). As only one of both physical keys is present on a hardware, this works just fine. Lets introduce hardware-vendors into this: ------------------------------------------ Unfortunately, it seems way to expensive to produce a different device for American and European layouts. Therefore, hardware-vendors put both keys, (0x31 and 0x32) on the same keyboard, but only one of them is hooked up to the physical button, the other one is 'dead'. This means, they can use the same hardware, with a different button-layout and automatically produce the correct HID events for American *and* European layouts. This is unproblematic for normal keyboards, as the 'dead' key will never report any KEY-DOWN events. But RollOver keyboards send the whole matrix on each key-event, allowing n-key roll-over mode. This means, we get a 0x31 and 0x32 event on each key-press. One of them will always be 0, the other reports the real state. As we map both to the same keycode, we will get spurious key-events, even though the real key-state never changed. The easiest way would be to blacklist 'dead' keys and never handle those. We could simply read the 'country' tag of USB devices and blacklist either key according to the layout. But... hardware vendors... want the same device for all countries and thus many of them set 'country' to 0 for all devices. Meh.. So we have to deal with this properly. As we cannot know which of the keys is 'dead', we either need a heuristic and track those keys, or we simply make use of our value-tracking for HID fields. We simply ignore HID events for absolute data if the data didn't change. As HID tracks events on the HID level, we haven't done the keycode translation, yet. Therefore, the 'dead' key is tracked independently of the real key, therefore, any events on it will be ignored. This patch simply discards any HID events for absolute data if it didn't change compared to the last report. We need to ignore relative and buffered-byte reports for obvious reasons. But those cannot be affected by this bug, so we're fine. Preferably, we'd do this filtering on the HID-core level. But this might break a lot of custom drivers, if they do not follow the HID specs. Therefore, we do this late in hid-input just before we inject it into the input layer (which does the exact same filtering, but on the keycode level). If this turns out to break some devices, we might have to limit filtering to EV_KEY events. But lets try to do the Right Thing first, and properly filter any absolute data that didn't change. This patch is tagged for 'stable' as it fixes a lot of n-key RollOver hardware. We might wanna wait with backporting for a while, before we know it doesn't break anything else, though. Cc: Reported-by: Adam Goode Reported-by: Fredrik Hallenberg Tested-by: Fredrik Hallenberg Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e0a0f06..84b6899 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1101,6 +1101,22 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } + /* + * Ignore reports for absolute data if the data didn't change. This is + * not only an optimization but also fixes 'dead' key reports. Some + * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID + * 0x31 and 0x32) report multiple keys, even though a localized keyboard + * can only have one of them physically available. The 'dead' keys + * report constant 0. As all map to the same keycode, they'd confuse + * the input layer. If we filter the 'dead' keys on the HID level, we + * skip the keycode translation and only forward real events. + */ + if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | + HID_MAIN_ITEM_BUFFERED_BYTE)) && + usage->usage_index < field->maxusage && + value == field->value[usage->usage_index]) + return; + /* report the usage code as scancode if the key status has changed */ if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); -- cgit v0.10.2 From 79bc33bd60ac3d5ab3bd1918fba95234ac9d510e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 6 Jan 2015 09:09:13 +0100 Subject: HID: fix Kconfig text Signed-off-by: Geert Uytterhoeven Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 230b6f8..303b295 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -388,7 +388,7 @@ config HID_LOGITECH_HIDPP Say Y if you want support for Logitech devices relying on the HID++ specification. Such devices are the various Logitech Touchpads (T650, T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar - Keayboard). + Keyboard). config LOGITECH_FF bool "Logitech force feedback support" -- cgit v0.10.2 From cbd366bea2b8513bc0fc1c9e8832cb0ab221d6d5 Mon Sep 17 00:00:00 2001 From: Ross Skaliotis Date: Sat, 20 Dec 2014 19:01:35 -0500 Subject: HID: apple: fix battery support for the 2009 ANSI wireless keyboard Enabled quirks necessary for correct battery capacity reporting. Cleaned up surrounding style. Signed-off-by: Ross Skaliotis Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e0a0f06..146da43 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -306,10 +306,13 @@ static enum power_supply_property hidinput_battery_props[] = { static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), -- cgit v0.10.2 From 8e7b341037db1835ee6eea64663013cbfcf33575 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 6 Jan 2015 22:34:19 +0100 Subject: HID: fixup the conflicting keyboard mappings quirk The ignore check that got added in 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") needs to properly check for VARIABLE reports as well (ARRAY reports should be ignored), otherwise legitimate keyboards might break. Cc: Fixes: 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") Reported-by: Fredrik Hallenberg Reported-by: David Herrmann Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 84b6899..a758900 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1113,6 +1113,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct */ if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_BUFFERED_BYTE)) && + (field->flags & HID_MAIN_ITEM_VARIABLE) && usage->usage_index < field->maxusage && value == field->value[usage->usage_index]) return; -- cgit v0.10.2 From 9da7dae94fb8adab5cc5f395640e30736a66e910 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Tue, 6 Jan 2015 17:29:29 +0100 Subject: workqueue.h: remove loops of single statement macros checkpatch.pl complained about two single statement macros in do while (0) loops. The loops and the trailing semicolons are now removed, which makes checkpatch happy and the two macros consistent with the rest of the file. Signed-off-by: Valentin Rothberg Signed-off-by: Tejun Heo diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index b996e6cd..74db135 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -220,14 +220,10 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; } #endif #define INIT_WORK(_work, _func) \ - do { \ - __INIT_WORK((_work), (_func), 0); \ - } while (0) + __INIT_WORK((_work), (_func), 0) #define INIT_WORK_ONSTACK(_work, _func) \ - do { \ - __INIT_WORK((_work), (_func), 1); \ - } while (0) + __INIT_WORK((_work), (_func), 1) #define __INIT_DELAYED_WORK(_work, _func, _tflags) \ do { \ -- cgit v0.10.2 From b2d8957f288e2e51085e7c468a05d5d98f0a785f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 29 Dec 2014 13:08:39 +0100 Subject: ALSA: sound/atmel/ac97c.c: Add device tree support This adds device tree support for the AC97 controller. It uses the soc-ac97link bindings, but actually only ac97-reset is used. Signed-off-by: Alexander Stein Acked-by: Alexandre Belloni Signed-off-by: Takashi Iwai diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 5e6a1db..cf4cedf 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -902,6 +905,40 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip) } } +#ifdef CONFIG_OF +static const struct of_device_id atmel_ac97c_dt_ids[] = { + { .compatible = "atmel,at91sam9263-ac97c", }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids); + +static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev) +{ + struct ac97c_platform_data *pdata; + struct device_node *node = dev->of_node; + const struct of_device_id *match; + + if (!node) { + dev_err(dev, "Device does not have associated DT data\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); + + return pdata; +} +#else +static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev) +{ + dev_err(dev, "no platform data defined\n"); + return ERR_PTR(-ENXIO); +} +#endif + static int atmel_ac97c_probe(struct platform_device *pdev) { struct snd_card *card; @@ -922,10 +959,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; } - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { - dev_dbg(&pdev->dev, "no platform data\n"); - return -ENXIO; + pdata = atmel_ac97c_probe_dt(&pdev->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } irq = platform_get_irq(pdev, 0); @@ -1204,6 +1242,7 @@ static struct platform_driver atmel_ac97c_driver = { .driver = { .name = "atmel_ac97c", .pm = ATMEL_AC97C_PM_OPS, + .of_match_table = of_match_ptr(atmel_ac97c_dt_ids), }, }; module_platform_driver(atmel_ac97c_driver); -- cgit v0.10.2 From e4a93be6cb281fb3dbbd41b22aee02cb0e551ba8 Mon Sep 17 00:00:00 2001 From: Oscar Forner Martinez Date: Tue, 6 Jan 2015 16:54:19 -0800 Subject: isofs: Fix bug in the way to check if the year is a leap year Changed the whole algorithm for a call to mktime64 that takes care of all that details. Signed-off-by: Oscar Forner Martinez Signed-off-by: Jan Kara diff --git a/fs/isofs/util.c b/fs/isofs/util.c index 01e1ee7..005a15c 100644 --- a/fs/isofs/util.c +++ b/fs/isofs/util.c @@ -2,6 +2,7 @@ * linux/fs/isofs/util.c */ +#include #include "isofs.h" /* @@ -17,9 +18,9 @@ int iso_date(char * p, int flag) { int year, month, day, hour, minute, second, tz; - int crtime, days, i; + int crtime; - year = p[0] - 70; + year = p[0]; month = p[1]; day = p[2]; hour = p[3]; @@ -31,18 +32,7 @@ int iso_date(char * p, int flag) if (year < 0) { crtime = 0; } else { - int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; - - days = year * 365; - if (year > 2) - days += (year+1) / 4; - for (i = 1; i < month; i++) - days += monlen[i-1]; - if (((year+2) % 4) == 0 && month > 2) - days++; - days += day - 1; - crtime = ((((days * 24) + hour) * 60 + minute) * 60) - + second; + crtime = mktime64(year+1900, month, day, hour, minute, second); /* sign extend */ if (tz & 0x80) -- cgit v0.10.2 From 5e7e9e90b5867a3754159a8ce524299d930fbac8 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Tue, 6 Jan 2015 18:32:51 -0800 Subject: HID: microsoft: add support for Japanese Surface Type Cover 3 Based on code for the US Surface Type Cover 3 from commit be3b16341d5cd8cf2a64fcc7a604a8efe6599ff0 ("HID: add support for MS Surface Pro 3 Type Cover"): Signed-off-by: Alan Wu Tested-by: Karlis Dreizis Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d0ac1..0cea5a0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -704,7 +704,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 && + (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; } @@ -1860,6 +1861,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7460f34..95ee91b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -653,6 +653,7 @@ #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc +#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index cacda43..fbaea6e 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -276,6 +276,8 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_DUPLICATE_USAGES }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), + .driver_data = MS_HIDINPUT }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index dc89be9..6591b5d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -80,6 +80,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v0.10.2 From ae9b56e3996dadbb59c727018f45486c06844261 Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Tue, 6 Jan 2015 23:13:47 +0530 Subject: EDAC, synps: Add EDAC support for zynq ddr ecc controller Add EDAC support for ecc errors reporting on the synopsys ddr controller. The ddr ecc controller corrects single bit errors and detects double bit errors. Selected important-ish notes from the changelog: - I have not taken care of spliting synps_edac_geterror_info function as it adds additional indentation levels and moreover the existing changes were made as part of the v2 review comments - Removed dt binding info as already there is a binding info available under memorycontroller. so, updated ecc info there. - Shortened the prefix "sysnopsys" to "synps" Signed-off-by: Punnaiah Choudary Kalluri Link: http://lkml.kernel.org/r/a728a8d4678f4dbf9de189a480297c3d@BY2FFO11FD034.protection.gbl [ Boris: massage commit message. ] Signed-off-by: Borislav Petkov diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8..375e248 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1583,6 +1583,7 @@ N: xilinx F: drivers/clocksource/cadence_ttc_timer.c F: drivers/i2c/busses/i2c-cadence.c F: drivers/mmc/host/sdhci-of-arasan.c +F: drivers/edac/synopsys_edac.c ARM SMMU DRIVER M: Will Deacon diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 49c2652..cb59619 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -385,4 +385,11 @@ config EDAC_ALTERA_MC preloader must initialize the SDRAM before loading the kernel. +config EDAC_SYNOPSYS + tristate "Synopsys DDR Memory Controller" + depends on EDAC_MM_EDAC && ARCH_ZYNQ + help + Support for error detection and correction on the Synopsys DDR + memory controller. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index d40c69a..b255f36 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -67,3 +67,4 @@ obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o +obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c new file mode 100644 index 0000000..1c96915 --- /dev/null +++ b/drivers/edac/synopsys_edac.c @@ -0,0 +1,535 @@ +/* + * Synopsys DDR ECC Driver + * This driver is based on ppc4xx_edac.c drivers + * + * Copyright (C) 2012 - 2014 Xilinx, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details + */ + +#include +#include +#include + +#include "edac_core.h" + +/* Number of cs_rows needed per memory controller */ +#define SYNPS_EDAC_NR_CSROWS 1 + +/* Number of channels per memory controller */ +#define SYNPS_EDAC_NR_CHANS 1 + +/* Granularity of reported error in bytes */ +#define SYNPS_EDAC_ERR_GRAIN 1 + +#define SYNPS_EDAC_MSG_SIZE 256 + +#define SYNPS_EDAC_MOD_STRING "synps_edac" +#define SYNPS_EDAC_MOD_VER "1" + +/* Synopsys DDR memory controller registers that are relevant to ECC */ +#define CTRL_OFST 0x0 +#define T_ZQ_OFST 0xA4 + +/* ECC control register */ +#define ECC_CTRL_OFST 0xC4 +/* ECC log register */ +#define CE_LOG_OFST 0xC8 +/* ECC address register */ +#define CE_ADDR_OFST 0xCC +/* ECC data[31:0] register */ +#define CE_DATA_31_0_OFST 0xD0 + +/* Uncorrectable error info registers */ +#define UE_LOG_OFST 0xDC +#define UE_ADDR_OFST 0xE0 +#define UE_DATA_31_0_OFST 0xE4 + +#define STAT_OFST 0xF0 +#define SCRUB_OFST 0xF4 + +/* Control register bit field definitions */ +#define CTRL_BW_MASK 0xC +#define CTRL_BW_SHIFT 2 + +#define DDRCTL_WDTH_16 1 +#define DDRCTL_WDTH_32 0 + +/* ZQ register bit field definitions */ +#define T_ZQ_DDRMODE_MASK 0x2 + +/* ECC control register bit field definitions */ +#define ECC_CTRL_CLR_CE_ERR 0x2 +#define ECC_CTRL_CLR_UE_ERR 0x1 + +/* ECC correctable/uncorrectable error log register definitions */ +#define LOG_VALID 0x1 +#define CE_LOG_BITPOS_MASK 0xFE +#define CE_LOG_BITPOS_SHIFT 1 + +/* ECC correctable/uncorrectable error address register definitions */ +#define ADDR_COL_MASK 0xFFF +#define ADDR_ROW_MASK 0xFFFF000 +#define ADDR_ROW_SHIFT 12 +#define ADDR_BANK_MASK 0x70000000 +#define ADDR_BANK_SHIFT 28 + +/* ECC statistic register definitions */ +#define STAT_UECNT_MASK 0xFF +#define STAT_CECNT_MASK 0xFF00 +#define STAT_CECNT_SHIFT 8 + +/* ECC scrub register definitions */ +#define SCRUB_MODE_MASK 0x7 +#define SCRUB_MODE_SECDED 0x4 + +/** + * struct ecc_error_info - ECC error log information + * @row: Row number + * @col: Column number + * @bank: Bank number + * @bitpos: Bit position + * @data: Data causing the error + */ +struct ecc_error_info { + u32 row; + u32 col; + u32 bank; + u32 bitpos; + u32 data; +}; + +/** + * struct synps_ecc_status - ECC status information to report + * @ce_cnt: Correctable error count + * @ue_cnt: Uncorrectable error count + * @ceinfo: Correctable error log information + * @ueinfo: Uncorrectable error log information + */ +struct synps_ecc_status { + u32 ce_cnt; + u32 ue_cnt; + struct ecc_error_info ceinfo; + struct ecc_error_info ueinfo; +}; + +/** + * struct synps_edac_priv - DDR memory controller private instance data + * @baseaddr: Base address of the DDR controller + * @message: Buffer for framing the event specific info + * @stat: ECC status information + * @ce_cnt: Correctable Error count + * @ue_cnt: Uncorrectable Error count + */ +struct synps_edac_priv { + void __iomem *baseaddr; + char message[SYNPS_EDAC_MSG_SIZE]; + struct synps_ecc_status stat; + u32 ce_cnt; + u32 ue_cnt; +}; + +/** + * synps_edac_geterror_info - Get the current ecc error info + * @base: Pointer to the base address of the ddr memory controller + * @p: Pointer to the synopsys ecc status structure + * + * Determines there is any ecc error or not + * + * Return: one if there is no error otherwise returns zero + */ +static int synps_edac_geterror_info(void __iomem *base, + struct synps_ecc_status *p) +{ + u32 regval, clearval = 0; + + regval = readl(base + STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT; + p->ue_cnt = regval & STAT_UECNT_MASK; + + regval = readl(base + CE_LOG_OFST); + if (!(p->ce_cnt && (regval & LOG_VALID))) + goto ue_err; + + p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT; + regval = readl(base + CE_ADDR_OFST); + p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT; + p->ceinfo.col = regval & ADDR_COL_MASK; + p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; + p->ceinfo.data = readl(base + CE_DATA_31_0_OFST); + edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos, + p->ceinfo.data); + clearval = ECC_CTRL_CLR_CE_ERR; + +ue_err: + regval = readl(base + UE_LOG_OFST); + if (!(p->ue_cnt && (regval & LOG_VALID))) + goto out; + + regval = readl(base + UE_ADDR_OFST); + p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT; + p->ueinfo.col = regval & ADDR_COL_MASK; + p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; + p->ueinfo.data = readl(base + UE_DATA_31_0_OFST); + clearval |= ECC_CTRL_CLR_UE_ERR; + +out: + writel(clearval, base + ECC_CTRL_OFST); + writel(0x0, base + ECC_CTRL_OFST); + + return 0; +} + +/** + * synps_edac_handle_error - Handle controller error types CE and UE + * @mci: Pointer to the edac memory controller instance + * @p: Pointer to the synopsys ecc status structure + * + * Handles the controller ECC correctable and un correctable error. + */ +static void synps_edac_handle_error(struct mem_ctl_info *mci, + struct synps_ecc_status *p) +{ + struct synps_edac_priv *priv = mci->pvt_info; + struct ecc_error_info *pinf; + + if (p->ce_cnt) { + pinf = &p->ceinfo; + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, + "DDR ECC error type :%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, + p->ce_cnt, 0, 0, 0, 0, 0, -1, + priv->message, ""); + } + + if (p->ue_cnt) { + pinf = &p->ueinfo; + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, + "DDR ECC error type :%s Row %d Bank %d Col %d ", + "UE", pinf->row, pinf->bank, pinf->col); + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, + p->ue_cnt, 0, 0, 0, 0, 0, -1, + priv->message, ""); + } + + memset(p, 0, sizeof(*p)); +} + +/** + * synps_edac_check - Check controller for ECC errors + * @mci: Pointer to the edac memory controller instance + * + * Used to check and post ECC errors. Called by the polling thread + */ +static void synps_edac_check(struct mem_ctl_info *mci) +{ + struct synps_edac_priv *priv = mci->pvt_info; + int status; + + status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + if (status) + return; + + priv->ce_cnt += priv->stat.ce_cnt; + priv->ue_cnt += priv->stat.ue_cnt; + synps_edac_handle_error(mci, &priv->stat); + + edac_dbg(3, "Total error count ce %d ue %d\n", + priv->ce_cnt, priv->ue_cnt); +} + +/** + * synps_edac_get_dtype - Return the controller memory width + * @base: Pointer to the ddr memory controller base address + * + * Get the EDAC device type width appropriate for the current controller + * configuration. + * + * Return: a device type width enumeration. + */ +static enum dev_type synps_edac_get_dtype(const void __iomem *base) +{ + enum dev_type dt; + u32 width; + + width = readl(base + CTRL_OFST); + width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT; + + switch (width) { + case DDRCTL_WDTH_16: + dt = DEV_X2; + break; + case DDRCTL_WDTH_32: + dt = DEV_X4; + break; + default: + dt = DEV_UNKNOWN; + } + + return dt; +} + +/** + * synps_edac_get_eccstate - Return the controller ecc enable/disable status + * @base: Pointer to the ddr memory controller base address + * + * Get the ECC enable/disable status for the controller + * + * Return: a ecc status boolean i.e true/false - enabled/disabled. + */ +static bool synps_edac_get_eccstate(void __iomem *base) +{ + enum dev_type dt; + u32 ecctype; + bool state = false; + + dt = synps_edac_get_dtype(base); + if (dt == DEV_UNKNOWN) + return state; + + ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK; + if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2)) + state = true; + + return state; +} + +/** + * synps_edac_get_memsize - reads the size of the attached memory device + * + * Return: the memory size in bytes + */ +static u32 synps_edac_get_memsize(void) +{ + struct sysinfo inf; + + si_meminfo(&inf); + + return inf.totalram * inf.mem_unit; +} + +/** + * synps_edac_get_mtype - Returns controller memory type + * @base: pointer to the synopsys ecc status structure + * + * Get the EDAC memory type appropriate for the current controller + * configuration. + * + * Return: a memory type enumeration. + */ +static enum mem_type synps_edac_get_mtype(const void __iomem *base) +{ + enum mem_type mt; + u32 memtype; + + memtype = readl(base + T_ZQ_OFST); + + if (memtype & T_ZQ_DDRMODE_MASK) + mt = MEM_DDR3; + else + mt = MEM_DDR2; + + return mt; +} + +/** + * synps_edac_init_csrows - Initialize the cs row data + * @mci: Pointer to the edac memory controller instance + * + * Initializes the chip select rows associated with the EDAC memory + * controller instance + * + * Return: Unconditionally 0. + */ +static int synps_edac_init_csrows(struct mem_ctl_info *mci) +{ + struct csrow_info *csi; + struct dimm_info *dimm; + struct synps_edac_priv *priv = mci->pvt_info; + u32 size; + int row, j; + + for (row = 0; row < mci->nr_csrows; row++) { + csi = mci->csrows[row]; + size = synps_edac_get_memsize(); + + for (j = 0; j < csi->nr_channels; j++) { + dimm = csi->channels[j]->dimm; + dimm->edac_mode = EDAC_FLAG_SECDED; + dimm->mtype = synps_edac_get_mtype(priv->baseaddr); + dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; + dimm->grain = SYNPS_EDAC_ERR_GRAIN; + dimm->dtype = synps_edac_get_dtype(priv->baseaddr); + } + } + + return 0; +} + +/** + * synps_edac_mc_init - Initialize driver instance + * @mci: Pointer to the edac memory controller instance + * @pdev: Pointer to the platform_device struct + * + * Performs initialization of the EDAC memory controller instance and + * related driver-private data associated with the memory controller the + * instance is bound to. + * + * Return: Always zero. + */ +static int synps_edac_mc_init(struct mem_ctl_info *mci, + struct platform_device *pdev) +{ + int status; + struct synps_edac_priv *priv; + + mci->pdev = &pdev->dev; + priv = mci->pvt_info; + platform_set_drvdata(pdev, mci); + + /* Initialize controller capabilities and configuration */ + mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->scrub_cap = SCRUB_HW_SRC; + mci->scrub_mode = SCRUB_NONE; + + mci->edac_cap = EDAC_FLAG_SECDED; + mci->ctl_name = "synps_ddr_controller"; + mci->dev_name = SYNPS_EDAC_MOD_STRING; + mci->mod_name = SYNPS_EDAC_MOD_VER; + mci->mod_ver = "1"; + + edac_op_state = EDAC_OPSTATE_POLL; + mci->edac_check = synps_edac_check; + mci->ctl_page_to_phys = NULL; + + status = synps_edac_init_csrows(mci); + + return status; +} + +/** + * synps_edac_mc_probe - Check controller and bind driver + * @pdev: Pointer to the platform_device struct + * + * Probes a specific controller instance for binding with the driver. + * + * Return: 0 if the controller instance was successfully bound to the + * driver; otherwise, < 0 on error. + */ +static int synps_edac_mc_probe(struct platform_device *pdev) +{ + struct mem_ctl_info *mci; + struct edac_mc_layer layers[2]; + struct synps_edac_priv *priv; + int rc; + struct resource *res; + void __iomem *baseaddr; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + baseaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(baseaddr)) + return PTR_ERR(baseaddr); + + if (!synps_edac_get_eccstate(baseaddr)) { + edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); + return -ENXIO; + } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = SYNPS_EDAC_NR_CSROWS; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = SYNPS_EDAC_NR_CHANS; + layers[1].is_virt_csrow = false; + + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, + sizeof(struct synps_edac_priv)); + if (!mci) { + edac_printk(KERN_ERR, EDAC_MC, + "Failed memory allocation for mc instance\n"); + return -ENOMEM; + } + + priv = mci->pvt_info; + priv->baseaddr = baseaddr; + rc = synps_edac_mc_init(mci, pdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, + "Failed to initialize instance\n"); + goto free_edac_mc; + } + + rc = edac_mc_add_mc(mci); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, + "Failed to register with EDAC core\n"); + goto free_edac_mc; + } + + /* + * Start capturing the correctable and uncorrectable errors. A write of + * 0 starts the counters. + */ + writel(0x0, baseaddr + ECC_CTRL_OFST); + return rc; + +free_edac_mc: + edac_mc_free(mci); + + return rc; +} + +/** + * synps_edac_mc_remove - Unbind driver from controller + * @pdev: Pointer to the platform_device struct + * + * Return: Unconditionally 0 + */ +static int synps_edac_mc_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + + return 0; +} + +static struct of_device_id synps_edac_match[] = { + { .compatible = "xlnx,zynq-ddrc-a05", }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, synps_edac_match); + +static struct platform_driver synps_edac_mc_driver = { + .driver = { + .name = "synopsys-edac", + .of_match_table = synps_edac_match, + }, + .probe = synps_edac_mc_probe, + .remove = synps_edac_mc_remove, +}; + +module_platform_driver(synps_edac_mc_driver); + +MODULE_AUTHOR("Xilinx Inc"); +MODULE_DESCRIPTION("Synopsys DDR ECC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 79144954278d4bb5989f8b903adcac7a20ff2a5a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 7 Jan 2015 13:46:16 +0100 Subject: udf: Remove repeated loads blocksize Store blocksize in a local variable in udf_fill_inode() since it is used a lot of times. Signed-off-by: Jan Kara diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 5bc71d9..95cb697 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1288,6 +1288,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) struct kernel_lb_addr *iloc = &iinfo->i_location; unsigned int link_count; unsigned int indirections = 0; + int bs = inode->i_sb->s_blocksize; int ret = -EIO; reread: @@ -1374,38 +1375,35 @@ reread: if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_EFE)) { iinfo->i_efe = 1; iinfo->i_use = 0; - ret = udf_alloc_i_data(inode, inode->i_sb->s_blocksize - + ret = udf_alloc_i_data(inode, bs - sizeof(struct extendedFileEntry)); if (ret) goto out; memcpy(iinfo->i_ext.i_data, bh->b_data + sizeof(struct extendedFileEntry), - inode->i_sb->s_blocksize - - sizeof(struct extendedFileEntry)); + bs - sizeof(struct extendedFileEntry)); } else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_FE)) { iinfo->i_efe = 0; iinfo->i_use = 0; - ret = udf_alloc_i_data(inode, inode->i_sb->s_blocksize - - sizeof(struct fileEntry)); + ret = udf_alloc_i_data(inode, bs - sizeof(struct fileEntry)); if (ret) goto out; memcpy(iinfo->i_ext.i_data, bh->b_data + sizeof(struct fileEntry), - inode->i_sb->s_blocksize - sizeof(struct fileEntry)); + bs - sizeof(struct fileEntry)); } else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_USE)) { iinfo->i_efe = 0; iinfo->i_use = 1; iinfo->i_lenAlloc = le32_to_cpu( ((struct unallocSpaceEntry *)bh->b_data)-> lengthAllocDescs); - ret = udf_alloc_i_data(inode, inode->i_sb->s_blocksize - + ret = udf_alloc_i_data(inode, bs - sizeof(struct unallocSpaceEntry)); if (ret) goto out; memcpy(iinfo->i_ext.i_data, bh->b_data + sizeof(struct unallocSpaceEntry), - inode->i_sb->s_blocksize - - sizeof(struct unallocSpaceEntry)); + bs - sizeof(struct unallocSpaceEntry)); return 0; } @@ -1498,8 +1496,7 @@ reread: if (iinfo->i_lenAlloc != inode->i_size) goto out; /* File in ICB has to fit in there... */ - if (inode->i_size > inode->i_sb->s_blocksize - - udf_file_entry_alloc_offset(inode)) + if (inode->i_size > bs - udf_file_entry_alloc_offset(inode)) goto out; } -- cgit v0.10.2 From 23b133bdc452aa441fcb9b82cbf6dd05cfd342d0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 7 Jan 2015 13:49:08 +0100 Subject: udf: Check length of extended attributes and allocation descriptors Check length of extended attributes and allocation descriptors when loading inodes from disk. Otherwise corrupted filesystems could confuse the code and make the kernel oops. Reported-by: Carl Henrik Lunde CC: stable@vger.kernel.org Signed-off-by: Jan Kara diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 95cb697..7b72b7d 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1487,6 +1487,15 @@ reread: } inode->i_generation = iinfo->i_unique; + /* + * Sanity check length of allocation descriptors and extended attrs to + * avoid integer overflows + */ + if (iinfo->i_lenEAttr > bs || iinfo->i_lenAlloc > bs) + goto out; + /* Now do exact checks */ + if (udf_file_entry_alloc_offset(inode) + iinfo->i_lenAlloc > bs) + goto out; /* Sanity checks for files in ICB so that we don't get confused later */ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { /* -- cgit v0.10.2 From 322b8af16f267a2bc027297ffa9b3b681325ed37 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 7 Jan 2015 14:41:58 +0100 Subject: ALSA: hda - Print codec->chip_name in autoconfig This will help end users figure out what HDA codec they have. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 1ede822..6ec3775 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -409,10 +409,10 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, /* * debug prints of the parsed results */ - codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", - cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[3], - cfg->line_out_pins[4], + codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", + codec->chip_name, cfg->line_outs, cfg->line_out_pins[0], + cfg->line_out_pins[1], cfg->line_out_pins[2], + cfg->line_out_pins[3], cfg->line_out_pins[4], cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? "speaker" : "line")); -- cgit v0.10.2 From 4f7946eca787baa0f66b4a508595b768a4772f3f Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 7 Jan 2015 14:41:59 +0100 Subject: ALSA: hda - Debug output which type of fixup was selected Our fixup system is becoming increasingly complex, so it's becoming time consuming to figure out which way the fix was applied. This patch adds a few debug prints to aid when debugging why a specific fixup was selected. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 6ec3775..3f8706b 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -920,6 +920,8 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, codec->fixup_id = pq->value; #ifdef CONFIG_SND_DEBUG_VERBOSE codec->fixup_name = pq->name; + codec_dbg(codec, "%s: picked fixup %s (pin match)\n", + codec->chip_name, codec->fixup_name); #endif codec->fixup_list = fixlist; return; @@ -960,6 +962,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_list = NULL; codec->fixup_name = NULL; codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP; + codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n", + codec->chip_name); return; } @@ -969,6 +973,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_id = models->id; codec->fixup_name = models->name; codec->fixup_list = fixlist; + codec_dbg(codec, "%s: picked fixup %s (model specified)\n", + codec->chip_name, codec->fixup_name); return; } models++; @@ -980,6 +986,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, id = q->value; #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; + codec_dbg(codec, "%s: picked fixup %s (PCI SSID%s)\n", + codec->chip_name, name, q->subdevice_mask ? "" : " - vendor generic"); #endif } } @@ -992,6 +1000,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, id = q->value; #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; + codec_dbg(codec, "%s: picked fixup %s (codec SSID)\n", + codec->chip_name, name); #endif break; } -- cgit v0.10.2 From 5618955c4269b07c8177f88a8075d4879e74cd27 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jan 2015 01:40:17 +0200 Subject: ALSA: fm801: move to pcim_* and devm_* functions The managed functions allow to get ->probe() and ->remove() simplier. This patch converts code to use managed functions. While here remove the dead code and fix the value printed in error message. [removed pci_release_regions() as it's managed in pcim_release(), too -- tiwai] Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index d167aff..dd6f23f 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1186,12 +1186,6 @@ static int snd_fm801_free(struct fm801 *chip) v4l2_device_unregister(&chip->v4l2_dev); } #endif - if (chip->irq >= 0) - free_irq(chip->irq, chip); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - - kfree(chip); return 0; } @@ -1214,28 +1208,23 @@ static int snd_fm801_create(struct snd_card *card, }; *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + if ((err = pcim_enable_device(pci)) < 0) return err; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); + chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL); + if (chip == NULL) return -ENOMEM; - } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; chip->irq = -1; chip->tea575x_tuner = tea575x_tuner; - if ((err = pci_request_regions(pci, "FM801")) < 0) { - kfree(chip); - pci_disable_device(pci); + if ((err = pci_request_regions(pci, "FM801")) < 0) return err; - } chip->port = pci_resource_start(pci, 0); if ((tea575x_tuner & TUNER_ONLY) == 0) { - if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { - dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq); + if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip)) { + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_fm801_free(chip); return -EBUSY; } @@ -1250,12 +1239,6 @@ static int snd_fm801_create(struct snd_card *card, /* init might set tuner access method */ tea575x_tuner = chip->tea575x_tuner; - if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) { - pci_clear_master(pci); - free_irq(chip->irq, chip); - chip->irq = -1; - } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); return err; -- cgit v0.10.2 From 33f4acd3b214fee9662cbaf569a4876b8604f152 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 7 Jan 2015 15:50:13 +0100 Subject: ALSA: hda - Enable mic mute hotkey and LEDs for an HP machine On this machine, the mic mute hotkey is connected to GPIO2. We therefore create an extra input device for this key. Also enable LEDs connected to GPIO3 and GPIO4. (Note: if this patch is backported to older kernels, where KEY_MIC_MUTE is not available, change the KEY_MIC_MUTE to KEY_F20, which was previously used for mic mute keys.) BugLink: https://bugs.launchpad.net/bugs/1408295 Tested-by: Keng-Yu Lin Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 65f1f4e..09d2131 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include "hda_codec.h" @@ -120,6 +121,9 @@ struct alc_spec { hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; +#if IS_ENABLED(CONFIG_INPUT) + struct input_dev *kb_dev; +#endif }; /* @@ -3472,6 +3476,84 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, } } +#if IS_ENABLED(CONFIG_INPUT) +static void gpio2_mic_hotkey_event(struct hda_codec *codec, + struct hda_jack_callback *event) +{ + struct alc_spec *spec = codec->spec; + + /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore + send both key on and key off event for every interrupt. */ + input_report_key(spec->kb_dev, KEY_MICMUTE, 1); + input_sync(spec->kb_dev); + input_report_key(spec->kb_dev, KEY_MICMUTE, 0); + input_sync(spec->kb_dev); +} +#endif + +static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ +#if IS_ENABLED(CONFIG_INPUT) + /* GPIO1 = set according to SKU external amp + GPIO2 = mic mute hotkey + GPIO3 = mute LED + GPIO4 = mic mute LED */ + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a }, + { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 }, + {} + }; + + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->kb_dev = input_allocate_device(); + if (!spec->kb_dev) { + codec_err(codec, "Out of memory (input_allocate_device)\n"); + return; + } + spec->kb_dev->name = "Microphone Mute Button"; + spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY); + spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE); + if (input_register_device(spec->kb_dev)) { + codec_err(codec, "input_register_device failed\n"); + input_free_device(spec->kb_dev); + spec->kb_dev = NULL; + return; + } + + snd_hda_add_verbs(codec, gpio_init); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04); + snd_hda_jack_detect_enable_callback(codec, codec->afg, + gpio2_mic_hotkey_event); + + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; + spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; + spec->gpio_mic_led_mask = 0x10; + return; + } + + if (!spec->kb_dev) + return; + + switch (action) { + case HDA_FIXUP_ACT_PROBE: + spec->init_amp = ALC_INIT_DEFAULT; + break; + case HDA_FIXUP_ACT_FREE: + input_unregister_device(spec->kb_dev); + input_free_device(spec->kb_dev); + spec->kb_dev = NULL; + } +#endif +} + static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -4341,6 +4423,7 @@ enum { ALC282_FIXUP_ASPIRE_V5_PINS, ALC280_FIXUP_HP_GPIO4, ALC286_FIXUP_HP_GPIO_LED, + ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, }; static const struct hda_fixup alc269_fixups[] = { @@ -4814,6 +4897,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc286_fixup_hp_gpio_led, }, + [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc280_fixup_hp_gpio2_mic_hotkey, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4843,6 +4930,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY), /* ALC282 */ SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), -- cgit v0.10.2 From 9d9acda9ba956a5d37e61e0ce6c579a67610bd05 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Wed, 7 Jan 2015 00:44:52 -0500 Subject: libata: Remove FIXME comment in atapi_eh_request_sense Remove the FIXME comment in atapi_eh_request_sense () asking whether memset of sense buffer is necessary. The buffer may be partially or fully filled by the device. We want it to be cleared. Signed-off-by: Nicholas Krause Signed-off-by: Tejun Heo diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8d00c26..a9f5aed 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1635,7 +1635,6 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev, DPRINTK("ATAPI request sense\n"); - /* FIXME: is this needed? */ memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); /* initialize sense_buf with the error register, -- cgit v0.10.2 From d4812e169de44f4ab53ff671c6193c67de24da62 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Mon, 5 Jan 2015 16:44:42 -0800 Subject: x86, mce: Get rid of TIF_MCE_NOTIFY and associated mce tricks We now switch to the kernel stack when a machine check interrupts during user mode. This means that we can perform recovery actions in the tail of do_machine_check() Acked-by: Borislav Petkov Signed-off-by: Tony Luck Signed-off-by: Andy Lutomirski diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 51b26e89..9b3de99 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -190,7 +190,6 @@ enum mcp_flags { void machine_check_poll(enum mcp_flags flags, mce_banks_t *b); int mce_notify_irq(void); -void mce_notify_process(void); DECLARE_PER_CPU(struct mce, injectm); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 8b13b0fb..e82e95a 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -75,7 +75,6 @@ struct thread_info { #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ -#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ #define TIF_UPROBE 12 /* breakpointed or singlestepping */ #define TIF_NOTSC 16 /* TSC is not accessible in userland */ @@ -100,7 +99,6 @@ struct thread_info { #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) -#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) #define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) #define _TIF_UPROBE (1 << TIF_UPROBE) #define _TIF_NOTSC (1 << TIF_NOTSC) @@ -140,7 +138,7 @@ struct thread_info { /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ - (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \ + (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \ _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE) /* flags to check in __switch_to() */ diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 800d423..d231799 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1004,51 +1004,6 @@ static void mce_clear_state(unsigned long *toclear) } /* - * Need to save faulting physical address associated with a process - * in the machine check handler some place where we can grab it back - * later in mce_notify_process() - */ -#define MCE_INFO_MAX 16 - -struct mce_info { - atomic_t inuse; - struct task_struct *t; - __u64 paddr; - int restartable; -} mce_info[MCE_INFO_MAX]; - -static void mce_save_info(__u64 addr, int c) -{ - struct mce_info *mi; - - for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) { - if (atomic_cmpxchg(&mi->inuse, 0, 1) == 0) { - mi->t = current; - mi->paddr = addr; - mi->restartable = c; - return; - } - } - - mce_panic("Too many concurrent recoverable errors", NULL, NULL); -} - -static struct mce_info *mce_find_info(void) -{ - struct mce_info *mi; - - for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) - if (atomic_read(&mi->inuse) && mi->t == current) - return mi; - return NULL; -} - -static void mce_clear_info(struct mce_info *mi) -{ - atomic_set(&mi->inuse, 0); -} - -/* * The actual machine check handler. This only handles real * exceptions when something got corrupted coming in through int 18. * @@ -1086,6 +1041,8 @@ void do_machine_check(struct pt_regs *regs, long error_code) DECLARE_BITMAP(toclear, MAX_NR_BANKS); DECLARE_BITMAP(valid_banks, MAX_NR_BANKS); char *msg = "Unknown"; + u64 recover_paddr = ~0ull; + int flags = MF_ACTION_REQUIRED; prev_state = ist_enter(regs); @@ -1207,9 +1164,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) if (no_way_out) mce_panic("Fatal machine check on current CPU", &m, msg); if (worst == MCE_AR_SEVERITY) { - /* schedule action before return to userland */ - mce_save_info(m.addr, m.mcgstatus & MCG_STATUS_RIPV); - set_thread_flag(TIF_MCE_NOTIFY); + recover_paddr = m.addr; + if (!(m.mcgstatus & MCG_STATUS_RIPV)) + flags |= MF_MUST_KILL; } else if (kill_it) { force_sig(SIGBUS, current); } @@ -1220,6 +1177,26 @@ void do_machine_check(struct pt_regs *regs, long error_code) mce_wrmsrl(MSR_IA32_MCG_STATUS, 0); out: sync_core(); + + if (recover_paddr == ~0ull) + goto done; + + pr_err("Uncorrected hardware memory error in user-access at %llx", + recover_paddr); + /* + * We must call memory_failure() here even if the current process is + * doomed. We still need to mark the page as poisoned and alert any + * other users of the page. + */ + ist_begin_non_atomic(regs); + local_irq_enable(); + if (memory_failure(recover_paddr >> PAGE_SHIFT, MCE_VECTOR, flags) < 0) { + pr_err("Memory error not recovered"); + force_sig(SIGBUS, current); + } + local_irq_disable(); + ist_end_non_atomic(); +done: ist_exit(regs, prev_state); } EXPORT_SYMBOL_GPL(do_machine_check); @@ -1238,42 +1215,6 @@ int memory_failure(unsigned long pfn, int vector, int flags) #endif /* - * Called in process context that interrupted by MCE and marked with - * TIF_MCE_NOTIFY, just before returning to erroneous userland. - * This code is allowed to sleep. - * Attempt possible recovery such as calling the high level VM handler to - * process any corrupted pages, and kill/signal current process if required. - * Action required errors are handled here. - */ -void mce_notify_process(void) -{ - unsigned long pfn; - struct mce_info *mi = mce_find_info(); - int flags = MF_ACTION_REQUIRED; - - if (!mi) - mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL); - pfn = mi->paddr >> PAGE_SHIFT; - - clear_thread_flag(TIF_MCE_NOTIFY); - - pr_err("Uncorrected hardware memory error in user-access at %llx", - mi->paddr); - /* - * We must call memory_failure() here even if the current process is - * doomed. We still need to mark the page as poisoned and alert any - * other users of the page. - */ - if (!mi->restartable) - flags |= MF_MUST_KILL; - if (memory_failure(pfn, MCE_VECTOR, flags) < 0) { - pr_err("Memory error not recovered"); - force_sig(SIGBUS, current); - } - mce_clear_info(mi); -} - -/* * Action optional processing happens here (picking up * from the list of faulting pages that do_machine_check() * placed into the "ring"). diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index ed37a76..2a33c8f 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -740,12 +740,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { user_exit(); -#ifdef CONFIG_X86_MCE - /* notify userspace of pending MCEs */ - if (thread_info_flags & _TIF_MCE_NOTIFY) - mce_notify_process(); -#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ - if (thread_info_flags & _TIF_UPROBE) uprobe_notify_resume(regs); -- cgit v0.10.2 From 432fbf3c6a856726f21011edfd53311bf373dba9 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 4 Sep 2014 17:12:49 -0700 Subject: documentation: Record limitations of bitfields and small variables This commit documents the fact that it is not safe to use bitfields as shared variables in synchronization algorithms. It also documents that CPUs must be able to concurrently load from and store to adjacent one-byte and two-byte variables, which is in fact required by the C11 standard (Section 3.14). Signed-off-by: Paul E. McKenney diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 70a09f8..a10f7cd 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -269,6 +269,50 @@ And there are a number of things that _must_ or _must_not_ be assumed: STORE *(A + 4) = Y; STORE *A = X; STORE {*A, *(A + 4) } = {X, Y}; +And there are anti-guarantees: + + (*) These guarantees do not apply to bitfields, because compilers often + generate code to modify these using non-atomic read-modify-write + sequences. Do not attempt to use bitfields to synchronize parallel + algorithms. + + (*) Even in cases where bitfields are protected by locks, all fields + in a given bitfield must be protected by one lock. If two fields + in a given bitfield are protected by different locks, the compiler's + non-atomic read-modify-write sequences can cause an update to one + field to corrupt the value of an adjacent field. + + (*) These guarantees apply only to properly aligned and sized scalar + variables. "Properly sized" currently means variables that are + the same size as "char", "short", "int" and "long". "Properly + aligned" means the natural alignment, thus no constraints for + "char", two-byte alignment for "short", four-byte alignment for + "int", and either four-byte or eight-byte alignment for "long", + on 32-bit and 64-bit systems, respectively. Note that these + guarantees were introduced into the C11 standard, so beware when + using older pre-C11 compilers (for example, gcc 4.6). The portion + of the standard containing this guarantee is Section 3.14, which + defines "memory location" as follows: + + memory location + either an object of scalar type, or a maximal sequence + of adjacent bit-fields all having nonzero width + + NOTE 1: Two threads of execution can update and access + separate memory locations without interfering with + each other. + + NOTE 2: A bit-field and an adjacent non-bit-field member + are in separate memory locations. The same applies + to two bit-fields, if one is declared inside a nested + structure declaration and the other is not, or if the two + are separated by a zero-length bit-field declaration, + or if they are separated by a non-bit-field member + declaration. It is not safe to concurrently update two + bit-fields in the same structure if all members declared + between them are also bit-fields, no matter what the + sizes of those intervening bit-fields happen to be. + ========================= WHAT ARE MEMORY BARRIERS? -- cgit v0.10.2 From d87510c5a6e34e84835814b7b8c319918171276e Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Sun, 28 Dec 2014 01:11:16 -0800 Subject: documentation: Fix smp typo in memory-barriers.txt Signed-off-by: Davidlohr Bueso Signed-off-by: Paul E. McKenney diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index a10f7cd..ca2387e 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -794,7 +794,7 @@ In summary: However, they do -not- guarantee any other sort of ordering: Not prior loads against later loads, nor prior stores against later anything. If you need these other forms of ordering, - use smb_rmb(), smp_wmb(), or, in the case of prior stores and + use smp_rmb(), smp_wmb(), or, in the case of prior stores and later loads, smp_mb(). (*) If both legs of the "if" statement begin with identical stores -- cgit v0.10.2 From c8935ef0f2a8e8c5c440c62fb194d40c4415f456 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 7 Jan 2015 16:37:25 +0100 Subject: spi: sh-msiof: Use async pm_runtime_put() in sh_msiof_spi_setup() There's no need to use the synchronous version. Reported-by: Sergei Shtylyov Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index c58c249..9a884e6 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -546,7 +546,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi) gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - pm_runtime_put_sync(&p->pdev->dev); + pm_runtime_put(&p->pdev->dev); return 0; } -- cgit v0.10.2 From b7ed9f1d26f04272127a98248338177e5bac233e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 7 Jan 2015 10:19:06 +0800 Subject: ASoC: rt5670: redefine ASRC control registers 0x84 and 0x85 The previous definition of registers 0x84 and 0x85 doesn't match the datasheet. So this patch removes the wrong definition and writes a new one for the two registers. Signed-off-by: Bard Liao Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index d11b9c2..ec38d8f 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1023,50 +1023,33 @@ #define RT5670_DMIC_2_M_NOR (0x0 << 8) #define RT5670_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5670_CLK_SEL_SYS (0x0) +#define RT5670_CLK_SEL_I2S1_ASRC (0x1) +#define RT5670_CLK_SEL_I2S2_ASRC (0x2) +#define RT5670_CLK_SEL_I2S3_ASRC (0x3) +#define RT5670_CLK_SEL_SYS2 (0x5) +#define RT5670_CLK_SEL_SYS3 (0x6) + /* ASRC Control 2 (0x84) */ -#define RT5670_MDA_L_M_MASK (0x1 << 15) -#define RT5670_MDA_L_M_SFT 15 -#define RT5670_MDA_L_M_NOR (0x0 << 15) -#define RT5670_MDA_L_M_ASYN (0x1 << 15) -#define RT5670_MDA_R_M_MASK (0x1 << 14) -#define RT5670_MDA_R_M_SFT 14 -#define RT5670_MDA_R_M_NOR (0x0 << 14) -#define RT5670_MDA_R_M_ASYN (0x1 << 14) -#define RT5670_MAD_L_M_MASK (0x1 << 13) -#define RT5670_MAD_L_M_SFT 13 -#define RT5670_MAD_L_M_NOR (0x0 << 13) -#define RT5670_MAD_L_M_ASYN (0x1 << 13) -#define RT5670_MAD_R_M_MASK (0x1 << 12) -#define RT5670_MAD_R_M_SFT 12 -#define RT5670_MAD_R_M_NOR (0x0 << 12) -#define RT5670_MAD_R_M_ASYN (0x1 << 12) -#define RT5670_ADC_M_MASK (0x1 << 11) -#define RT5670_ADC_M_SFT 11 -#define RT5670_ADC_M_NOR (0x0 << 11) -#define RT5670_ADC_M_ASYN (0x1 << 11) -#define RT5670_STO_DAC_M_MASK (0x1 << 5) -#define RT5670_STO_DAC_M_SFT 5 -#define RT5670_STO_DAC_M_NOR (0x0 << 5) -#define RT5670_STO_DAC_M_ASYN (0x1 << 5) -#define RT5670_I2S1_R_D_MASK (0x1 << 4) -#define RT5670_I2S1_R_D_SFT 4 -#define RT5670_I2S1_R_D_DIS (0x0 << 4) -#define RT5670_I2S1_R_D_EN (0x1 << 4) -#define RT5670_I2S2_R_D_MASK (0x1 << 3) -#define RT5670_I2S2_R_D_SFT 3 -#define RT5670_I2S2_R_D_DIS (0x0 << 3) -#define RT5670_I2S2_R_D_EN (0x1 << 3) -#define RT5670_PRE_SCLK_MASK (0x3) -#define RT5670_PRE_SCLK_SFT 0 -#define RT5670_PRE_SCLK_512 (0x0) -#define RT5670_PRE_SCLK_1024 (0x1) -#define RT5670_PRE_SCLK_2048 (0x2) +#define RT5670_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5670_DA_STO_CLK_SEL_SFT 12 +#define RT5670_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5670_DA_MONOL_CLK_SEL_SFT 8 +#define RT5670_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5670_DA_MONOR_CLK_SEL_SFT 4 +#define RT5670_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5670_I2S1_RATE_MASK (0xf << 12) -#define RT5670_I2S1_RATE_SFT 12 -#define RT5670_I2S2_RATE_MASK (0xf << 8) -#define RT5670_I2S2_RATE_SFT 8 +#define RT5670_UP_CLK_SEL_MASK (0xf << 12) +#define RT5670_UP_CLK_SEL_SFT 12 +#define RT5670_DOWN_CLK_SEL_MASK (0xf << 8) +#define RT5670_DOWN_CLK_SEL_SFT 8 +#define RT5670_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5670_AD_MONOL_CLK_SEL_SFT 4 +#define RT5670_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5670_I2S1_PD_MASK (0x7 << 12) -- cgit v0.10.2 From e8c47ba3cadcc3649f18e4710804bb6c3791eac2 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 7 Jan 2015 10:19:12 +0800 Subject: ASoC: rt5670: add API to select ASRC clock source When codec is in slave mode, ASRC can suppress noise for asynchronous MCLK and LRCLK or special I2S format. This patch defines an API to select the clock source for specified filters. And the codec driver will turn on ASRC for these filters if ASRC is selected as their clock source. Signed-off-by: Bard Liao Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0a027bc..0632b74 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -590,6 +590,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source, return 0; } + +/** + * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0, asrc2_value = 0; + unsigned int asrc3_mask = 0, asrc3_value = 0; + + if (clk_src > RT5670_CLK_SEL_SYS3) + return -EINVAL; + + if (filter_mask & RT5670_DA_STEREO_FILTER) { + asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5670_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_L_FILTER) { + asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_R_FILTER) { + asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_STEREO_FILTER) { + asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_L_FILTER) { + asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_R_FILTER) { + asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_UP_RATE_FILTER) { + asrc3_mask |= RT5670_UP_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK) + | (clk_src << RT5670_UP_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DOWN_RATE_FILTER) { + asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK) + | (clk_src << RT5670_DOWN_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5670_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5670_ASRC_3, + asrc3_mask, asrc3_value); + return 0; +} +EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index ec38d8f..21f8e18 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1966,6 +1966,21 @@ enum { RT5670_DMIC_DATA_GPIO5, }; +/* filter mask */ +enum { + RT5670_DA_STEREO_FILTER = 0x1, + RT5670_DA_MONO_L_FILTER = (0x1 << 1), + RT5670_DA_MONO_R_FILTER = (0x1 << 2), + RT5670_AD_STEREO_FILTER = (0x1 << 3), + RT5670_AD_MONO_L_FILTER = (0x1 << 4), + RT5670_AD_MONO_R_FILTER = (0x1 << 5), + RT5670_UP_RATE_FILTER = (0x1 << 6), + RT5670_DOWN_RATE_FILTER = (0x1 << 7), +}; + +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5670_priv { struct snd_soc_codec *codec; struct rt5670_platform_data pdata; -- cgit v0.10.2 From eb55fab997c0bf1b1ddf0a7199da0ceb18432b96 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 7 Jan 2015 10:19:23 +0800 Subject: ASoC: Intel: Select RT5672 ASRC clock source on Cherrytrail and Braswell On Cherrytrail and Braswell, the I2S BCLK is 100FS which cannot be supported by RT5672 in slave mode and can cause noise. This patch selects codec ASRC clock source to track I2S1 clock so that codec ASRC can be enabled to suppress the noise. Signed-off-by: Mengdong Lin Reviewed-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index a406c610..ff01662 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -140,6 +140,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_dai *codec_dai = runtime->codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); @@ -148,6 +149,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } + /* Select codec ASRC clock source to track I2S1 clock, because codec + * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot + * be supported by RT5672. Otherwise, ASRC will be disabled and cause + * noise. + */ + rt5670_sel_asrc_clk_src(codec, + RT5670_DA_STEREO_FILTER + | RT5670_DA_MONO_L_FILTER + | RT5670_DA_MONO_R_FILTER + | RT5670_AD_STEREO_FILTER + | RT5670_AD_MONO_L_FILTER + | RT5670_AD_MONO_R_FILTER, + RT5670_CLK_SEL_I2S1_ASRC); return 0; } -- cgit v0.10.2 From 30b4b703a5d5aa9977f5ad3aba3d77b6b8d0d255 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jan 2015 16:56:55 +0200 Subject: spi: dw: print debug message with FIFO size When autodetection is used it would be useful to know what the FIFO size is. The patch adds a debug message for this purpose. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 8edcd1b..5a97a62 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -608,7 +608,7 @@ static void dw_spi_cleanup(struct spi_device *spi) } /* Restart the controller, disable all interrupts, clean rx fifo */ -static void spi_hw_init(struct dw_spi *dws) +static void spi_hw_init(struct device *dev, struct dw_spi *dws) { spi_enable_chip(dws, 0); spi_mask_intr(dws, 0xff); @@ -626,9 +626,10 @@ static void spi_hw_init(struct dw_spi *dws) if (fifo != dw_readw(dws, DW_SPI_TXFLTR)) break; } + dw_writew(dws, DW_SPI_TXFLTR, 0); dws->fifo_len = (fifo == 2) ? 0 : fifo - 1; - dw_writew(dws, DW_SPI_TXFLTR, 0); + dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); } } @@ -668,7 +669,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->dev.of_node = dev->of_node; /* Basic HW init */ - spi_hw_init(dws); + spi_hw_init(dev, dws); if (dws->dma_ops && dws->dma_ops->dma_init) { ret = dws->dma_ops->dma_init(dws); @@ -731,7 +732,7 @@ int dw_spi_resume_host(struct dw_spi *dws) { int ret; - spi_hw_init(dws); + spi_hw_init(&dws->master->dev, dws); ret = spi_master_resume(dws->master); if (ret) dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); -- cgit v0.10.2 From d58cf5ff6500522880683ce90d9caa79af385ed8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jan 2015 17:15:00 +0200 Subject: spi: dw-pci: describe Intel MID controllers better There are more that one SPI controller on the Intel MID boards. This patch describes the status and IDs of them. From now on we also have to care about bus number that must be unique per host. According to the specification the SPI1 has 5 bits for chip selects and SPI2 only 2 bits. The patch makes it depend to PCI ID. The first controller (SPI1) is DMA capable, meanwhile SPI2 can share same channels (via software switch) such functionality is not in the scope of this patch. Thus, attempt to init DMA for SPI2 will always fail for now. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 44b9271..852aa4c 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -293,7 +293,6 @@ static void mrst_power_off_unused_dev(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev); /* diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index a67d37c..47a8e65 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -270,8 +270,6 @@ int dw_spi_mid_init(struct dw_spi *dws) dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1); iounmap(clk_reg); - dws->num_cs = 16; - #ifdef CONFIG_SPI_DW_MID_DMA dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL); if (!dws->dma_priv) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index ba68da1..64f3efa 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -30,10 +30,20 @@ struct dw_spi_pci { struct spi_pci_desc { int (*setup)(struct dw_spi *); + u16 num_cs; + u16 bus_num; }; -static struct spi_pci_desc spi_pci_mid_desc = { +static struct spi_pci_desc spi_pci_mid_desc_1 = { .setup = dw_spi_mid_init, + .num_cs = 32, + .bus_num = 0, +}; + +static struct spi_pci_desc spi_pci_mid_desc_2 = { + .setup = dw_spi_mid_init, + .num_cs = 4, + .bus_num = 1, }; static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -65,18 +75,23 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dws->regs = pcim_iomap_table(pdev)[pci_bar]; - dws->bus_num = 0; - dws->num_cs = 4; dws->irq = pdev->irq; /* * Specific handling for paltforms, like dma setup, * clock rate, FIFO depth. */ - if (desc && desc->setup) { - ret = desc->setup(dws); - if (ret) - return ret; + if (desc) { + if (desc->setup) { + ret = desc->setup(dws); + if (ret) + return ret; + } + + dws->num_cs = desc->num_cs; + dws->bus_num = desc->bus_num; + } else { + return -ENODEV; } ret = dw_spi_add_host(&pdev->dev, dws); @@ -121,7 +136,14 @@ static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); static const struct pci_device_id pci_ids[] = { /* Intel MID platform SPI controller 0 */ - { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc}, + /* + * The access to the device 8086:0801 is disabled by HW, since it's + * exclusively used by SCU to communicate with MSIC. + */ + /* Intel MID platform SPI controller 1 */ + { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1}, + /* Intel MID platform SPI controller 2 */ + { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2}, {}, }; -- cgit v0.10.2 From ce64c8b9cf5be2a93508af4667110dbe90904557 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 6 Jan 2015 15:17:20 +0100 Subject: ASoC: Add helper function for changing the DAI link format For some setups it is necessary to change the DAI link format at runtime. This patch factors out the code that does the initial static DAI link format configuration into a separate helper function which can be used board drivers as well. This allows board drivers that have to change the DAI link format at runtime to reuse it instead of having to manually change the format on all DAIs. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index b4fca9a..edd4a0a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -429,6 +429,9 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd); void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream); void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream); +int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, + unsigned int dai_fmt); + /* Utility functions to get clock rates from various things */ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 985052b..80ea358 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1427,11 +1427,75 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) return 0; } +/** + * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime + * @rtd: The runtime for which the DAI link format should be changed + * @dai_fmt: The new DAI link format + * + * This function updates the DAI link format for all DAIs connected to the DAI + * link for the specified runtime. + * + * Note: For setups with a static format set the dai_fmt field in the + * corresponding snd_dai_link struct instead of using this function. + * + * Returns 0 on success, otherwise a negative error code. + */ +int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, + unsigned int dai_fmt) +{ + struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int i; + int ret; + + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = codec_dais[i]; + + ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); + if (ret != 0 && ret != -ENOTSUPP) { + dev_warn(codec_dai->dev, + "ASoC: Failed to set DAI format: %d\n", ret); + return ret; + } + } + + /* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */ + if (cpu_dai->codec) { + unsigned int inv_dai_fmt; + + inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK; + switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + break; + case SND_SOC_DAIFMT_CBM_CFS: + inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; + break; + case SND_SOC_DAIFMT_CBS_CFM: + inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; + break; + case SND_SOC_DAIFMT_CBS_CFS: + inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + break; + } + + dai_fmt = inv_dai_fmt; + } + + ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); + if (ret != 0 && ret != -ENOTSUPP) { + dev_warn(cpu_dai->dev, + "ASoC: Failed to set DAI format: %d\n", ret); + return ret; + } + + return 0; +} + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; - struct snd_soc_dai_link *dai_link; - int ret, i, order, dai_fmt; + int ret, i, order; mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); @@ -1542,60 +1606,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) card->num_dapm_routes); for (i = 0; i < card->num_links; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; - dai_link = &card->dai_link[i]; - dai_fmt = dai_link->dai_fmt; - - if (dai_fmt) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; - int j; - - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = codec_dais[j]; - - ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(codec_dai->dev, - "ASoC: Failed to set DAI format: %d\n", - ret); - } - } - - /* If this is a regular CPU link there will be a platform */ - if (dai_fmt && - (dai_link->platform_name || dai_link->platform_of_node)) { - ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai, - dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(card->rtd[i].cpu_dai->dev, - "ASoC: Failed to set DAI format: %d\n", - ret); - } else if (dai_fmt) { - /* Flip the polarity for the "CPU" end */ - dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; - switch (dai_link->dai_fmt & - SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; - break; - case SND_SOC_DAIFMT_CBM_CFS: - dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; - break; - case SND_SOC_DAIFMT_CBS_CFM: - dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; - break; - case SND_SOC_DAIFMT_CBS_CFS: - dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - break; - } - - ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai, - dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(card->rtd[i].cpu_dai->dev, - "ASoC: Failed to set DAI format: %d\n", - ret); - } + if (card->dai_link[i].dai_fmt) + snd_soc_runtime_set_dai_fmt(&card->rtd[i], + card->dai_link[i].dai_fmt); } snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), -- cgit v0.10.2 From dc1b36b24990b9d87c6de88819c112c4db91dbc8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 6 Jan 2015 15:17:21 +0100 Subject: ASoC: omap-twl4030: Use snd_soc_runtime_set_dai_fmt() Use snd_soc_runtime_set_dai_fmt() to configure the format for the DAI link rather than configuring each DAI individually. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index 5e551c7..fb1f6bb 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -53,11 +53,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_card *card = rtd->card; unsigned int fmt; - int ret; switch (params_channels(params)) { case 2: /* Stereo I2S mode */ @@ -74,21 +70,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) { - dev_err(card->dev, "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) { - dev_err(card->dev, "can't set cpu DAI configuration\n"); - return ret; - } - - return 0; + return snd_soc_runtime_set_dai_fmt(rtd, fmt); } static struct snd_soc_ops omap_twl4030_ops = { -- cgit v0.10.2 From c853679a51b9bb76a3e06e64a0b4c6276f391921 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 6 Jan 2015 15:17:22 +0100 Subject: ASoC: mop500_ab8500: Use snd_soc_runtime_set_dai_fmt() Use snd_soc_runtime_set_dai_fmt() to configure the format for the DAI link rather than configuring each DAI individually. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index be4f1ac7..aa65370 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -290,21 +290,9 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream, SND_SOC_DAIFMT_GATED; } - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) { - dev_err(dev, - "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n", - __func__, ret); - return ret; - } - - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) { - dev_err(dev, - "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n", - __func__, ret); + ret = snd_soc_runtime_set_dai_fmt(rtd, fmt); + if (ret) return ret; - } /* Setup TDM-slots */ -- cgit v0.10.2 From a37f1b8fdc912600c24f9d0d45d7046e50a031e4 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Tue, 30 Dec 2014 11:12:35 -0800 Subject: ASoC: tegra: Add platform driver for rt5677 audio codec The driver supports NVIDIA Tegra Ryu board Sponsored: Google ChromeOS Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt new file mode 100644 index 0000000..a4589cd --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt @@ -0,0 +1,67 @@ +NVIDIA Tegra audio complex, with RT5677 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-rt5677" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the RT5677's pins (as documented in its binding), and the jacks + on the board: + + * Headphone + * Speaker + * Headset Mic + * Internal Mic 1 + * Internal Mic 2 + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding + assumes that AIF1 on the CODEC is connected to Tegra. + +Optional properties: +- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in +- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier +- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in +- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal + +Example: + +sound { + compatible = "nvidia,tegra-audio-rt5677-ryu", + "nvidia,tegra-audio-rt5677"; + nvidia,model = "NVIDIA Tegra Ryu"; + + nvidia,audio-routing = + "Headphone", "LOUT2", + "Headphone", "LOUT1", + "Headset Mic", "MICBIAS1", + "IN1P", "Headset Mic", + "IN1N", "Headset Mic", + "DMIC L1", "Internal Mic 1", + "DMIC R1", "Internal Mic 1", + "DMIC L2", "Internal Mic 2", + "DMIC R2", "Internal Mic 2", + "Speaker", "PDM1L", + "Speaker", "PDM1R"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5677>; + + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>; + nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>; + nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>; + nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 31198cf7..a6768f8 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -128,3 +128,13 @@ config SND_SOC_TEGRA_MAX98090 help Say Y or M here if you want to add support for SoC audio on Tegra boards using the MAX98090 codec, such as Venice2. + +config SND_SOC_TEGRA_RT5677 + tristate "SoC Audio support for Tegra boards using a RT5677 codec" + depends on SND_SOC_TEGRA && I2C && GPIOLIB + select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC + select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC + select SND_SOC_RT5677 + help + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the RT5677 codec, such as Ryu. diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 5ae588c..9171655 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o # Tegra machine Support snd-soc-tegra-rt5640-objs := tegra_rt5640.o +snd-soc-tegra-rt5677-objs := tegra_rt5677.o snd-soc-tegra-wm8753-objs := tegra_wm8753.o snd-soc-tegra-wm8903-objs := tegra_wm8903.o snd-soc-tegra-wm9712-objs := tegra_wm9712.o @@ -27,6 +28,7 @@ snd-soc-tegra-alc5632-objs := tegra_alc5632.o snd-soc-tegra-max98090-objs := tegra_max98090.o obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o +obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c new file mode 100644 index 0000000..e4cf978 --- /dev/null +++ b/sound/soc/tegra/tegra_rt5677.c @@ -0,0 +1,347 @@ +/* +* tegra_rt5677.c - Tegra machine ASoC driver for boards using RT5677 codec. + * + * Copyright (c) 2014, The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Based on code copyright/by: + * + * Copyright (C) 2010-2012 - NVIDIA, Inc. + * Copyright (C) 2011 The AC100 Kernel Team + * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. + * Copyright 2007 Wolfson Microelectronics PLC. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../codecs/rt5677.h" + +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-rt5677" + +struct tegra_rt5677 { + struct tegra_asoc_utils_data util_data; + int gpio_hp_det; + int gpio_hp_en; + int gpio_mic_present; + int gpio_dmic_clk_en; +}; + +static int tegra_rt5677_asoc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_card *card = rtd->card; + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk, err; + + srate = params_rate(params); + mclk = 256 * srate; + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + + if (!gpio_is_valid(machine->gpio_hp_en)) + return 0; + + gpio_set_value_cansleep(machine->gpio_hp_en, + SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static struct snd_soc_ops tegra_rt5677_ops = { + .hw_params = tegra_rt5677_asoc_hw_params, +}; + +static struct snd_soc_jack tegra_rt5677_hp_jack; + +static struct snd_soc_jack_pin tegra_rt5677_hp_jack_pins = { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, +}; +static struct snd_soc_jack_gpio tegra_rt5677_hp_jack_gpio = { + .name = "Headphone detection", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +static struct snd_soc_jack tegra_rt5677_mic_jack; + +static struct snd_soc_jack_pin tegra_rt5677_mic_jack_pins = { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, +}; + +static struct snd_soc_jack_gpio tegra_rt5677_mic_jack_gpio = { + .name = "Headset Mic detection", + .report = SND_JACK_MICROPHONE, + .debounce_time = 150, + .invert = 1 +}; + +static const struct snd_soc_dapm_widget tegra_rt5677_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_HP("Headphone", tegra_rt5677_event_hp), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic 1", NULL), + SND_SOC_DAPM_MIC("Internal Mic 2", NULL), +}; + +static const struct snd_kcontrol_new tegra_rt5677_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic 1"), + SOC_DAPM_PIN_SWITCH("Internal Mic 2"), +}; + +static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card); + + snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, + &tegra_rt5677_hp_jack); + snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1, + &tegra_rt5677_hp_jack_pins); + + if (gpio_is_valid(machine->gpio_hp_det)) { + tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det; + snd_soc_jack_add_gpios(&tegra_rt5677_hp_jack, 1, + &tegra_rt5677_hp_jack_gpio); + } + + + snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_rt5677_mic_jack); + snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1, + &tegra_rt5677_mic_jack_pins); + + if (gpio_is_valid(machine->gpio_mic_present)) { + tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present; + snd_soc_jack_add_gpios(&tegra_rt5677_mic_jack, 1, + &tegra_rt5677_mic_jack_gpio); + } + + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + + return 0; +} + +static int tegra_rt5677_card_remove(struct snd_soc_card *card) +{ + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_free_gpios(&tegra_rt5677_hp_jack, 1, + &tegra_rt5677_hp_jack_gpio); + } + + if (gpio_is_valid(machine->gpio_mic_present)) { + snd_soc_jack_free_gpios(&tegra_rt5677_mic_jack, 1, + &tegra_rt5677_mic_jack_gpio); + } + + return 0; +} + +static struct snd_soc_dai_link tegra_rt5677_dai = { + .name = "RT5677", + .stream_name = "RT5677 PCM", + .codec_dai_name = "rt5677-aif1", + .init = tegra_rt5677_asoc_init, + .ops = &tegra_rt5677_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_tegra_rt5677 = { + .name = "tegra-rt5677", + .owner = THIS_MODULE, + .remove = tegra_rt5677_card_remove, + .dai_link = &tegra_rt5677_dai, + .num_links = 1, + .controls = tegra_rt5677_controls, + .num_controls = ARRAY_SIZE(tegra_rt5677_controls), + .dapm_widgets = tegra_rt5677_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_rt5677_dapm_widgets), + .fully_routed = true, +}; + +static int tegra_rt5677_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card = &snd_soc_tegra_rt5677; + struct tegra_rt5677 *machine; + int ret; + + machine = devm_kzalloc(&pdev->dev, + sizeof(struct tegra_rt5677), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); + if (machine->gpio_hp_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + + machine->gpio_mic_present = of_get_named_gpio(np, + "nvidia,mic-present-gpios", 0); + if (machine->gpio_mic_present == -EPROBE_DEFER) + return -EPROBE_DEFER; + + machine->gpio_hp_en = of_get_named_gpio(np, "nvidia,hp-en-gpios", 0); + if (machine->gpio_hp_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_hp_en)) { + ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_en, + GPIOF_OUT_INIT_LOW, "hp_en"); + if (ret) { + dev_err(card->dev, "cannot get hp_en gpio\n"); + return ret; + } + } + + machine->gpio_dmic_clk_en = of_get_named_gpio(np, + "nvidia,dmic-clk-en-gpios", 0); + if (machine->gpio_dmic_clk_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_dmic_clk_en)) { + ret = devm_gpio_request_one(&pdev->dev, + machine->gpio_dmic_clk_en, + GPIOF_OUT_INIT_HIGH, "dmic_clk_en"); + if (ret) { + dev_err(card->dev, "cannot get dmic_clk_en gpio\n"); + return ret; + } + } + + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_rt5677_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!tegra_rt5677_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_rt5677_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!tegra_rt5677_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + tegra_rt5677_dai.platform_of_node = tegra_rt5677_dai.cpu_of_node; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err: + return ret; +} + +static int tegra_rt5677_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + return 0; +} + +static const struct of_device_id tegra_rt5677_of_match[] = { + { .compatible = "nvidia,tegra-audio-rt5677", }, + {}, +}; + +static struct platform_driver tegra_rt5677_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = tegra_rt5677_of_match, + }, + .probe = tegra_rt5677_probe, + .remove = tegra_rt5677_remove, +}; +module_platform_driver(tegra_rt5677_driver); + +MODULE_AUTHOR("Anatol Pomozov "); +MODULE_DESCRIPTION("Tegra+RT5677 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_rt5677_of_match); -- cgit v0.10.2 From 061a5ad7c9b938fd730672b21347b69896a27973 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 4 Jan 2015 14:28:46 -0800 Subject: Input: imx_keypad - use the preferred form for passing a size of a struct According to Documentation/CodingStyle - Chapter 14: "The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not." So do it as recommended. Signed-off-by: Fabio Estevam Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 20a99c3..3b681c8 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -448,8 +448,7 @@ static int imx_keypad_probe(struct platform_device *pdev) return -ENOMEM; } - keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad), - GFP_KERNEL); + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); if (!keypad) { dev_err(&pdev->dev, "not enough memory for driver data\n"); return -ENOMEM; -- cgit v0.10.2 From 0e4ca02b3fc0e33e96eef1f4da227eab2c67b8ac Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 9 Dec 2014 16:14:11 -0500 Subject: efi: Update the URLs for efibootmgr Matt Domsch changed the dell page to point to the new upstream quite some time ago; kernel should reflect that here as well. Cc: Matt Domsch Signed-off-by: Peter Jones Signed-off-by: Ricardo Neri diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index f712d47..8de4da5 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -12,11 +12,11 @@ config EFI_VARS Note that using this driver in concert with efibootmgr requires at least test release version 0.5.0-test3 or later, which is - available from Matt Domsch's website located at: + available from: Subsequent efibootmgr releases may be found at: - + config EFI_VARS_PSTORE tristate "Register efivars backend for pstore" -- cgit v0.10.2 From 26e022727f5e88c6e5054e14d954425deacbe56a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 18 Dec 2014 16:02:17 +0100 Subject: efi: Rename efi_guid_unparse to efi_guid_to_str Call it what it does - "unparse" is plain-misleading. Signed-off-by: Borislav Petkov Signed-off-by: Ricardo Neri diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 56d08fd..26cb624 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -715,7 +715,7 @@ int efi_partition(struct parsed_partitions *state) state->parts[i + 1].flags = ADDPART_FLAG_RAID; info = &state->parts[i + 1].info; - efi_guid_unparse(&ptes[i].unique_partition_guid, info->uuid); + efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid); /* Naively convert UTF16-LE to 7 bits. */ label_max = min(ARRAY_SIZE(info->volname) - 1, diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 8590099..ff0bbe3 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -272,10 +272,10 @@ static __init int match_config_table(efi_guid_t *guid, int i; if (table_types) { - efi_guid_unparse(guid, str); + efi_guid_to_str(guid, str); for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { - efi_guid_unparse(&table_types[i].guid, str); + efi_guid_to_str(&table_types[i].guid, str); if (!efi_guidcmp(*guid, table_types[i].guid)) { *(table_types[i].ptr) = table; diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index f256ecd..7b2e049 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -39,7 +39,7 @@ * fix locking per Peter Chubb's findings * * 25 Mar 2002 - Matt Domsch - * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() + * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_to_str() * * 12 Feb 2002 - Matt Domsch * use list_for_each_safe when deleting vars. @@ -128,7 +128,7 @@ efivar_guid_read(struct efivar_entry *entry, char *buf) if (!entry || !buf) return 0; - efi_guid_unparse(&var->VendorGuid, str); + efi_guid_to_str(&var->VendorGuid, str); str += strlen(str); str += sprintf(str, "\n"); @@ -569,7 +569,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var) private variables from another's. */ *(short_name + strlen(short_name)) = '-'; - efi_guid_unparse(&new_var->var.VendorGuid, + efi_guid_to_str(&new_var->var.VendorGuid, short_name + strlen(short_name)); new_var->kobj.kset = efivars_kset; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 6dad117..ddbce42 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -140,7 +140,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, name[len] = '-'; - efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); + efi_guid_to_str(&entry->var.VendorGuid, name + len + 1); name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; diff --git a/include/linux/efi.h b/include/linux/efi.h index 0949f9c..d762c81 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -844,7 +844,7 @@ efi_guidcmp (efi_guid_t left, efi_guid_t right) } static inline char * -efi_guid_unparse(efi_guid_t *guid, char *out) +efi_guid_to_str(efi_guid_t *guid, char *out) { sprintf(out, "%pUl", guid->b); return out; -- cgit v0.10.2 From 3db084fd0af5407eebeb9b7ebd5d0425b362c519 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 8 Jan 2015 00:39:17 +0200 Subject: ALSA: fm801: PCI core handles power state for us There is no need to repeat the work that is already done in the PCI driver core. The patch removes excerpts from suspend and resume callbacks. Note that there is no more calls performed to enable or disable a PCI device during suspend-resume cycle. Nowadays they seems to be superflous. Someone can read more in [1]. [1] https://www.kernel.org/doc/ols/2009/ols2009-pages-319-330.pdf Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index dd6f23f..1a0494e 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1375,7 +1375,6 @@ static unsigned char saved_regs[] = { static int snd_fm801_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct fm801 *chip = card->private_data; int i; @@ -1387,29 +1386,15 @@ static int snd_fm801_suspend(struct device *dev) for (i = 0; i < ARRAY_SIZE(saved_regs); i++) chip->saved_regs[i] = inw(chip->port + saved_regs[i]); /* FIXME: tea575x suspend */ - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_fm801_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct fm801 *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_fm801_chip_init(chip, 1); snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97_sec); -- cgit v0.10.2 From e9f49369722bd7dd53f90467196df4b952eac1b6 Mon Sep 17 00:00:00 2001 From: Paul Bonser Date: Wed, 7 Jan 2015 23:34:16 -0600 Subject: ALSA: usb-audio: Add support for Akai MPC Element USB MIDI controller The Akai MPC Element incorrectly reports its bInterfaceClass as 255, but otherwise implements the USB MIDI spec correctly. This adds a quirks-table.h entry which allows the device to be recognized as a standard USB MIDI device. Signed-off-by: Paul Bonser Signed-off-by: Takashi Iwai diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 0a598af..67d4765 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2486,6 +2486,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* Akai MPC Element */ + USB_DEVICE(0x09e8, 0x0021), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, + /* TerraTec devices */ { USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), -- cgit v0.10.2 From 2558cd8cab793e9c8c3b17bdf06552bfb98d49e5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:38:00 +0100 Subject: microblaze: Use unsigned type for limit comparison in cache.c The patch removes warnings: arch/microblaze/kernel/cpu/cache.c:146:14: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index a6e44410..0bde47e 100644 --- a/arch/microblaze/kernel/cpu/cache.c +++ b/arch/microblaze/kernel/cpu/cache.c @@ -140,10 +140,10 @@ do { \ /* It is used only first parameter for OP - for wic, wdc */ #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ do { \ - int volatile temp = 0; \ - int align = ~(line_length - 1); \ + unsigned int volatile temp = 0; \ + unsigned int align = ~(line_length - 1); \ end = ((end & align) == end) ? end - line_length : end & align; \ - WARN_ON(end - start < 0); \ + WARN_ON(end < start); \ \ __asm__ __volatile__ (" 1: " #op " %1, r0;" \ "cmpu %0, %1, %2;" \ -- cgit v0.10.2 From ed4602e13f8d7b764308d6db58ff9932353f16a3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Dec 2014 15:38:07 +0100 Subject: microblaze: Fix variable types to remove W=1 warning This patch removes this warning: arch/microblaze/kernel/signal.c: In function 'setup_rt_frame': arch/microblaze/kernel/signal.c:177:3: warning: signed and unsigned type in conditional expression [-Wsign-compare] Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 8955a38..2357060 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -158,7 +158,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, { struct rt_sigframe __user *frame; int err = 0, sig = ksig->sig; - int signal; + unsigned long signal; unsigned long address = 0; #ifdef CONFIG_MMU pmd_t *pmdp; @@ -174,7 +174,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig; + : (unsigned long)sig; if (ksig->ka.sa.sa_flags & SA_SIGINFO) err |= copy_siginfo_to_user(&frame->info, &ksig->info); -- cgit v0.10.2 From 81653edd99ee2297ad6ab49a4f91a1d5dce577f1 Mon Sep 17 00:00:00 2001 From: Erico Nunes Date: Fri, 2 Jan 2015 00:40:33 -0200 Subject: microblaze: Add missing PVR version codes PVR version code was missing in the cpu_ver_lookup table for the following versions: 8.50.b 8.50.c 9.2 9.3 This caused /proc/cpuinfo to display "CPU-Ver: Unknown" for these versions. This was detected and the patch tested with MicroBlaze version 8.50.c. The other codes were taken from the Xilinx MicroBlaze Processor Reference Guides UG081 (v14.7) and UG984 (v2014.1). Signed-off-by: Erico Nunes Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index 234acad..b60442d 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -41,8 +41,12 @@ const struct cpu_ver_key cpu_ver_lookup[] = { {"8.40.a", 0x18}, {"8.40.b", 0x19}, {"8.50.a", 0x1a}, + {"8.50.b", 0x1c}, + {"8.50.c", 0x1e}, {"9.0", 0x1b}, {"9.1", 0x1d}, + {"9.2", 0x1f}, + {"9.3", 0x20}, {NULL, 0}, }; -- cgit v0.10.2 From ed89466f2368fc15c72ce5344d582c640dcf53a6 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 5 Jan 2015 12:01:17 +0100 Subject: microblaze: Add target architecture Add missing target architectures - virtex7, ultrascale virtex and ultrascale kintex. Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index b60442d..d1dd6e8 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -65,11 +65,14 @@ const struct family_string_key family_string_lookup[] = { {"spartan3adsp", 0xc}, {"spartan6", 0xd}, {"virtex6", 0xe}, + {"virtex7", 0xf}, /* FIXME There is no key code defined for spartan2 */ {"spartan2", 0xf0}, {"kintex7", 0x10}, {"artix7", 0x11}, {"zynq7000", 0x12}, + {"UltraScale Virtex", 0x13}, + {"UltraScale Kintex", 0x14}, {NULL, 0}, }; -- cgit v0.10.2 From 2c80a072a6c1cc4490fbbde5ba82bc7faf0374f0 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 19 Dec 2014 10:21:04 -0800 Subject: microblaze: intc: Don't override error codes Just pass on error codes instead of overriding them. Signed-off-by: Soren Brinkmann Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 15c7c12..01ae730 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -148,13 +148,13 @@ static int __init xilinx_intc_of_init(struct device_node *intc, ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq); if (ret < 0) { pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__); - return -EINVAL; + return ret; } ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask); if (ret < 0) { pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__); - return -EINVAL; + return ret; } if (intr_mask > (u32)((1ULL << nr_irq) - 1)) -- cgit v0.10.2 From d50466c90724d5aae4d38a9a9bc163bea6f94098 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 19 Dec 2014 10:21:05 -0800 Subject: microblaze: intc: Refactor DT sanity check Avoid funky casts and arithmetic. Signed-off-by: Soren Brinkmann Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 01ae730..8965fd3 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -157,7 +157,7 @@ static int __init xilinx_intc_of_init(struct device_node *intc, return ret; } - if (intr_mask > (u32)((1ULL << nr_irq) - 1)) + if (intr_mask >> nr_irq) pr_info(" ERROR: Mismatch in kind-of-intr param\n"); pr_info("%s: num_irq=%d, edge=0x%x\n", -- cgit v0.10.2 From 231856ae7ccb5ee49b2f722e1d8ba7a45df1a978 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 19 Dec 2014 10:21:06 -0800 Subject: microblaze: intc: Reformat output A message was using pr_info level output for a message including "ERROR" which is not really a fatal error. Remove the 'ERROR' from that message, use pr_warn loglevel and add the function name to the output to give users a chance to find the culprit in case the warning triggers. Signed-off-by: Soren Brinkmann Signed-off-by: Michal Simek diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 8965fd3..719feee 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -158,7 +158,7 @@ static int __init xilinx_intc_of_init(struct device_node *intc, } if (intr_mask >> nr_irq) - pr_info(" ERROR: Mismatch in kind-of-intr param\n"); + pr_warn("%s: mismatch in kind-of-intr param\n", __func__); pr_info("%s: num_irq=%d, edge=0x%x\n", intc->full_name, nr_irq, intr_mask); -- cgit v0.10.2 From 0774bf6a8b49ccd35fad58a1eed0d2382f34912e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 6 Jan 2015 17:44:02 +0200 Subject: microblaze/uaccess: fix sparse errors virtio wants to read bitwise types from userspace using get_user. At the moment this triggers sparse errors, since the value is passed through an integer. Fix that up using __force. Signed-off-by: Michael S. Tsirkin Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 59a89a6..e41bebf 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -220,7 +220,7 @@ extern long __user_bad(void); } else { \ __gu_err = -EFAULT; \ } \ - x = (typeof(*(ptr)))__gu_val; \ + x = (__force typeof(*(ptr)))__gu_val; \ __gu_err; \ }) @@ -242,7 +242,7 @@ extern long __user_bad(void); default: \ /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ } \ - x = (__typeof__(*(ptr))) __gu_val; \ + x = (__force __typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) -- cgit v0.10.2 From 132d5dfc04698e4226ca9787214bd4e277ed39f2 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 6 Jan 2015 17:45:03 +0200 Subject: microblaze: whitespace fix Align using tabs to make code prettier. Signed-off-by: Michael S. Tsirkin Signed-off-by: Michal Simek diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index e41bebf..62942fd 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -306,7 +306,7 @@ extern long __user_bad(void); #define __put_user_check(x, ptr, size) \ ({ \ - typeof(*(ptr)) volatile __pu_val = x; \ + typeof(*(ptr)) volatile __pu_val = x; \ typeof(*(ptr)) __user *__pu_addr = (ptr); \ int __pu_err = 0; \ \ -- cgit v0.10.2 From 58498ee3e573dc03be651b6839dbdf865ae7ee38 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 9 Dec 2014 10:18:49 +0100 Subject: s390/ftrace: add code replacement sanity checks Always verify that the to be replaced code matches what we expect to see. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index b86bb88..3dabcae 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -59,62 +59,65 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - struct ftrace_insn insn; - unsigned short op; - void *from, *to; - size_t size; - - ftrace_generate_nop_insn(&insn); - size = sizeof(insn); - from = &insn; - to = (void *) rec->ip; - if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) + struct ftrace_insn orig, new, old; + + if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) return -EFAULT; - /* - * If we find a breakpoint instruction, a kprobe has been placed - * at the beginning of the function. We write the constant - * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original - * instruction so that the kprobes handler can execute a nop, if it - * reaches this breakpoint. - */ - if (op == BREAKPOINT_INSTRUCTION) { - size -= 2; - from += 2; - to += 2; - insn.disp = KPROBE_ON_FTRACE_NOP; + if (addr == MCOUNT_ADDR) { + /* Initial code replacement; we expect to see stg r14,8(r15) */ + orig.opc = 0xe3e0; + orig.disp = 0xf0080024; + ftrace_generate_nop_insn(&new); + } else if (old.opc == BREAKPOINT_INSTRUCTION) { + /* + * If we find a breakpoint instruction, a kprobe has been + * placed at the beginning of the function. We write the + * constant KPROBE_ON_FTRACE_NOP into the remaining four + * bytes of the original instruction so that the kprobes + * handler can execute a nop, if it reaches this breakpoint. + */ + new.opc = orig.opc = BREAKPOINT_INSTRUCTION; + orig.disp = KPROBE_ON_FTRACE_CALL; + new.disp = KPROBE_ON_FTRACE_NOP; + } else { + /* Replace ftrace call with a nop. */ + ftrace_generate_call_insn(&orig, rec->ip); + ftrace_generate_nop_insn(&new); } - if (probe_kernel_write(to, from, size)) + /* Verify that the to be replaced code matches what we expect. */ + if (memcmp(&orig, &old, sizeof(old))) + return -EINVAL; + if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return 0; } int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - struct ftrace_insn insn; - unsigned short op; - void *from, *to; - size_t size; - - ftrace_generate_call_insn(&insn, rec->ip); - size = sizeof(insn); - from = &insn; - to = (void *) rec->ip; - if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) + struct ftrace_insn orig, new, old; + + if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) return -EFAULT; - /* - * If we find a breakpoint instruction, a kprobe has been placed - * at the beginning of the function. We write the constant - * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original - * instruction so that the kprobes handler can execute a brasl if it - * reaches this breakpoint. - */ - if (op == BREAKPOINT_INSTRUCTION) { - size -= 2; - from += 2; - to += 2; - insn.disp = KPROBE_ON_FTRACE_CALL; + if (old.opc == BREAKPOINT_INSTRUCTION) { + /* + * If we find a breakpoint instruction, a kprobe has been + * placed at the beginning of the function. We write the + * constant KPROBE_ON_FTRACE_CALL into the remaining four + * bytes of the original instruction so that the kprobes + * handler can execute a brasl if it reaches this breakpoint. + */ + new.opc = orig.opc = BREAKPOINT_INSTRUCTION; + orig.disp = KPROBE_ON_FTRACE_NOP; + new.disp = KPROBE_ON_FTRACE_CALL; + } else { + /* Replace nop with an ftrace call. */ + ftrace_generate_nop_insn(&orig); + ftrace_generate_call_insn(&new, rec->ip); } - if (probe_kernel_write(to, from, size)) + /* Verify that the to be replaced code matches what we expect. */ + if (memcmp(&orig, &old, sizeof(old))) + return -EINVAL; + if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return 0; } -- cgit v0.10.2 From eba8452525e3fd0b982f78365dea8bd2ce11a20a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Dec 2014 12:46:35 +0100 Subject: s390/pci: add missing address space annotation Signed-off-by: Heiko Carstens diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index 62c5ea6..8aa271b 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -55,7 +55,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr, ret = get_pfn(mmio_addr, VM_WRITE, &pfn); if (ret) goto out; - io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); + io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); ret = -EFAULT; if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) @@ -96,7 +96,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr, ret = get_pfn(mmio_addr, VM_READ, &pfn); if (ret) goto out; - io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); + io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); ret = -EFAULT; if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) -- cgit v0.10.2 From 8d1f211ebbdfd57843a52fa7efe34251530beec1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Dec 2014 12:52:00 +0100 Subject: s390/disassembler: remove indentical initializer Remove one of the two identical initializer entries. Signed-off-by: Heiko Carstens diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index f376293..d46d0b0 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -226,7 +226,6 @@ static const struct s390_operand operands[] = [U16_32] = { 16, 32, 0 }, [J16_16] = { 16, 16, OPERAND_PCREL }, [J16_32] = { 16, 32, OPERAND_PCREL }, - [I16_32] = { 16, 32, OPERAND_SIGNED }, [I24_24] = { 24, 24, OPERAND_SIGNED }, [J32_16] = { 32, 16, OPERAND_PCREL }, [I32_16] = { 32, 16, OPERAND_SIGNED }, -- cgit v0.10.2 From 925dfc020a41ce484172a43b603437e58aecd1c1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Dec 2014 13:04:21 +0100 Subject: s390/pgtable: add unsigned long casts Get rid of warnings like this one: warning: constant 0xffe0000000000000 is so big it is unsigned long Signed-off-by: Heiko Carstens diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 601deb8..47cbca0 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -527,7 +527,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) table += (gaddr >> 53) & 0x7ff; if ((*table & _REGION_ENTRY_INVALID) && gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY, - gaddr & 0xffe0000000000000)) + gaddr & 0xffe0000000000000UL)) return -ENOMEM; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); } @@ -535,7 +535,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) table += (gaddr >> 42) & 0x7ff; if ((*table & _REGION_ENTRY_INVALID) && gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY, - gaddr & 0xfffffc0000000000)) + gaddr & 0xfffffc0000000000UL)) return -ENOMEM; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); } @@ -543,7 +543,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) table += (gaddr >> 31) & 0x7ff; if ((*table & _REGION_ENTRY_INVALID) && gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY, - gaddr & 0xffffffff80000000)) + gaddr & 0xffffffff80000000UL)) return -ENOMEM; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); } -- cgit v0.10.2 From e0a50545480de0936ab867168d9bd086e56f465c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Dec 2014 13:11:08 +0100 Subject: s390/signal: add sys_sigreturn and sys_rt_sigreturn declarations Get rid of sparse warnings like this one: arch/s390/kernel/signal.c:244:1: warning: symbol 'sys_sigreturn' was not declared. Should it be static? Signed-off-by: Heiko Carstens diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 8e61393..834df04 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -71,9 +71,11 @@ struct s390_mmap_arg_struct; struct fadvise64_64_args; struct old_sigaction; +long sys_rt_sigreturn(void); +long sys_sigreturn(void); + long sys_s390_personality(unsigned int personality); long sys_s390_runtime_instr(int command, int signum); - long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); #endif /* _ENTRY_H */ -- cgit v0.10.2 From 8ebd51a705c56520481f2b813790dc5afdb0a751 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sat, 20 Dec 2014 13:27:49 +0100 Subject: s390/cio: idset.c: remove some unused functions Removes some functions that are not used anywhere: idset_clear() idset_sch_get_first() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 5a99908..b3e06a7 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -38,11 +38,6 @@ void idset_free(struct idset *set) vfree(set); } -void idset_clear(struct idset *set) -{ - memset(set->bitmap, 0, bitmap_size(set->num_ssid, set->num_id)); -} - void idset_fill(struct idset *set) { memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id)); @@ -103,21 +98,6 @@ int idset_sch_contains(struct idset *set, struct subchannel_id schid) return idset_contains(set, schid.ssid, schid.sch_no); } -int idset_sch_get_first(struct idset *set, struct subchannel_id *schid) -{ - int ssid = 0; - int id = 0; - int rc; - - rc = idset_get_first(set, &ssid, &id); - if (rc) { - init_subchannel_id(schid); - schid->ssid = ssid; - schid->sch_no = id; - } - return rc; -} - int idset_is_empty(struct idset *set) { return bitmap_empty(set->bitmap, set->num_ssid * set->num_id); diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 06d3bc0..22b5810 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h @@ -11,7 +11,6 @@ struct idset; void idset_free(struct idset *set); -void idset_clear(struct idset *set); void idset_fill(struct idset *set); struct idset *idset_sch_new(void); @@ -19,7 +18,6 @@ void idset_sch_add(struct idset *set, struct subchannel_id id); void idset_sch_del(struct idset *set, struct subchannel_id id); void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid); int idset_sch_contains(struct idset *set, struct subchannel_id id); -int idset_sch_get_first(struct idset *set, struct subchannel_id *id); int idset_is_empty(struct idset *set); void idset_add_set(struct idset *to, struct idset *from); -- cgit v0.10.2 From 47523c983f55448c3a09cc3f1a885bf81cd422e3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 22 Dec 2014 10:07:04 +0100 Subject: s390: keep Kconfig sorted Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 68b68d7..e79c3ea 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -66,6 +66,7 @@ config S390 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS select ARCH_HAS_GCOV_PROFILE_ALL + select ARCH_HAS_SG_CHAIN select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_INLINE_READ_LOCK select ARCH_INLINE_READ_LOCK_BH @@ -151,7 +152,6 @@ config S390 select TTY select VIRT_CPU_ACCOUNTING select VIRT_TO_BUS - select ARCH_HAS_SG_CHAIN config SCHED_OMIT_FRAME_POINTER def_bool y -- cgit v0.10.2 From fbf87dff6706d412fe69b8158f7ae415e5e7380b Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Sat, 3 Jan 2015 17:29:07 +0800 Subject: s390/sclp: fix declaration of _sclp_print_early() _sclp_print_early() has return value: at present, return 0 for OK, 1 for failure. It returns '%r2', so use 'long' as return value (upper caller can check '%r2' directly). The related warning: CC arch/s390/boot/compressed/misc.o arch/s390/boot/compressed/misc.c:66:8: warning: type defaults to 'int' in declaration of '_sclp_print_early' [-Wimplicit-int] extern _sclp_print_early(const char *); ^ At present, _sclp_print_early() is only used by puts(), so can still remain its declaration in 'misc.c' file. [heiko.carstens@de.ibm.com]: move declaration to sclp.h header file Signed-off-by: Chen Gang Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 57cbaff..42506b3 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "sizes.h" @@ -63,8 +64,6 @@ static unsigned long free_mem_end_ptr; #include "../../../../lib/decompress_unxz.c" #endif -extern _sclp_print_early(const char *); - static int puts(const char *s) { _sclp_print_early(s); diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 1aba89b..b6f8066 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -68,4 +68,6 @@ void sclp_early_detect(void); int sclp_has_siif(void); unsigned int sclp_get_ibc(void); +long _sclp_print_early(const char *); + #endif /* _ASM_S390_SCLP_H */ -- cgit v0.10.2 From a7e75d434b53b45ae60779903904d4fbdbd145a5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Jan 2015 10:10:14 +0100 Subject: s390/sclp: sign extend return value of _sclp_print_early() _sclp_print_early() has a return value, but misses to sign extend it if called from 64 bit code. This is not really a bug, since currently no caller cares what the return value is. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S index a41f2c9..7e77e03 100644 --- a/arch/s390/kernel/sclp.S +++ b/arch/s390/kernel/sclp.S @@ -294,7 +294,8 @@ ENTRY(_sclp_print_early) #ifdef CONFIG_64BIT tm LC_AR_MODE_ID,1 jno .Lesa3 - lmh %r6,%r15,96(%r15) # store upper register halves + lgfr %r2,%r2 # sign extend return value + lmh %r6,%r15,96(%r15) # restore upper register halves ahi %r15,80 .Lesa3: #endif -- cgit v0.10.2 From 91c0837e6dee8c694c8849c70e1f0f770d92d072 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 5 Jan 2015 04:29:18 -0800 Subject: s390: remove unnecessary KERN_CONT This has no effect as KERN_CONT is an empty string, It's probably just a missing conversion artifact as the other pr_cont uses in the same file don't have this prefix. Signed-off-by: Joe Perches Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 811937b..232c14e 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -171,7 +171,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address) table = table + ((address >> 20) & 0x7ff); if (bad_address(table)) goto bad; - pr_cont(KERN_CONT "S:%016lx ", *table); + pr_cont("S:%016lx ", *table); if (*table & (_SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_LARGE)) goto out; table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN); -- cgit v0.10.2 From e6a67ad0e29087201536792f7d5cecec4ff6fc64 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Thu, 1 Jan 2015 22:56:02 +0800 Subject: s390/crypto: remove 'const' to avoid compiler warnings In aes_encrypt() and aes_decrypt(), need let 'sctx->key' be modified, so remove 'const' for it. The related warnings: CC [M] arch/s390/crypto/aes_s390.o arch/s390/crypto/aes_s390.c: In function 'aes_encrypt': arch/s390/crypto/aes_s390.c:146:37: warning: passing argument 2 of 'crypt_s390_km' discards 'const' qualifier from pointer target type [-Wdiscarded-array-qualifiers] crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, ^ ... In file included from arch/s390/crypto/aes_s390.c:29:0: arch/s390/crypto/crypt_s390.h:154:19: note: expected 'void *' but argument is of type 'const u8 (*)[32] {aka const unsigned char (*)[32]}' static inline int crypt_s390_km(long func, void *param, ^ Signed-off-by: Chen Gang Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 1f272b2..5566ce8 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -134,7 +134,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); if (unlikely(need_fallback(sctx->key_len))) { crypto_cipher_encrypt_one(sctx->fallback.cip, out, in); @@ -159,7 +159,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); if (unlikely(need_fallback(sctx->key_len))) { crypto_cipher_decrypt_one(sctx->fallback.cip, out, in); -- cgit v0.10.2 From d97d929f06d0e072cd36fba6bd9d25b29bae34fd Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 8 Jan 2015 07:41:52 +0000 Subject: s390: move cacheinfo sysfs to generic cacheinfo infrastructure This patch removes the redundant sysfs cacheinfo code by reusing the newly introduced generic cacheinfo infrastructure through the commit 246246cbde5e ("drivers: base: support cpu cache information interface to userspace via sysfs") Signed-off-by: Sudeep Holla Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c index c0b03c2..fe21f07 100644 --- a/arch/s390/kernel/cache.c +++ b/arch/s390/kernel/cache.c @@ -5,37 +5,11 @@ * Author(s): Heiko Carstens */ -#include #include -#include -#include -#include #include +#include #include -struct cache { - unsigned long size; - unsigned int line_size; - unsigned int associativity; - unsigned int nr_sets; - unsigned int level : 3; - unsigned int type : 2; - unsigned int private : 1; - struct list_head list; -}; - -struct cache_dir { - struct kobject *kobj; - struct cache_index_dir *index; -}; - -struct cache_index_dir { - struct kobject kobj; - int cpu; - struct cache *cache; - struct cache_index_dir *next; -}; - enum { CACHE_SCOPE_NOTEXISTS, CACHE_SCOPE_PRIVATE, @@ -44,10 +18,10 @@ enum { }; enum { - CACHE_TYPE_SEPARATE, - CACHE_TYPE_DATA, - CACHE_TYPE_INSTRUCTION, - CACHE_TYPE_UNIFIED, + CTYPE_SEPARATE, + CTYPE_DATA, + CTYPE_INSTRUCTION, + CTYPE_UNIFIED, }; enum { @@ -70,39 +44,59 @@ struct cache_info { }; #define CACHE_MAX_LEVEL 8 - union cache_topology { struct cache_info ci[CACHE_MAX_LEVEL]; unsigned long long raw; }; static const char * const cache_type_string[] = { - "Data", + "", "Instruction", + "Data", + "", "Unified", }; -static struct cache_dir *cache_dir_cpu[NR_CPUS]; -static LIST_HEAD(cache_list); +static const enum cache_type cache_type_map[] = { + [CTYPE_SEPARATE] = CACHE_TYPE_SEPARATE, + [CTYPE_DATA] = CACHE_TYPE_DATA, + [CTYPE_INSTRUCTION] = CACHE_TYPE_INST, + [CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED, +}; void show_cacheinfo(struct seq_file *m) { - struct cache *cache; - int index = 0; + int cpu = smp_processor_id(), idx; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *cache; - list_for_each_entry(cache, &cache_list, list) { - seq_printf(m, "cache%-11d: ", index); + for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) { + cache = this_cpu_ci->info_list + idx; + seq_printf(m, "cache%-11d: ", idx); seq_printf(m, "level=%d ", cache->level); seq_printf(m, "type=%s ", cache_type_string[cache->type]); - seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared"); - seq_printf(m, "size=%luK ", cache->size >> 10); - seq_printf(m, "line_size=%u ", cache->line_size); - seq_printf(m, "associativity=%d", cache->associativity); + seq_printf(m, "scope=%s ", + cache->disable_sysfs ? "Shared" : "Private"); + seq_printf(m, "size=%dK ", cache->size >> 10); + seq_printf(m, "line_size=%u ", cache->coherency_line_size); + seq_printf(m, "associativity=%d", cache->ways_of_associativity); seq_puts(m, "\n"); - index++; } } +static inline enum cache_type get_cache_type(struct cache_info *ci, int level) +{ + if (level >= CACHE_MAX_LEVEL) + return CACHE_TYPE_NOCACHE; + + ci += level; + + if (ci->scope != CACHE_SCOPE_SHARED && ci->scope != CACHE_SCOPE_PRIVATE) + return CACHE_TYPE_NOCACHE; + + return cache_type_map[ci->type]; +} + static inline unsigned long ecag(int ai, int li, int ti) { unsigned long cmd, val; @@ -113,277 +107,79 @@ static inline unsigned long ecag(int ai, int li, int ti) return val; } -static int __init cache_add(int level, int private, int type) +static void ci_leaf_init(struct cacheinfo *this_leaf, int private, + enum cache_type type, unsigned int level) { - struct cache *cache; - int ti; + int ti, num_sets; + int cpu = smp_processor_id(); - cache = kzalloc(sizeof(*cache), GFP_KERNEL); - if (!cache) - return -ENOMEM; - if (type == CACHE_TYPE_INSTRUCTION) + if (type == CACHE_TYPE_INST) ti = CACHE_TI_INSTRUCTION; else ti = CACHE_TI_UNIFIED; - cache->size = ecag(EXTRACT_SIZE, level, ti); - cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti); - cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti); - cache->nr_sets = cache->size / cache->associativity; - cache->nr_sets /= cache->line_size; - cache->private = private; - cache->level = level + 1; - cache->type = type - 1; - list_add_tail(&cache->list, &cache_list); - return 0; -} - -static void __init cache_build_info(void) -{ - struct cache *cache, *next; - union cache_topology ct; - int level, private, rc; - - ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0); - for (level = 0; level < CACHE_MAX_LEVEL; level++) { - switch (ct.ci[level].scope) { - case CACHE_SCOPE_SHARED: - private = 0; - break; - case CACHE_SCOPE_PRIVATE: - private = 1; - break; - default: - return; - } - if (ct.ci[level].type == CACHE_TYPE_SEPARATE) { - rc = cache_add(level, private, CACHE_TYPE_DATA); - rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION); - } else { - rc = cache_add(level, private, ct.ci[level].type); - } - if (rc) - goto error; - } - return; -error: - list_for_each_entry_safe(cache, next, &cache_list, list) { - list_del(&cache->list); - kfree(cache); - } -} - -static struct cache_dir *cache_create_cache_dir(int cpu) -{ - struct cache_dir *cache_dir; - struct kobject *kobj = NULL; - struct device *dev; - - dev = get_cpu_device(cpu); - if (!dev) - goto out; - kobj = kobject_create_and_add("cache", &dev->kobj); - if (!kobj) - goto out; - cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL); - if (!cache_dir) - goto out; - cache_dir->kobj = kobj; - cache_dir_cpu[cpu] = cache_dir; - return cache_dir; -out: - kobject_put(kobj); - return NULL; -} - -static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj) -{ - return container_of(kobj, struct cache_index_dir, kobj); -} - -static void cache_index_release(struct kobject *kobj) -{ - struct cache_index_dir *index; - - index = kobj_to_cache_index_dir(kobj); - kfree(index); -} - -static ssize_t cache_index_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct kobj_attribute *kobj_attr; - - kobj_attr = container_of(attr, struct kobj_attribute, attr); - return kobj_attr->show(kobj, kobj_attr, buf); -} - -#define DEFINE_CACHE_ATTR(_name, _format, _value) \ -static ssize_t cache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ - char *buf) \ -{ \ - struct cache_index_dir *index; \ - \ - index = kobj_to_cache_index_dir(kobj); \ - return sprintf(buf, _format, _value); \ -} \ -static struct kobj_attribute cache_##_name##_attr = \ - __ATTR(_name, 0444, cache_##_name##_show, NULL); -DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10); -DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size); -DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets); -DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity); -DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]); -DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level); + this_leaf->level = level + 1; + this_leaf->type = type; + this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti); + this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY, + level, ti); + this_leaf->size = ecag(EXTRACT_SIZE, level, ti); -static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf) -{ - struct cache_index_dir *index; - int len; - - index = kobj_to_cache_index_dir(kobj); - len = type ? - cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) : - cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)); - len += sprintf(&buf[len], "\n"); - return len; -} - -static ssize_t shared_cpu_map_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return shared_cpu_map_func(kobj, 0, buf); + num_sets = this_leaf->size / this_leaf->coherency_line_size; + num_sets /= this_leaf->ways_of_associativity; + this_leaf->number_of_sets = num_sets; + cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); + if (!private) + this_leaf->disable_sysfs = true; } -static struct kobj_attribute cache_shared_cpu_map_attr = - __ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL); -static ssize_t shared_cpu_list_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +int init_cache_level(unsigned int cpu) { - return shared_cpu_map_func(kobj, 1, buf); -} -static struct kobj_attribute cache_shared_cpu_list_attr = - __ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL); - -static struct attribute *cache_index_default_attrs[] = { - &cache_type_attr.attr, - &cache_size_attr.attr, - &cache_number_of_sets_attr.attr, - &cache_ways_of_associativity_attr.attr, - &cache_level_attr.attr, - &cache_coherency_line_size_attr.attr, - &cache_shared_cpu_map_attr.attr, - &cache_shared_cpu_list_attr.attr, - NULL, -}; - -static const struct sysfs_ops cache_index_ops = { - .show = cache_index_show, -}; - -static struct kobj_type cache_index_type = { - .sysfs_ops = &cache_index_ops, - .release = cache_index_release, - .default_attrs = cache_index_default_attrs, -}; - -static int cache_create_index_dir(struct cache_dir *cache_dir, - struct cache *cache, int index, int cpu) -{ - struct cache_index_dir *index_dir; - int rc; - - index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL); - if (!index_dir) - return -ENOMEM; - index_dir->cache = cache; - index_dir->cpu = cpu; - rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type, - cache_dir->kobj, "index%d", index); - if (rc) - goto out; - index_dir->next = cache_dir->index; - cache_dir->index = index_dir; - return 0; -out: - kfree(index_dir); - return rc; -} + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + unsigned int level = 0, leaves = 0; + union cache_topology ct; + enum cache_type ctype; -static int cache_add_cpu(int cpu) -{ - struct cache_dir *cache_dir; - struct cache *cache; - int rc, index = 0; + if (!this_cpu_ci) + return -EINVAL; - if (list_empty(&cache_list)) - return 0; - cache_dir = cache_create_cache_dir(cpu); - if (!cache_dir) - return -ENOMEM; - list_for_each_entry(cache, &cache_list, list) { - if (!cache->private) + ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0); + do { + ctype = get_cache_type(&ct.ci[0], level); + if (ctype == CACHE_TYPE_NOCACHE) break; - rc = cache_create_index_dir(cache_dir, cache, index, cpu); - if (rc) - return rc; - index++; - } - return 0; -} + /* Separate instruction and data caches */ + leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; + } while (++level < CACHE_MAX_LEVEL); -static void cache_remove_cpu(int cpu) -{ - struct cache_index_dir *index, *next; - struct cache_dir *cache_dir; + this_cpu_ci->num_levels = level; + this_cpu_ci->num_leaves = leaves; - cache_dir = cache_dir_cpu[cpu]; - if (!cache_dir) - return; - index = cache_dir->index; - while (index) { - next = index->next; - kobject_put(&index->kobj); - index = next; - } - kobject_put(cache_dir->kobj); - kfree(cache_dir); - cache_dir_cpu[cpu] = NULL; + return 0; } -static int cache_hotplug(struct notifier_block *nfb, unsigned long action, - void *hcpu) +int populate_cache_leaves(unsigned int cpu) { - int cpu = (long)hcpu; - int rc = 0; + unsigned int level, idx, pvt; + union cache_topology ct; + enum cache_type ctype; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_ONLINE: - rc = cache_add_cpu(cpu); - if (rc) - cache_remove_cpu(cpu); - break; - case CPU_DEAD: - cache_remove_cpu(cpu); - break; + ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0); + for (idx = 0, level = 0; level < this_cpu_ci->num_levels && + idx < this_cpu_ci->num_leaves; idx++, level++) { + if (!this_leaf) + return -EINVAL; + + pvt = (ct.ci[level].scope == CACHE_SCOPE_PRIVATE) ? 1 : 0; + ctype = get_cache_type(&ct.ci[0], level); + if (ctype == CACHE_TYPE_SEPARATE) { + ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level); + ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level); + } else { + ci_leaf_init(this_leaf++, pvt, ctype, level); + } } - return rc ? NOTIFY_BAD : NOTIFY_OK; -} - -static int __init cache_init(void) -{ - int cpu; - - if (!test_facility(34)) - return 0; - cache_build_info(); - - cpu_notifier_register_begin(); - for_each_online_cpu(cpu) - cache_add_cpu(cpu); - __hotcpu_notifier(cache_hotplug, 0); - cpu_notifier_register_done(); return 0; } -device_initcall(cache_init); -- cgit v0.10.2 From f71d148f1adf82edef467d41a2a3be22b36811f0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jan 2015 15:24:20 +0200 Subject: sata_dwc_460ex: remove redundant dev_set_drvdata Driver core sets it to NULL upon probe failure or release. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 8e824817..5c34395 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1783,7 +1783,6 @@ static int sata_dwc_remove(struct platform_device *ofdev) struct sata_dwc_device *hsdev = host->private_data; ata_host_detach(host); - dev_set_drvdata(dev, NULL); /* Free SATA DMA resources */ dma_dwc_exit(hsdev); -- cgit v0.10.2 From 84683a7e081ff60e75039cd2475776654ebbf526 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jan 2015 15:24:21 +0200 Subject: sata_dwc_460ex: enable COMPILE_TEST for the driver To test how the driver could be compiled in the non-native environment let's enable COMPILE_TEST for it. It would be useful for further work. This patch enables COMPILE_TEST for the driver and fixes compilation errors on at least x86 platforms. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index a3a1360..5ed20e3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -269,7 +269,7 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" - depends on 460EX + depends on 460EX || COMPILE_TEST help This option enables support for the on-chip SATA controller of the AppliedMicro processor 460EX. diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 5c34395..c1723e0 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -48,6 +48,18 @@ #define DRV_NAME "sata-dwc" #define DRV_VERSION "1.3" +#ifndef out_le32 +#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (void __iomem *)(a)) +#endif + +#ifndef in_le32 +#define in_le32(a) __le32_to_cpu(__raw_readl((void __iomem *)(a))) +#endif + +#ifndef NO_IRQ +#define NO_IRQ 0 +#endif + /* SATA DMA driver Globals */ #define DMA_NUM_CHANS 1 #define DMA_NUM_CHAN_REGS 8 -- cgit v0.10.2 From d7c256e857c12597813d631a7890a19bbbb6f3a5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jan 2015 15:24:22 +0200 Subject: sata_dwc_460ex: fix most of the sparse warnings There are a lot sparse warnings. Most of them related to __iomem keyword which sometimes absent when it's needed and vise versa. The patch fixes most of the warnings. While at it, remove the redundant sata_dwc_sht.can_queue initialization to ATA_DEF_QUEUE. tj: Added description about ATA_DEF_QUEUE init removal. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index c1723e0..6c1b649 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -285,7 +285,7 @@ struct sata_dwc_device { struct device *dev; /* generic device struct */ struct ata_probe_ent *pe; /* ptr to probe-ent */ struct ata_host *host; - u8 *reg_base; + u8 __iomem *reg_base; struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ int irq_dma; }; @@ -335,7 +335,9 @@ struct sata_dwc_host_priv { struct device *dwc_dev; int dma_channel; }; -struct sata_dwc_host_priv host_pvt; + +static struct sata_dwc_host_priv host_pvt; + /* * Prototypes */ @@ -592,9 +594,9 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems, sms_val = 0; dms_val = 1 + host_pvt.dma_channel; - dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x" - " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli, - (u32)dmadr_addr); + dev_dbg(host_pvt.dwc_dev, + "%s: sg=%p nelem=%d lli=%p dma_lli=0x%pad dmadr=0x%p\n", + __func__, sg, num_elems, lli, &dma_lli, dmadr_addr); bl = get_burst_length_encode(AHB_DMA_BRST_DFLT); @@ -785,7 +787,7 @@ static void dma_dwc_exit(struct sata_dwc_device *hsdev) { dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__); if (host_pvt.sata_dma_regs) { - iounmap(host_pvt.sata_dma_regs); + iounmap((void __iomem *)host_pvt.sata_dma_regs); host_pvt.sata_dma_regs = NULL; } @@ -830,7 +832,7 @@ static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) return -EINVAL; } - *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4)); + *val = in_le32(link->ap->ioaddr.scr_addr + (scr * 4)); dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", __func__, link->ap->print_id, scr, *val); @@ -846,21 +848,19 @@ static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val) __func__, scr); return -EINVAL; } - out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val); + out_le32(link->ap->ioaddr.scr_addr + (scr * 4), val); return 0; } static u32 core_scr_read(unsigned int scr) { - return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\ - (scr * 4)); + return in_le32(host_pvt.scr_addr_sstatus + (scr * 4)); } static void core_scr_write(unsigned int scr, u32 val) { - out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4), - val); + out_le32(host_pvt.scr_addr_sstatus + (scr * 4), val); } static void clear_serror(void) @@ -868,7 +868,6 @@ static void clear_serror(void) u32 val; val = core_scr_read(SCR_ERROR); core_scr_write(SCR_ERROR, val); - } static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit) @@ -1268,24 +1267,24 @@ static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev) static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base) { - port->cmd_addr = (void *)base + 0x00; - port->data_addr = (void *)base + 0x00; + port->cmd_addr = (void __iomem *)base + 0x00; + port->data_addr = (void __iomem *)base + 0x00; - port->error_addr = (void *)base + 0x04; - port->feature_addr = (void *)base + 0x04; + port->error_addr = (void __iomem *)base + 0x04; + port->feature_addr = (void __iomem *)base + 0x04; - port->nsect_addr = (void *)base + 0x08; + port->nsect_addr = (void __iomem *)base + 0x08; - port->lbal_addr = (void *)base + 0x0c; - port->lbam_addr = (void *)base + 0x10; - port->lbah_addr = (void *)base + 0x14; + port->lbal_addr = (void __iomem *)base + 0x0c; + port->lbam_addr = (void __iomem *)base + 0x10; + port->lbah_addr = (void __iomem *)base + 0x14; - port->device_addr = (void *)base + 0x18; - port->command_addr = (void *)base + 0x1c; - port->status_addr = (void *)base + 0x1c; + port->device_addr = (void __iomem *)base + 0x18; + port->command_addr = (void __iomem *)base + 0x1c; + port->status_addr = (void __iomem *)base + 0x1c; - port->altstatus_addr = (void *)base + 0x20; - port->ctl_addr = (void *)base + 0x20; + port->altstatus_addr = (void __iomem *)base + 0x20; + port->ctl_addr = (void __iomem *)base + 0x20; } /* @@ -1326,7 +1325,7 @@ static int sata_dwc_port_start(struct ata_port *ap) for (i = 0; i < SATA_DWC_QCMD_MAX; i++) hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; - ap->bmdma_prd = 0; /* set these so libata doesn't use them */ + ap->bmdma_prd = NULL; /* set these so libata doesn't use them */ ap->bmdma_prd_dma = 0; /* @@ -1523,8 +1522,8 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag], hsdevp->llit_dma[tag], - (void *__iomem)(&hsdev->sata_dwc_regs->\ - dmadr), qc->dma_dir); + (void __iomem *)&hsdev->sata_dwc_regs->dmadr, + qc->dma_dir); if (dma_chan < 0) { dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n", __func__, dma_chan); @@ -1597,8 +1596,8 @@ static void sata_dwc_error_handler(struct ata_port *ap) ata_sff_error_handler(ap); } -int sata_dwc_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +static int sata_dwc_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap); int ret; @@ -1630,7 +1629,7 @@ static struct scsi_host_template sata_dwc_sht = { * max of 1. This will get fixed in in a future release. */ .sg_tablesize = LIBATA_MAX_PRD, - .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */ + /* .can_queue = ATA_MAX_QUEUE, */ .dma_boundary = ATA_DMA_BOUNDARY, }; @@ -1667,7 +1666,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) struct sata_dwc_device *hsdev; u32 idr, versionr; char *ver = (char *)&versionr; - u8 *base = NULL; + u8 __iomem *base; int err = 0; int irq; struct ata_host *host; @@ -1736,7 +1735,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) } /* Get physical SATA DMA register base address */ - host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1); + host_pvt.sata_dma_regs = (void *)of_iomap(ofdev->dev.of_node, 1); if (!(host_pvt.sata_dma_regs)) { dev_err(&ofdev->dev, "ioremap failed for AHBDMA register" " address\n"); -- cgit v0.10.2 From 9037908f16d6376b79f3639d89470e5ef4c7a85f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 8 Jan 2015 12:50:12 +0200 Subject: sata_dwc_460ex: use np local variable in ->probe() This patch fixes the style of usage of a node pointer. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 6c1b649..b206017 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1691,7 +1691,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) host_pvt.dma_channel = dma_chan; /* Ioremap SATA registers */ - base = of_iomap(ofdev->dev.of_node, 0); + base = of_iomap(np, 0); if (!base) { dev_err(&ofdev->dev, "ioremap failed for SATA register" " address\n"); @@ -1727,7 +1727,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) idr, ver[0], ver[1], ver[2]); /* Get SATA DMA interrupt number */ - irq = irq_of_parse_and_map(ofdev->dev.of_node, 1); + irq = irq_of_parse_and_map(np, 1); if (irq == NO_IRQ) { dev_err(&ofdev->dev, "no SATA DMA irq\n"); err = -ENODEV; @@ -1735,7 +1735,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) } /* Get physical SATA DMA register base address */ - host_pvt.sata_dma_regs = (void *)of_iomap(ofdev->dev.of_node, 1); + host_pvt.sata_dma_regs = (void *)of_iomap(np, 1); if (!(host_pvt.sata_dma_regs)) { dev_err(&ofdev->dev, "ioremap failed for AHBDMA register" " address\n"); @@ -1755,7 +1755,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) sata_dwc_enable_interrupts(hsdev); /* Get SATA interrupt number */ - irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + irq = irq_of_parse_and_map(np, 0); if (irq == NO_IRQ) { dev_err(&ofdev->dev, "no SATA DMA irq\n"); err = -ENODEV; -- cgit v0.10.2 From c592b74f6b8ba72cb0b5a90ceb0989fc35fc1391 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 8 Jan 2015 12:50:13 +0200 Subject: sata_dwc_460ex: remove extra message There is no need to print a message about failure of memory allocation. The caller will get an error code and may print the same. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index b206017..169cbca 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1677,11 +1677,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) /* Allocate DWC SATA device */ hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); - if (hsdev == NULL) { - dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); - err = -ENOMEM; - goto error; - } + if (hsdev == NULL) + return -ENOMEM; if (of_property_read_u32(np, "dma-channel", &dma_chan)) { dev_warn(&ofdev->dev, "no dma-channel property set." @@ -1783,7 +1780,6 @@ error_iomap: iounmap(base); error_kmalloc: kfree(hsdev); -error: return err; } -- cgit v0.10.2 From d537fc0c0e23ce87201cb763bf040e730834f94d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 8 Jan 2015 12:50:14 +0200 Subject: sata_dwc_460ex: convert to devm_kzalloc in ->probe() The patch converts ->probe() to use devm_kzalloc that simplifies error path. Note that ata_host_alloc_pinfo() has been using device resources already. Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 169cbca..fdb0f28 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1676,10 +1676,13 @@ static int sata_dwc_probe(struct platform_device *ofdev) u32 dma_chan; /* Allocate DWC SATA device */ - hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); - if (hsdev == NULL) + host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); + hsdev = devm_kzalloc(&ofdev->dev, sizeof(*hsdev), GFP_KERNEL); + if (!host || !hsdev) return -ENOMEM; + host->private_data = hsdev; + if (of_property_read_u32(np, "dma-channel", &dma_chan)) { dev_warn(&ofdev->dev, "no dma-channel property set." " Use channel 0\n"); @@ -1692,8 +1695,7 @@ static int sata_dwc_probe(struct platform_device *ofdev) if (!base) { dev_err(&ofdev->dev, "ioremap failed for SATA register" " address\n"); - err = -ENODEV; - goto error_kmalloc; + return -ENODEV; } hsdev->reg_base = base; dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n"); @@ -1701,16 +1703,6 @@ static int sata_dwc_probe(struct platform_device *ofdev) /* Synopsys DWC SATA specific Registers */ hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); - /* Allocate and fill host */ - host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); - if (!host) { - dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n"); - err = -ENOMEM; - goto error_iomap; - } - - host->private_data = hsdev; - /* Setup port */ host->ports[0]->ioaddr.cmd_addr = base; host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; @@ -1778,8 +1770,6 @@ error_dma_iomap: iounmap((void __iomem *)host_pvt.sata_dma_regs); error_iomap: iounmap(base); -error_kmalloc: - kfree(hsdev); return err; } @@ -1796,8 +1786,6 @@ static int sata_dwc_remove(struct platform_device *ofdev) iounmap((void __iomem *)host_pvt.sata_dma_regs); iounmap(hsdev->reg_base); - kfree(hsdev); - kfree(host); dev_dbg(&ofdev->dev, "done\n"); return 0; } -- cgit v0.10.2 From ddaca25aa4dade234163290f6a9e091e7f57b36a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 8 Jan 2015 12:23:05 +0100 Subject: ASoC: Export snd_soc_runtime_set_dai_fmt() Export snd_soc_runtime_set_dai_fmt() so it can be used in modules. Fixes: ce64c8b9cf5b ("ASoC: Add helper function for changing the DAI link format") Reported-by: kbuild test robot Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 80ea358..d342ee2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1491,6 +1491,7 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); static int snd_soc_instantiate_card(struct snd_soc_card *card) { -- cgit v0.10.2 From a6b3db2c837a2db359bf7f846346680883dbb032 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 8 Jan 2015 08:59:39 +0530 Subject: ASoC: wm5102: Use put_unaligned_be16 This patch introduces the use of function put_unaligned_be16. This is done using Coccinelle and semantic patch used is as follows: @a@ typedef u16, __be16, uint16_t; {u16,__be16,uint16_t} e16; identifier tmp; expression ptr; expression y,e; type T; @@ - tmp = cpu_to_be16(y); <+... when != tmp ( - memcpy(ptr, (T)&tmp, \(2\|sizeof(u16)\|sizeof(__be16)\|sizeof(uint16_t)\|sizeof(e16)\)); + put_unaligned_be16(y,ptr); | - memcpy(ptr, (T)&tmp, ...); + put_unaligned_be16(y,ptr); ) ...+> ? tmp = e @@ type T; identifier a.tmp; @@ - T tmp; ...when != tmp Signed-off-by: Vaishali Thakkar Acked-by: Charles Keepax -- Changes Since v2: Make the patch compatible for current code sound/soc/codecs/wm5102.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index f439ae0..7dbac8a 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -28,6 +28,7 @@ #include #include +#include #include "arizona.h" #include "wm5102.h" @@ -617,11 +618,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - uint16_t data; mutex_lock(&arizona->dac_comp_lock); - data = cpu_to_be16(arizona->dac_comp_coeff); - memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); + put_unaligned_be16(arizona->dac_comp_coeff, + ucontrol->value.bytes.data); mutex_unlock(&arizona->dac_comp_lock); return 0; -- cgit v0.10.2 From 69067f9d52aa325baa0d113c1f35eb98fe486bfc Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 8 Jan 2015 20:12:52 +0800 Subject: ASoC: Intel: Always enable DRAM block for FW dump The first 512 bytes of data DRAM memory is used for FW dump, and this first data SRAM block should be never power gated (always on), here always enable the block(DSRAM[0]) for D0 stage. Signed-off-by: Jie Yang Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 57039b0..c42ffae 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -306,7 +306,7 @@ static void hsw_reset(struct sst_dsp *sst) static int hsw_set_dsp_D0(struct sst_dsp *sst) { int tries = 10; - u32 reg; + u32 reg, fw_dump_bit; /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); @@ -368,7 +368,9 @@ finish: can't be accessed, please enable each block before accessing. */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); + /* for D0, always enable the block(DSRAM[0]) used for FW dump */ + fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; + writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); /* disable DMA finish function for SSP0 & SSP1 */ @@ -491,6 +493,7 @@ static const struct sst_sram_shift sram_shift[] = { {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */ {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */ }; + static u32 hsw_block_get_bit(struct sst_mem_block *block) { u32 bit = 0, shift = 0, index; @@ -587,7 +590,9 @@ static int hsw_block_disable(struct sst_mem_block *block) val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); bit = hsw_block_get_bit(block); - writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); + /* don't disable DSRAM[0], keep it always enable for FW dump*/ + if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT)) + writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); /* wait 18 DSP clock ticks */ udelay(10); @@ -612,7 +617,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) const struct sst_adsp_memregion *region; struct device *dev; int ret = -ENODEV, i, j, region_count; - u32 offset, size; + u32 offset, size, fw_dump_bit; dev = sst->dma_dev; @@ -669,9 +674,11 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) } } + /* always enable the block(DSRAM[0]) used for FW dump */ + fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; /* set default power gating control, enable power gating control for all blocks. that is, can't be accessed, please enable each block before accessing. */ - writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0); + writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); return 0; } -- cgit v0.10.2 From 98b9c1d2ce59d98d5921bbdca5a6d7fe40b4a384 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 8 Jan 2015 14:32:20 +0800 Subject: ASoC: Intel: Add stream direction for pcm-module map A DAI may have 2 streams(playback/capture) and different modules may be needed for them respectively, so we need add a stream direction here, the combination(dai_id + stream) can tell us which module we really need here. Signed-off-by: Jie Yang Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 13f156b..5448f79 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -78,7 +78,6 @@ static const u32 volume_map[] = { #define HSW_PCM_DAI_ID_OFFLOAD0 1 #define HSW_PCM_DAI_ID_OFFLOAD1 2 #define HSW_PCM_DAI_ID_LOOPBACK 3 -#define HSW_PCM_DAI_ID_CAPTURE 4 static const struct snd_pcm_hardware hsw_pcm_hardware = { @@ -99,6 +98,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { struct hsw_pcm_module_map { int dai_id; + int stream; enum sst_hsw_module_id mod_id; }; @@ -687,11 +687,11 @@ static struct snd_pcm_ops hsw_pcm_ops = { /* static mappings between PCMs and modules - may be dynamic in future */ static struct hsw_pcm_module_map mod_map[] = { - {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM}, - {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE}, - {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE}, + {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, + {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, + {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, }; static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) @@ -1075,7 +1075,7 @@ static void hsw_pcm_complete(struct device *dev) return; } - for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[i]; if (!pcm_data->substream) @@ -1109,7 +1109,7 @@ static int hsw_pcm_prepare(struct device *dev) if (pdata->pm_state == HSW_PM_STATE_D3) return 0; /* suspend all active streams */ - for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[i]; if (!pcm_data->substream) @@ -1128,7 +1128,7 @@ static int hsw_pcm_prepare(struct device *dev) sst_hsw_dsp_runtime_suspend(hsw); /* preserve persistent memory */ - for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[i]; if (!pcm_data->substream) -- cgit v0.10.2 From 0c1232503ae5e792a5bef182c64daeb5cf52498d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 7 Jan 2015 13:44:32 -0200 Subject: ASoC: fsl_ssi: Make error message concise Currently the error message uses 'np->full_name' which leads to a very verbose log as: fsl-ssi-dai 202c000.ssi: no irq for node /soc/aips-bus@02000000/spba-bus@02000000/ssi@0202c000 We can have a concise log by using pdev->name instead: fsl-ssi-dai 202c000.ssi: no irq for node 202c000.ssi Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index a65f17d..fa19507 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1363,7 +1363,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi_private->irq = platform_get_irq(pdev, 0); if (!ssi_private->irq) { - dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); return -ENXIO; } -- cgit v0.10.2 From f03038e570728036cf6784a435e11ae1d24a5cf0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 7 Jan 2015 13:44:33 -0200 Subject: ASoC: fsl_asrc: Make error message concise Currently the error message uses 'np->full_name' which leads to a very verbose log that contains the full path of the node. We can have a concise log by using pdev->name instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 026a801..633ffff 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -837,7 +837,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); return irq; } -- cgit v0.10.2 From 0954237f22d808df4918ced2995ff758358881c0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 7 Jan 2015 13:44:34 -0200 Subject: ASoC: fsl_sai: Make error message concise Currently the error message uses 'np->full_name' which leads to a very verbose log that contains the full path of the node. We can have a concise log by using pdev->name instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 032d2d3..ec79c3d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -612,7 +612,7 @@ static int fsl_sai_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); return irq; } -- cgit v0.10.2 From da2d45249af55f4fe7186b5aca76e8cb8e7f8a1a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 7 Jan 2015 13:44:35 -0200 Subject: ASoC: fsl_esai: Make error message concise Currently the error message uses 'np->full_name' which leads to a very verbose log that contains the full path of the node. We can have a concise log by using pdev->name instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 1c08ab1..5c75971 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -774,7 +774,7 @@ static int fsl_esai_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); return irq; } -- cgit v0.10.2 From b968d83f09d8a4af1c178f504bc0414bbb37651d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 7 Jan 2015 13:44:36 -0200 Subject: ASoC: fsl_spdif: Make error message concise Currently the error message uses 'np->full_name' which leads to a very verbose log that contains the full path of the node. We can have a concise log by using pdev->name instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index af042942..735e2ee 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1198,7 +1198,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); return irq; } -- cgit v0.10.2 From 277880a356c10adcb43604f6ab9ec9b2d64db8b2 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 8 Jan 2015 10:31:06 +0800 Subject: ASoC: rt5677: Add the MICBIAS VDD setting in the platform data The patch adds the MICBIAS VDD setting in the platform data. It can be set to 1V8 or 3V3 in the MICBIAS VDD. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index d9eb7d8..a620704 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -37,6 +37,9 @@ struct rt5677_platform_data { OFF, GPIO4, GPIO5 and GPIO6 respectively */ unsigned int jd2_gpio; unsigned int jd3_gpio; + + /* Set MICBIAS1 VDD 1v8 or 3v3 */ + bool micbias1_vdd_3v3; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index cf39fe6..3b32c3e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4912,6 +4912,11 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, RT5677_GPIO5_DIR_OUT); } + if (rt5677->pdata.micbias1_vdd_3v3) + regmap_update_bits(rt5677->regmap, RT5677_MICBIAS, + RT5677_MICBIAS1_CTRL_VDD_MASK, + RT5677_MICBIAS1_CTRL_VDD_3_3V); + rt5677_init_gpio(i2c); rt5677_init_irq(i2c); -- cgit v0.10.2 From 57b7068de5d0cca8ac6e21085b843c1bbd49d3f4 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 26 Dec 2014 20:19:38 +0300 Subject: ASoC: add xtensa xtfpga I2S interface and platform XTFPGA boards provides an audio subsystem that consists of TI CDCE706 clock synthesizer, I2S transmitter and TLV320AIC23 audio codec. I2S transmitter has MMIO-based interface that resembles that of the OpenCores I2S transmitter. I2S transmitter is always a master on I2S bus. There's no specialized audio DMA, sample data are transferred to I2S transmitter FIFO by CPU through memory-mapped queue interface. Signed-off-by: Max Filippov Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt b/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt new file mode 100644 index 0000000..befd125 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt @@ -0,0 +1,18 @@ +Bindings for I2S controller built into xtfpga Xtensa bitstreams. + +Required properties: +- compatible: shall be "cdns,xtfpga-i2s". +- reg: memory region (address and length) with device registers. +- interrupts: interrupt for the device. +- clocks: phandle to the clk used as master clock. I2S bus clock + is derived from it. + +Examples: + + i2s0: xtfpga-i2s@0d080000 { + #sound-dai-cells = <0>; + compatible = "cdns,xtfpga-i2s"; + reg = <0x0d080000 0x40>; + interrupts = <2 1>; + clocks = <&cdce706 4>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8..f1eb40f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10628,6 +10628,7 @@ M: Max Filippov L: linux-xtensa@linux-xtensa.org S: Maintained F: drivers/spi/spi-xtensa-xtfpga.c +F: sound/soc/xtensa/xtfpga-i2s.c YAM DRIVER FOR AX.25 M: Jean-Paul Roubelat diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 7d5d644..dcc79aa 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -55,6 +55,7 @@ source "sound/soc/spear/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" source "sound/soc/ux500/Kconfig" +source "sound/soc/xtensa/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 865e090..5b3c8f6 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -36,3 +36,4 @@ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ obj-$(CONFIG_SND_SOC) += ux500/ +obj-$(CONFIG_SND_SOC) += xtensa/ diff --git a/sound/soc/xtensa/Kconfig b/sound/soc/xtensa/Kconfig new file mode 100644 index 0000000..c201beb --- /dev/null +++ b/sound/soc/xtensa/Kconfig @@ -0,0 +1,7 @@ +config SND_SOC_XTFPGA_I2S + tristate "XTFPGA I2S master" + select REGMAP_MMIO + help + Say Y or M if you want to add support for codecs attached to the + I2S interface on XTFPGA daughter board. You will also need to select + the drivers for the rest of XTFPGA audio subsystem. diff --git a/sound/soc/xtensa/Makefile b/sound/soc/xtensa/Makefile new file mode 100644 index 0000000..15efbf9 --- /dev/null +++ b/sound/soc/xtensa/Makefile @@ -0,0 +1,3 @@ +snd-soc-xtfpga-i2s-objs := xtfpga-i2s.o + +obj-$(CONFIG_SND_SOC_XTFPGA_I2S) += snd-soc-xtfpga-i2s.o diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c new file mode 100644 index 0000000..1cfb19e --- /dev/null +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -0,0 +1,675 @@ +/* + * Xtfpga I2S controller driver + * + * Copyright (c) 2014 Cadence Design Systems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "xtfpga-i2s" + +#define XTFPGA_I2S_VERSION 0x00 +#define XTFPGA_I2S_CONFIG 0x04 +#define XTFPGA_I2S_INT_MASK 0x08 +#define XTFPGA_I2S_INT_STATUS 0x0c +#define XTFPGA_I2S_CHAN0_DATA 0x10 +#define XTFPGA_I2S_CHAN1_DATA 0x14 +#define XTFPGA_I2S_CHAN2_DATA 0x18 +#define XTFPGA_I2S_CHAN3_DATA 0x1c + +#define XTFPGA_I2S_CONFIG_TX_ENABLE 0x1 +#define XTFPGA_I2S_CONFIG_INT_ENABLE 0x2 +#define XTFPGA_I2S_CONFIG_LEFT 0x4 +#define XTFPGA_I2S_CONFIG_RATIO_BASE 8 +#define XTFPGA_I2S_CONFIG_RATIO_MASK 0x0000ff00 +#define XTFPGA_I2S_CONFIG_RES_BASE 16 +#define XTFPGA_I2S_CONFIG_RES_MASK 0x003f0000 +#define XTFPGA_I2S_CONFIG_LEVEL_BASE 24 +#define XTFPGA_I2S_CONFIG_LEVEL_MASK 0x0f000000 +#define XTFPGA_I2S_CONFIG_CHANNEL_BASE 28 + +#define XTFPGA_I2S_INT_UNDERRUN 0x1 +#define XTFPGA_I2S_INT_LEVEL 0x2 +#define XTFPGA_I2S_INT_VALID 0x3 + +#define XTFPGA_I2S_FIFO_SIZE 8192 + +/* + * I2S controller operation: + * + * Enabling TX: output 1 period of zeros (starting with left channel) + * and then queued data. + * + * Level status and interrupt: whenever FIFO level is below FIFO trigger, + * level status is 1 and an IRQ is asserted (if enabled). + * + * Underrun status and interrupt: whenever FIFO is empty, underrun status + * is 1 and an IRQ is asserted (if enabled). + */ +struct xtfpga_i2s { + struct device *dev; + struct clk *clk; + struct regmap *regmap; + void __iomem *regs; + + /* current playback substream. NULL if not playing. + * + * Access to that field is synchronized between the interrupt handler + * and userspace through RCU. + * + * Interrupt handler (threaded part) does PIO on substream data in RCU + * read-side critical section. Trigger callback sets and clears the + * pointer when the playback is started and stopped with + * rcu_assign_pointer. When userspace is about to free the playback + * stream in the pcm_close callback it synchronizes with the interrupt + * handler by means of synchronize_rcu call. + */ + struct snd_pcm_substream *tx_substream; + unsigned (*tx_fn)(struct xtfpga_i2s *i2s, + struct snd_pcm_runtime *runtime, + unsigned tx_ptr); + unsigned tx_ptr; /* next frame index in the sample buffer */ + + /* current fifo level estimate. + * Doesn't have to be perfectly accurate, but must be not less than + * the actual FIFO level in order to avoid stall on push attempt. + */ + unsigned tx_fifo_level; + + /* FIFO level at which level interrupt occurs */ + unsigned tx_fifo_low; + + /* maximal FIFO level */ + unsigned tx_fifo_high; +}; + +static bool xtfpga_i2s_wr_reg(struct device *dev, unsigned int reg) +{ + return reg >= XTFPGA_I2S_CONFIG; +} + +static bool xtfpga_i2s_rd_reg(struct device *dev, unsigned int reg) +{ + return reg < XTFPGA_I2S_CHAN0_DATA; +} + +static bool xtfpga_i2s_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == XTFPGA_I2S_INT_STATUS; +} + +static const struct regmap_config xtfpga_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = XTFPGA_I2S_CHAN3_DATA, + .writeable_reg = xtfpga_i2s_wr_reg, + .readable_reg = xtfpga_i2s_rd_reg, + .volatile_reg = xtfpga_i2s_volatile_reg, + .cache_type = REGCACHE_FLAT, +}; + +/* Generate functions that do PIO from TX DMA area to FIFO for all supported + * stream formats. + * Functions will be called xtfpga_pcm_tx_x, e.g. + * xtfpga_pcm_tx_2x16 for 16-bit stereo. + * + * FIFO consists of 32-bit words, one word per channel, always 2 channels. + * If I2S interface is configured with smaller sample resolution, only + * the LSB of each word is used. + */ +#define xtfpga_pcm_tx_fn(channels, sample_bits) \ +static unsigned xtfpga_pcm_tx_##channels##x##sample_bits( \ + struct xtfpga_i2s *i2s, struct snd_pcm_runtime *runtime, \ + unsigned tx_ptr) \ +{ \ + const u##sample_bits (*p)[channels] = \ + (void *)runtime->dma_area; \ +\ + for (; i2s->tx_fifo_level < i2s->tx_fifo_high; \ + i2s->tx_fifo_level += 2) { \ + iowrite32(p[tx_ptr][0], \ + i2s->regs + XTFPGA_I2S_CHAN0_DATA); \ + iowrite32(p[tx_ptr][channels - 1], \ + i2s->regs + XTFPGA_I2S_CHAN0_DATA); \ + if (++tx_ptr >= runtime->buffer_size) \ + tx_ptr = 0; \ + } \ + return tx_ptr; \ +} + +xtfpga_pcm_tx_fn(1, 16) +xtfpga_pcm_tx_fn(2, 16) +xtfpga_pcm_tx_fn(1, 32) +xtfpga_pcm_tx_fn(2, 32) + +#undef xtfpga_pcm_tx_fn + +static bool xtfpga_pcm_push_tx(struct xtfpga_i2s *i2s) +{ + struct snd_pcm_substream *tx_substream; + bool tx_active; + + rcu_read_lock(); + tx_substream = rcu_dereference(i2s->tx_substream); + tx_active = tx_substream && snd_pcm_running(tx_substream); + if (tx_active) { + unsigned tx_ptr = ACCESS_ONCE(i2s->tx_ptr); + unsigned new_tx_ptr = i2s->tx_fn(i2s, tx_substream->runtime, + tx_ptr); + + cmpxchg(&i2s->tx_ptr, tx_ptr, new_tx_ptr); + } + rcu_read_unlock(); + + return tx_active; +} + +static void xtfpga_pcm_refill_fifo(struct xtfpga_i2s *i2s) +{ + unsigned int_status; + unsigned i; + + regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS, + &int_status); + + for (i = 0; i < 2; ++i) { + bool tx_active = xtfpga_pcm_push_tx(i2s); + + regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS, + XTFPGA_I2S_INT_VALID); + if (tx_active) + regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS, + &int_status); + + if (!tx_active || + !(int_status & XTFPGA_I2S_INT_LEVEL)) + break; + + /* After the push the level IRQ is still asserted, + * means FIFO level is below tx_fifo_low. Estimate + * it as tx_fifo_low. + */ + i2s->tx_fifo_level = i2s->tx_fifo_low; + } + + if (!(int_status & XTFPGA_I2S_INT_LEVEL)) + regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, + XTFPGA_I2S_INT_VALID); + else if (!(int_status & XTFPGA_I2S_INT_UNDERRUN)) + regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, + XTFPGA_I2S_INT_UNDERRUN); + + if (!(int_status & XTFPGA_I2S_INT_UNDERRUN)) + regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG, + XTFPGA_I2S_CONFIG_INT_ENABLE | + XTFPGA_I2S_CONFIG_TX_ENABLE, + XTFPGA_I2S_CONFIG_INT_ENABLE | + XTFPGA_I2S_CONFIG_TX_ENABLE); + else + regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG, + XTFPGA_I2S_CONFIG_INT_ENABLE | + XTFPGA_I2S_CONFIG_TX_ENABLE, 0); +} + +static irqreturn_t xtfpga_i2s_threaded_irq_handler(int irq, void *dev_id) +{ + struct xtfpga_i2s *i2s = dev_id; + struct snd_pcm_substream *tx_substream; + unsigned config, int_status, int_mask; + + regmap_read(i2s->regmap, XTFPGA_I2S_CONFIG, &config); + regmap_read(i2s->regmap, XTFPGA_I2S_INT_MASK, &int_mask); + regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS, &int_status); + + if (!(config & XTFPGA_I2S_CONFIG_INT_ENABLE) || + !(int_status & int_mask & XTFPGA_I2S_INT_VALID)) + return IRQ_NONE; + + /* Update FIFO level estimate in accordance with interrupt status + * register. + */ + if (int_status & XTFPGA_I2S_INT_UNDERRUN) { + i2s->tx_fifo_level = 0; + regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG, + XTFPGA_I2S_CONFIG_TX_ENABLE, 0); + } else { + /* The FIFO isn't empty, but is below tx_fifo_low. Estimate + * it as tx_fifo_low. + */ + i2s->tx_fifo_level = i2s->tx_fifo_low; + } + + rcu_read_lock(); + tx_substream = rcu_dereference(i2s->tx_substream); + + if (tx_substream && snd_pcm_running(tx_substream)) { + snd_pcm_period_elapsed(tx_substream); + if (int_status & XTFPGA_I2S_INT_UNDERRUN) + dev_dbg_ratelimited(i2s->dev, "%s: underrun\n", + __func__); + } + rcu_read_unlock(); + + /* Refill FIFO, update allowed IRQ reasons, enable IRQ if FIFO is + * not empty. + */ + xtfpga_pcm_refill_fifo(i2s); + + return IRQ_HANDLED; +} + +static int xtfpga_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct xtfpga_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, i2s); + return 0; +} + +static int xtfpga_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct xtfpga_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned srate = params_rate(params); + unsigned channels = params_channels(params); + unsigned period_size = params_period_size(params); + unsigned sample_size = snd_pcm_format_width(params_format(params)); + unsigned freq, ratio, level; + int err; + + regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG, + XTFPGA_I2S_CONFIG_RES_MASK, + sample_size << XTFPGA_I2S_CONFIG_RES_BASE); + + freq = 256 * srate; + err = clk_set_rate(i2s->clk, freq); + if (err < 0) + return err; + + /* ratio field of the config register controls MCLK->I2S clock + * derivation: I2S clock = MCLK / (2 * (ratio + 2)). + * + * So with MCLK = 256 * sample rate ratio is 0 for 32 bit stereo + * and 2 for 16 bit stereo. + */ + ratio = (freq - (srate * sample_size * 8)) / + (srate * sample_size * 4); + + regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG, + XTFPGA_I2S_CONFIG_RATIO_MASK, + ratio << XTFPGA_I2S_CONFIG_RATIO_BASE); + + i2s->tx_fifo_low = XTFPGA_I2S_FIFO_SIZE / 2; + + /* period_size * 2: FIFO always gets 2 samples per frame */ + for (level = 1; + i2s->tx_fifo_low / 2 >= period_size * 2 && + level < (XTFPGA_I2S_CONFIG_LEVEL_MASK >> + XTFPGA_I2S_CONFIG_LEVEL_BASE); ++level) + i2s->tx_fifo_low /= 2; + + i2s->tx_fifo_high = 2 * i2s->tx_fifo_low; + + regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG, + XTFPGA_I2S_CONFIG_LEVEL_MASK, + level << XTFPGA_I2S_CONFIG_LEVEL_BASE); + + dev_dbg(i2s->dev, + "%s srate: %u, channels: %u, sample_size: %u, period_size: %u\n", + __func__, srate, channels, sample_size, period_size); + dev_dbg(i2s->dev, "%s freq: %u, ratio: %u, level: %u\n", + __func__, freq, ratio, level); + + return 0; +} + +static int xtfpga_i2s_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) + return -EINVAL; + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + return -EINVAL; + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) + return -EINVAL; + + return 0; +} + +/* PCM */ + +static const struct snd_pcm_hardware xtfpga_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 2, + .period_bytes_min = 2, + .period_bytes_max = XTFPGA_I2S_FIFO_SIZE / 2 * 8, + .periods_min = 2, + .periods_max = XTFPGA_I2S_FIFO_SIZE * 8 / 2, + .buffer_bytes_max = XTFPGA_I2S_FIFO_SIZE * 8, + .fifo_size = 16, +}; + +static int xtfpga_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + void *p; + + snd_soc_set_runtime_hwparams(substream, &xtfpga_pcm_hardware); + p = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + runtime->private_data = p; + + return 0; +} + +static int xtfpga_pcm_close(struct snd_pcm_substream *substream) +{ + synchronize_rcu(); + return 0; +} + +static int xtfpga_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int ret; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xtfpga_i2s *i2s = runtime->private_data; + unsigned channels = params_channels(hw_params); + + switch (channels) { + case 1: + case 2: + break; + + default: + return -EINVAL; + + } + + switch (params_format(hw_params)) { + case SNDRV_PCM_FORMAT_S16_LE: + i2s->tx_fn = (channels == 1) ? + xtfpga_pcm_tx_1x16 : + xtfpga_pcm_tx_2x16; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + i2s->tx_fn = (channels == 1) ? + xtfpga_pcm_tx_1x32 : + xtfpga_pcm_tx_2x32; + break; + + default: + return -EINVAL; + } + + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + return ret; +} + +static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xtfpga_i2s *i2s = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ACCESS_ONCE(i2s->tx_ptr) = 0; + rcu_assign_pointer(i2s->tx_substream, substream); + xtfpga_pcm_refill_fifo(i2s); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + rcu_assign_pointer(i2s->tx_substream, NULL); + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct xtfpga_i2s *i2s = runtime->private_data; + snd_pcm_uframes_t pos = ACCESS_ONCE(i2s->tx_ptr); + + return pos < runtime->buffer_size ? pos : 0; +} + +static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + size_t size = xtfpga_pcm_hardware.buffer_bytes_max; + + return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, + card->dev, size, size); +} + +static void xtfpga_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static const struct snd_pcm_ops xtfpga_pcm_ops = { + .open = xtfpga_pcm_open, + .close = xtfpga_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = xtfpga_pcm_hw_params, + .trigger = xtfpga_pcm_trigger, + .pointer = xtfpga_pcm_pointer, +}; + +static const struct snd_soc_platform_driver xtfpga_soc_platform = { + .pcm_new = xtfpga_pcm_new, + .pcm_free = xtfpga_pcm_free, + .ops = &xtfpga_pcm_ops, +}; + +static const struct snd_soc_component_driver xtfpga_i2s_component = { + .name = DRV_NAME, +}; + +static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = { + .startup = xtfpga_i2s_startup, + .hw_params = xtfpga_i2s_hw_params, + .set_fmt = xtfpga_i2s_set_fmt, +}; + +static struct snd_soc_dai_driver xtfpga_i2s_dai[] = { + { + .name = "xtfpga-i2s", + .id = 0, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &xtfpga_i2s_dai_ops, + }, +}; + +static int xtfpga_i2s_runtime_suspend(struct device *dev) +{ + struct xtfpga_i2s *i2s = dev_get_drvdata(dev); + + clk_disable_unprepare(i2s->clk); + return 0; +} + +static int xtfpga_i2s_runtime_resume(struct device *dev) +{ + struct xtfpga_i2s *i2s = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(i2s->clk); + if (ret) { + dev_err(dev, "clk_prepare_enable failed: %d\n", ret); + return ret; + } + return 0; +} + +static int xtfpga_i2s_probe(struct platform_device *pdev) +{ + struct xtfpga_i2s *i2s; + struct resource *mem; + int err, irq; + + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) { + err = -ENOMEM; + goto err; + } + platform_set_drvdata(pdev, i2s); + i2s->dev = &pdev->dev; + dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2s->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2s->regs)) { + err = PTR_ERR(i2s->regs); + goto err; + } + + i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs, + &xtfpga_i2s_regmap_config); + if (IS_ERR(i2s->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + err = PTR_ERR(i2s->regmap); + goto err; + } + + i2s->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2s->clk)) { + dev_err(&pdev->dev, "couldn't get clock\n"); + err = PTR_ERR(i2s->clk); + goto err; + } + + regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG, + (0x1 << XTFPGA_I2S_CONFIG_CHANNEL_BASE)); + regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS, XTFPGA_I2S_INT_VALID); + regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, XTFPGA_I2S_INT_UNDERRUN); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + err = irq; + goto err; + } + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, + xtfpga_i2s_threaded_irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + pdev->name, i2s); + if (err < 0) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err; + } + + err = snd_soc_register_platform(&pdev->dev, &xtfpga_soc_platform); + if (err < 0) { + dev_err(&pdev->dev, "couldn't register platform\n"); + goto err; + } + err = devm_snd_soc_register_component(&pdev->dev, + &xtfpga_i2s_component, + xtfpga_i2s_dai, + ARRAY_SIZE(xtfpga_i2s_dai)); + if (err < 0) { + dev_err(&pdev->dev, "couldn't register component\n"); + goto err_unregister_platform; + } + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + err = xtfpga_i2s_runtime_resume(&pdev->dev); + if (err) + goto err_pm_disable; + } + return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); +err_unregister_platform: + snd_soc_unregister_platform(&pdev->dev); +err: + dev_err(&pdev->dev, "%s: err = %d\n", __func__, err); + return err; +} + +static int xtfpga_i2s_remove(struct platform_device *pdev) +{ + struct xtfpga_i2s *i2s = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_platform(&pdev->dev); + if (i2s->regmap && !IS_ERR(i2s->regmap)) { + regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG, 0); + regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, 0); + regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS, + XTFPGA_I2S_INT_VALID); + } + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + xtfpga_i2s_runtime_suspend(&pdev->dev); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id xtfpga_i2s_of_match[] = { + { .compatible = "cdns,xtfpga-i2s", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xtfpga_i2s_of_match); +#endif + +static const struct dev_pm_ops xtfpga_i2s_pm_ops = { + SET_RUNTIME_PM_OPS(xtfpga_i2s_runtime_suspend, + xtfpga_i2s_runtime_resume, NULL) +}; + +static struct platform_driver xtfpga_i2s_driver = { + .probe = xtfpga_i2s_probe, + .remove = xtfpga_i2s_remove, + .driver = { + .name = "xtfpga-i2s", + .of_match_table = of_match_ptr(xtfpga_i2s_of_match), + .pm = &xtfpga_i2s_pm_ops, + }, +}; + +module_platform_driver(xtfpga_i2s_driver); + +MODULE_AUTHOR("Max Filippov "); +MODULE_DESCRIPTION("xtfpga I2S controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 1b3de223385d6bf2ab9bf2e9e80aebb26fedd426 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 12:48:41 +0100 Subject: regulator: Copy config passed during registration Copy the 'regulator_config' structure passed to regulator_register() function so the driver could safely modify it after parsing init data. The driver may want to change the config as a result of specific init data parsed by regulator core (e.g. when core handled parsing device tree). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e225711..c13b557 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3581,20 +3581,21 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) */ struct regulator_dev * regulator_register(const struct regulator_desc *regulator_desc, - const struct regulator_config *config) + const struct regulator_config *cfg) { const struct regulation_constraints *constraints = NULL; const struct regulator_init_data *init_data; + struct regulator_config *config = NULL; static atomic_t regulator_no = ATOMIC_INIT(0); struct regulator_dev *rdev; struct device *dev; int ret, i; const char *supply = NULL; - if (regulator_desc == NULL || config == NULL) + if (regulator_desc == NULL || cfg == NULL) return ERR_PTR(-EINVAL); - dev = config->dev; + dev = cfg->dev; WARN_ON(!dev); if (regulator_desc->name == NULL || regulator_desc->ops == NULL) @@ -3624,6 +3625,16 @@ regulator_register(const struct regulator_desc *regulator_desc, if (rdev == NULL) return ERR_PTR(-ENOMEM); + /* + * Duplicate the config so the driver could override it after + * parsing init data. + */ + config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); + if (config == NULL) { + kfree(rdev); + return ERR_PTR(-ENOMEM); + } + init_data = regulator_of_get_init_data(dev, regulator_desc, &rdev->dev.of_node); if (!init_data) { @@ -3752,6 +3763,7 @@ add_dev: rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); + kfree(config); return rdev; unset_supplies: -- cgit v0.10.2 From 3307e9025d29105ecc5fa1144508715cdddba195 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 12:48:43 +0100 Subject: regulator: max77686: Add GPIO control Add enable control over GPIO for regulators supporting this: LDO20, LDO21, LDO22, buck8 and buck9. This is needed for proper (and full) configuration of the Maxim 77686 PMIC without creating redundant 'regulator-fixed' entries. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index 10d2062..15fb141 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,11 @@ #define MAX77686_DVS_UVSTEP 12500 /* + * Value for configuring buck[89] and LDO{20,21,22} as GPIO control. + * It is the same as 'off' for other regulators. + */ +#define MAX77686_GPIO_CONTROL 0x0 +/* * Values used for configuring LDOs and bucks. * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26 */ @@ -82,6 +88,8 @@ enum max77686_ramp_rate { }; struct max77686_data { + u64 gpio_enabled:MAX77686_REGULATORS; + /* Array indexed by regulator id */ unsigned int opmode[MAX77686_REGULATORS]; }; @@ -100,6 +108,26 @@ static unsigned int max77686_get_opmode_shift(int id) } } +/* + * When regulator is configured for GPIO control then it + * replaces "normal" mode. Any change from low power mode to normal + * should actually change to GPIO control. + * Map normal mode to proper value for such regulators. + */ +static unsigned int max77686_map_normal_mode(struct max77686_data *max77686, + int id) +{ + switch (id) { + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: + if (max77686->gpio_enabled & (1 << id)) + return MAX77686_GPIO_CONTROL; + } + + return MAX77686_NORMAL; +} + /* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */ static int max77686_set_suspend_disable(struct regulator_dev *rdev) { @@ -136,7 +164,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev, val = MAX77686_LDO_LOWPOWER_PWRREQ; break; case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = MAX77686_NORMAL; + val = max77686_map_normal_mode(max77686, id); break; default: pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", @@ -160,7 +188,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, { unsigned int val; struct max77686_data *max77686 = rdev_get_drvdata(rdev); - int ret; + int ret, id = rdev_get_id(rdev); switch (mode) { case REGULATOR_MODE_STANDBY: /* switch off */ @@ -170,7 +198,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, val = MAX77686_LDO_LOWPOWER_PWRREQ; break; case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = MAX77686_NORMAL; + val = max77686_map_normal_mode(max77686, id); break; default: pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", @@ -184,7 +212,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, if (ret) return ret; - max77686->opmode[rdev_get_id(rdev)] = val; + max77686->opmode[id] = val; return 0; } @@ -197,7 +225,7 @@ static int max77686_enable(struct regulator_dev *rdev) shift = max77686_get_opmode_shift(id); if (max77686->opmode[id] == MAX77686_OFF_PWRREQ) - max77686->opmode[id] = MAX77686_NORMAL; + max77686->opmode[id] = max77686_map_normal_mode(max77686, id); return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, @@ -229,6 +257,36 @@ static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) MAX77686_RAMP_RATE_MASK, ramp_value << 6); } +static int max77686_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct max77686_data *max77686 = config->driver_data; + + switch (desc->id) { + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: + config->ena_gpio = of_get_named_gpio(np, + "maxim,ena-gpios", 0); + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpio_initialized = true; + break; + default: + return 0; + } + + if (gpio_is_valid(config->ena_gpio)) { + max77686->gpio_enabled |= (1 << desc->id); + + return regmap_update_bits(config->regmap, desc->enable_reg, + desc->enable_mask, + MAX77686_GPIO_CONTROL); + } + + return 0; +} + static struct regulator_ops max77686_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -283,6 +341,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .name = "LDO"#num, \ .of_match = of_match_ptr("LDO"#num), \ .regulators_node = of_match_ptr("voltage-regulators"), \ + .of_parse_cb = max77686_of_parse_cb, \ .id = MAX77686_LDO##num, \ .ops = &max77686_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -355,6 +414,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .name = "BUCK"#num, \ .of_match = of_match_ptr("BUCK"#num), \ .regulators_node = of_match_ptr("voltage-regulators"), \ + .of_parse_cb = max77686_of_parse_cb, \ .id = MAX77686_BUCK##num, \ .ops = &max77686_ops, \ .type = REGULATOR_VOLTAGE, \ -- cgit v0.10.2 From bfa21a0dfe6915dc85953b5d40ea9dae5fdf205f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 12:48:42 +0100 Subject: regulator: Allow parsing custom properties when using simplified DT parsing When drivers use simplified DT parsing method (they provide 'regulator_desc.of_match') they still may want to parse custom properties for some of the regulators. For example some of the regulators support GPIO enable control. Add a driver-supplied callback for such case. This way the regulator core parses common bindings offloading a lot of code from drivers and still custom properties may be used. The callback, called for each parsed regulator, may modify the 'regulator_config' initially passed to regulator_register(). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c13b557..5fae8ca 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3635,7 +3635,7 @@ regulator_register(const struct regulator_desc *regulator_desc, return ERR_PTR(-ENOMEM); } - init_data = regulator_of_get_init_data(dev, regulator_desc, + init_data = regulator_of_get_init_data(dev, regulator_desc, config, &rdev->dev.of_node); if (!init_data) { init_data = config->init_data; diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 80ba2a3..c74ac87 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -38,11 +38,13 @@ struct regulator { #ifdef CONFIG_OF struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, + struct regulator_config *config, struct device_node **node); #else static inline struct regulator_init_data * regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, + struct regulator_config *config, struct device_node **node) { return NULL; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 91eaaf0..24e812c 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -270,6 +270,7 @@ EXPORT_SYMBOL_GPL(of_regulator_match); struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, + struct regulator_config *config, struct device_node **node) { struct device_node *search, *child; @@ -307,6 +308,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, break; } + if (desc->of_parse_cb) { + if (desc->of_parse_cb(child, desc, config)) { + dev_err(dev, + "driver callback failed to parse DT for regulator %s\n", + child->name); + init_data = NULL; + break; + } + } + of_node_get(child); *node = child; break; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 5f1e9ca..d4ad5b5 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -21,6 +21,7 @@ struct regmap; struct regulator_dev; +struct regulator_config; struct regulator_init_data; struct regulator_enable_gpio; @@ -205,6 +206,15 @@ enum regulator_type { * @supply_name: Identifying the regulator supply * @of_match: Name used to identify regulator in DT. * @regulators_node: Name of node containing regulator definitions in DT. + * @of_parse_cb: Optional callback called only if of_match is present. + * Will be called for each regulator parsed from DT, during + * init_data parsing. + * The regulator_config passed as argument to the callback will + * be a copy of config passed to regulator_register, valid only + * for this particular call. Callback may freely change the + * config but it cannot store it for later usage. + * Callback should return 0 on success or negative ERRNO + * indicating failure. * @id: Numerical identifier for the regulator. * @ops: Regulator operations table. * @irq: Interrupt number for the regulator. @@ -251,6 +261,9 @@ struct regulator_desc { const char *supply_name; const char *of_match; const char *regulators_node; + int (*of_parse_cb)(struct device_node *, + const struct regulator_desc *, + struct regulator_config *); int id; bool continuous_voltage_range; unsigned n_voltages; -- cgit v0.10.2 From 64d3d25c9b1bc06f3bd323d3b769dbdbcb616462 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 12:48:44 +0100 Subject: regulator: max77686: Document gpio properties Document usage of maxim,ena-gpios properties which turn on external/GPIO control over regulator. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index 75fdfaf..e39f0bc 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -39,6 +39,12 @@ to get matched with their hardware counterparts as follow: -BUCKn : 1-4. Use standard regulator bindings for it ('regulator-off-in-suspend'). + LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable + control. To turn this feature on this property must be added to the regulator + sub-node: + - maxim,ena-gpios : one GPIO specifier enable control (the gpio + flags are actually ignored and always + ACTIVE_HIGH is used) Example: @@ -65,4 +71,12 @@ Example: regulator-always-on; regulator-boot-on; }; + + buck9_reg { + regulator-compatible = "BUCK9"; + regulator-name = "CAM_ISP_CORE_1.2V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; + }; } -- cgit v0.10.2 From 5ab17145708e6ad4582b0372fb3a171be3379293 Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Thu, 8 Jan 2015 13:41:24 -0800 Subject: Input: small tweak to autorepeat handling If a device does not support autorepeat or does not emit any key events we should not be scanning all events in a packet to decide if we should start or stop autorepeat function. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/input.c b/drivers/input/input.c index 213e3a1..26199ab 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -152,12 +152,14 @@ static void input_pass_values(struct input_dev *dev, add_input_randomness(vals->type, vals->code, vals->value); /* trigger auto repeat for key events */ - for (v = vals; v != vals + count; v++) { - if (v->type == EV_KEY && v->value != 2) { - if (v->value) - input_start_autorepeat(dev, v->code); - else - input_stop_autorepeat(dev); + if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { + for (v = vals; v != vals + count; v++) { + if (v->type == EV_KEY && v->value != 2) { + if (v->value) + input_start_autorepeat(dev, v->code); + else + input_stop_autorepeat(dev); + } } } } -- cgit v0.10.2 From 2c50ad340c246b7f58f2d916006afe2d85d60698 Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Thu, 8 Jan 2015 13:47:37 -0800 Subject: Input: do not try to filter out events if handler is not a filter If given input handler is not a filter there is no point is iterating list of events in a packet to see if some of them need to be filtered out. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/input.c b/drivers/input/input.c index 26199ab..cc357f1 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -100,23 +100,24 @@ static unsigned int input_to_handler(struct input_handle *handle, struct input_value *end = vals; struct input_value *v; - for (v = vals; v != vals + count; v++) { - if (handler->filter && - handler->filter(handle, v->type, v->code, v->value)) - continue; - if (end != v) - *end = *v; - end++; + if (handler->filter) { + for (v = vals; v != vals + count; v++) { + if (handler->filter(handle, v->type, v->code, v->value)) + continue; + if (end != v) + *end = *v; + end++; + } + count = end - vals; } - count = end - vals; if (!count) return 0; if (handler->events) handler->events(handle, vals, count); else if (handler->event) - for (v = vals; v != end; v++) + for (v = vals; v != vals + count; v++) handler->event(handle, v->type, v->code, v->value); return count; @@ -143,8 +144,11 @@ static void input_pass_values(struct input_dev *dev, count = input_to_handler(handle, vals, count); } else { list_for_each_entry_rcu(handle, &dev->h_list, d_node) - if (handle->open) + if (handle->open) { count = input_to_handler(handle, vals, count); + if (!count) + break; + } } rcu_read_unlock(); -- cgit v0.10.2 From 5b6c26a9f6437c4467f5d7cbf0313a7ae2be86b1 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Mon, 29 Dec 2014 11:20:54 -0800 Subject: Input: add driver for AXP20x Power Enable Key This change adds support for the Power Enable Key found on MFD AXP202 and AXP209. Besides the basic support for the button, the driver adds two entries in sysfs to configure the time delay for power on/off. Signed-off-by: Carlo Caione Acked-by: Dmitry Torokhov [wens@csie.org: made axp20x_pek_remove() static; removed driver owner field; fixed path for sysfs entries] Signed-off-by: Chen-Yu Tsai Signed-off-by: Dmitry Torokhov diff --git a/Documentation/ABI/testing/sysfs-driver-input-axp-pek b/Documentation/ABI/testing/sysfs-driver-input-axp-pek new file mode 100644 index 0000000..a5e671b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-input-axp-pek @@ -0,0 +1,11 @@ +What: /sys/class/input/input(x)/device/startup +Date: March 2014 +Contact: Carlo Caione +Description: Startup time in us. Board is powered on if the button is pressed + for more than + +What: /sys/class/input/input(x)/device/shutdown +Date: March 2014 +Contact: Carlo Caione +Description: Shutdown time in us. Board is powered off if the button is pressed + for more than diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 9591917..9e610c4 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -426,6 +426,17 @@ config INPUT_TPS65218_PWRBUTTON To compile this driver as a module, choose M here. The module will be called tps65218-pwrbutton. +config INPUT_AXP20X_PEK + tristate "X-Powers AXP20X power button driver" + depends on MFD_AXP20X + help + Say Y here if you want to enable power key reporting via the + AXP20X PMIC. + + To compile this driver as a module, choose M here. The module will + be called axp20x-pek. + + config INPUT_TWL4030_PWRBUTTON tristate "TWL4030 Power button Driver" depends on TWL4030_CORE diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9a1083f..f8d9ea7 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o +obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c new file mode 100644 index 0000000..8dbd097 --- /dev/null +++ b/drivers/input/misc/axp20x-pek.c @@ -0,0 +1,282 @@ +/* + * axp20x power button driver. + * + * Copyright (C) 2013 Carlo Caione + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AXP20X_PEK_STARTUP_MASK (0xc0) +#define AXP20X_PEK_SHUTDOWN_MASK (0x03) + +struct axp20x_pek { + struct axp20x_dev *axp20x; + struct input_dev *input; + int irq_dbr; + int irq_dbf; +}; + +struct axp20x_time { + unsigned int time; + unsigned int idx; +}; + +static const struct axp20x_time startup_time[] = { + { .time = 128, .idx = 0 }, + { .time = 1000, .idx = 2 }, + { .time = 3000, .idx = 1 }, + { .time = 2000, .idx = 3 }, +}; + +static const struct axp20x_time shutdown_time[] = { + { .time = 4000, .idx = 0 }, + { .time = 6000, .idx = 1 }, + { .time = 8000, .idx = 2 }, + { .time = 10000, .idx = 3 }, +}; + +struct axp20x_pek_ext_attr { + const struct axp20x_time *p_time; + unsigned int mask; +}; + +static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = { + .p_time = startup_time, + .mask = AXP20X_PEK_STARTUP_MASK, +}; + +static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = { + .p_time = shutdown_time, + .mask = AXP20X_PEK_SHUTDOWN_MASK, +}; + +static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr) +{ + return container_of(attr, struct dev_ext_attribute, attr)->var; +} + +static ssize_t axp20x_show_ext_attr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); + struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr); + unsigned int val; + int ret, i; + + ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val); + if (ret != 0) + return ret; + + val &= axp20x_ea->mask; + val >>= ffs(axp20x_ea->mask) - 1; + + for (i = 0; i < 4; i++) + if (val == axp20x_ea->p_time[i].idx) + val = axp20x_ea->p_time[i].time; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t axp20x_store_ext_attr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); + struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr); + char val_str[20]; + size_t len; + int ret, i; + unsigned int val, idx = 0; + unsigned int best_err = UINT_MAX; + + val_str[sizeof(val_str) - 1] = '\0'; + strncpy(val_str, buf, sizeof(val_str) - 1); + len = strlen(val_str); + + if (len && val_str[len - 1] == '\n') + val_str[len - 1] = '\0'; + + ret = kstrtouint(val_str, 10, &val); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + unsigned int err; + + err = abs(axp20x_ea->p_time[i].time - val); + if (err < best_err) { + best_err = err; + idx = axp20x_ea->p_time[i].idx; + } + + if (!err) + break; + } + + idx <<= ffs(axp20x_ea->mask) - 1; + ret = regmap_update_bits(axp20x_pek->axp20x->regmap, + AXP20X_PEK_KEY, + axp20x_ea->mask, idx); + if (ret != 0) + return -EINVAL; + return count; +} + +static struct dev_ext_attribute axp20x_dev_attr_startup = { + .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), + .var = &axp20x_pek_startup_ext_attr +}; + +static struct dev_ext_attribute axp20x_dev_attr_shutdown = { + .attr = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), + .var = &axp20x_pek_shutdown_ext_attr +}; + +static irqreturn_t axp20x_pek_irq(int irq, void *pwr) +{ + struct input_dev *idev = pwr; + struct axp20x_pek *axp20x_pek = input_get_drvdata(idev); + + if (irq == axp20x_pek->irq_dbr) + input_report_key(idev, KEY_POWER, true); + else if (irq == axp20x_pek->irq_dbf) + input_report_key(idev, KEY_POWER, false); + + input_sync(idev); + + return IRQ_HANDLED; +} + +static int axp20x_pek_probe(struct platform_device *pdev) +{ + struct axp20x_pek *axp20x_pek; + struct axp20x_dev *axp20x; + struct input_dev *idev; + int error; + + axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), + GFP_KERNEL); + if (!axp20x_pek) + return -ENOMEM; + + axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); + axp20x = axp20x_pek->axp20x; + + axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); + if (axp20x_pek->irq_dbr < 0) { + dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n", + axp20x_pek->irq_dbr); + return axp20x_pek->irq_dbr; + } + axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc, + axp20x_pek->irq_dbr); + + axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); + if (axp20x_pek->irq_dbf < 0) { + dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n", + axp20x_pek->irq_dbf); + return axp20x_pek->irq_dbf; + } + axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc, + axp20x_pek->irq_dbf); + + axp20x_pek->input = devm_input_allocate_device(&pdev->dev); + if (!axp20x_pek->input) + return -ENOMEM; + + idev = axp20x_pek->input; + + idev->name = "axp20x-pek"; + idev->phys = "m1kbd/input2"; + idev->dev.parent = &pdev->dev; + + input_set_capability(idev, EV_KEY, KEY_POWER); + + input_set_drvdata(idev, axp20x_pek); + + error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, + axp20x_pek_irq, 0, + "axp20x-pek-dbr", idev); + if (error < 0) { + dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n", + axp20x_pek->irq_dbr, error); + + return error; + } + + error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, + axp20x_pek_irq, 0, + "axp20x-pek-dbf", idev); + if (error < 0) { + dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n", + axp20x_pek->irq_dbf, error); + return error; + } + + error = device_create_file(&pdev->dev, &axp20x_dev_attr_startup.attr); + if (error) + return error; + + error = device_create_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr); + if (error) + goto clear_startup_attr; + + error = input_register_device(idev); + if (error) { + dev_err(axp20x->dev, "Can't register input device: %d\n", + error); + goto clear_attr; + } + + platform_set_drvdata(pdev, axp20x_pek); + + return 0; + +clear_attr: + device_remove_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr); + +clear_startup_attr: + device_remove_file(&pdev->dev, &axp20x_dev_attr_startup.attr); + + return error; +} + +static int axp20x_pek_remove(struct platform_device *pdev) +{ + device_remove_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr); + device_remove_file(&pdev->dev, &axp20x_dev_attr_startup.attr); + + return 0; +} + +static struct platform_driver axp20x_pek_driver = { + .probe = axp20x_pek_probe, + .remove = axp20x_pek_remove, + .driver = { + .name = "axp20x-pek", + }, +}; +module_platform_driver(axp20x_pek_driver); + +MODULE_DESCRIPTION("axp20x Power Button"); +MODULE_AUTHOR("Carlo Caione "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From b388de88308fde104fb6520dbf9e7b342fd5761a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 29 Dec 2014 15:13:06 -0800 Subject: Input: axp20x-pek - switch over to using attribute group Instead of registering device attributes individually let's use attribute groups and also devm_* infrastructure to ease cleanup. Tested-by: Chen-Yu Tsai Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 8dbd097..f1c8447 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -138,17 +138,28 @@ static ssize_t axp20x_store_ext_attr(struct device *dev, axp20x_ea->mask, idx); if (ret != 0) return -EINVAL; + return count; } static struct dev_ext_attribute axp20x_dev_attr_startup = { .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), - .var = &axp20x_pek_startup_ext_attr + .var = &axp20x_pek_startup_ext_attr, }; static struct dev_ext_attribute axp20x_dev_attr_shutdown = { .attr = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), - .var = &axp20x_pek_shutdown_ext_attr + .var = &axp20x_pek_shutdown_ext_attr, +}; + +static struct attribute *axp20x_attributes[] = { + &axp20x_dev_attr_startup.attr.attr, + &axp20x_dev_attr_shutdown.attr.attr, + NULL, +}; + +static const struct attribute_group axp20x_attribute_group = { + .attrs = axp20x_attributes, }; static irqreturn_t axp20x_pek_irq(int irq, void *pwr) @@ -166,6 +177,13 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr) return IRQ_HANDLED; } +static void axp20x_remove_sysfs_group(void *_data) +{ + struct device *dev = _data; + + sysfs_remove_group(&dev->kobj, &axp20x_attribute_group); +} + static int axp20x_pek_probe(struct platform_device *pdev) { struct axp20x_pek *axp20x_pek; @@ -214,12 +232,11 @@ static int axp20x_pek_probe(struct platform_device *pdev) input_set_drvdata(idev, axp20x_pek); error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, - axp20x_pek_irq, 0, - "axp20x-pek-dbr", idev); + axp20x_pek_irq, 0, + "axp20x-pek-dbr", idev); if (error < 0) { dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n", axp20x_pek->irq_dbr, error); - return error; } @@ -232,45 +249,36 @@ static int axp20x_pek_probe(struct platform_device *pdev) return error; } - error = device_create_file(&pdev->dev, &axp20x_dev_attr_startup.attr); - if (error) + error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); + if (error) { + dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n", + error); return error; + } - error = device_create_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr); - if (error) - goto clear_startup_attr; + error = devm_add_action(&pdev->dev, + axp20x_remove_sysfs_group, &pdev->dev); + if (error) { + axp20x_remove_sysfs_group(&pdev->dev); + dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } error = input_register_device(idev); if (error) { dev_err(axp20x->dev, "Can't register input device: %d\n", error); - goto clear_attr; + return error; } platform_set_drvdata(pdev, axp20x_pek); return 0; - -clear_attr: - device_remove_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr); - -clear_startup_attr: - device_remove_file(&pdev->dev, &axp20x_dev_attr_startup.attr); - - return error; -} - -static int axp20x_pek_remove(struct platform_device *pdev) -{ - device_remove_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr); - device_remove_file(&pdev->dev, &axp20x_dev_attr_startup.attr); - - return 0; } static struct platform_driver axp20x_pek_driver = { .probe = axp20x_pek_probe, - .remove = axp20x_pek_remove, .driver = { .name = "axp20x-pek", }, -- cgit v0.10.2 From 2155355fda502e75cd942db101fbb08e1a826ba8 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 9 Jan 2015 10:45:13 +1100 Subject: xfs: move xfs_fs.h to libxfs Ioctl API definitions are shared with userspace, so move the header file that defines them all to libxfs along with all the other code shared with userspace. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h new file mode 100644 index 0000000..18dc721 --- /dev/null +++ b/fs/xfs/libxfs/xfs_fs.h @@ -0,0 +1,576 @@ +/* + * Copyright (c) 1995-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __XFS_FS_H__ +#define __XFS_FS_H__ + +/* + * SGI's XFS filesystem's major stuff (constants, structures) + */ + +/* + * Direct I/O attribute record used with XFS_IOC_DIOINFO + * d_miniosz is the min xfer size, xfer size multiple and file seek offset + * alignment. + */ +#ifndef HAVE_DIOATTR +struct dioattr { + __u32 d_mem; /* data buffer memory alignment */ + __u32 d_miniosz; /* min xfer size */ + __u32 d_maxiosz; /* max xfer size */ +}; +#endif + +/* + * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR. + */ +#ifndef HAVE_FSXATTR +struct fsxattr { + __u32 fsx_xflags; /* xflags field value (get/set) */ + __u32 fsx_extsize; /* extsize field value (get/set)*/ + __u32 fsx_nextents; /* nextents field value (get) */ + __u32 fsx_projid; /* project identifier (get/set) */ + unsigned char fsx_pad[12]; +}; +#endif + +/* + * Flags for the bs_xflags/fsx_xflags field + * There should be a one-to-one correspondence between these flags and the + * XFS_DIFLAG_s. + */ +#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ +#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ +#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ +#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */ +#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ +#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ +#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ +#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ +#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ +#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ +#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ +#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ +#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ +#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ +#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ + +/* + * Structure for XFS_IOC_GETBMAP. + * On input, fill in bmv_offset and bmv_length of the first structure + * to indicate the area of interest in the file, and bmv_entries with + * the number of array elements given back. The first structure is + * updated on return to give the offset and length for the next call. + */ +#ifndef HAVE_GETBMAP +struct getbmap { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output) */ +}; +#endif + +/* + * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries + * are used exactly as in the getbmap structure. The getbmapx structure + * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field + * is only used for the first structure. It contains input flags + * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled + * in by the XFS_IOC_GETBMAPX command for each returned structure after + * the first. + */ +#ifndef HAVE_GETBMAPX +struct getbmapx { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output). */ + __s32 bmv_iflags; /* input flags (1st structure) */ + __s32 bmv_oflags; /* output flags (after 1st structure)*/ + __s32 bmv_unused1; /* future use */ + __s32 bmv_unused2; /* future use */ +}; +#endif + +/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ +#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ +#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ +#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ +#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ +#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ +#define BMV_IF_VALID \ + (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ + BMV_IF_DELALLOC|BMV_IF_NO_HOLES) + +/* bmv_oflags values - returned for each non-header segment */ +#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ +#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ +#define BMV_OF_LAST 0x4 /* segment is the last in the file */ + +/* + * Structure for XFS_IOC_FSSETDM. + * For use by backup and restore programs to set the XFS on-disk inode + * fields di_dmevmask and di_dmstate. These must be set to exactly and + * only values previously obtained via xfs_bulkstat! (Specifically the + * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) + */ +#ifndef HAVE_FSDMIDATA +struct fsdmidata { + __u32 fsd_dmevmask; /* corresponds to di_dmevmask */ + __u16 fsd_padding; + __u16 fsd_dmstate; /* corresponds to di_dmstate */ +}; +#endif + +/* + * File segment locking set data type for 64 bit access. + * Also used for all the RESV/FREE interfaces. + */ +typedef struct xfs_flock64 { + __s16 l_type; + __s16 l_whence; + __s64 l_start; + __s64 l_len; /* len == 0 means until end of file */ + __s32 l_sysid; + __u32 l_pid; + __s32 l_pad[4]; /* reserve area */ +} xfs_flock64_t; + +/* + * Output for XFS_IOC_FSGEOMETRY_V1 + */ +typedef struct xfs_fsop_geom_v1 { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ +} xfs_fsop_geom_v1_t; + +/* + * Output for XFS_IOC_FSGEOMETRY + */ +typedef struct xfs_fsop_geom { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ + __u32 logsunit; /* log stripe unit, bytes */ +} xfs_fsop_geom_t; + +/* Output for XFS_FS_COUNTS */ +typedef struct xfs_fsop_counts { + __u64 freedata; /* free data section blocks */ + __u64 freertx; /* free rt extents */ + __u64 freeino; /* free inodes */ + __u64 allocino; /* total allocated inodes */ +} xfs_fsop_counts_t; + +/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ +typedef struct xfs_fsop_resblks { + __u64 resblks; + __u64 resblks_avail; +} xfs_fsop_resblks_t; + +#define XFS_FSOP_GEOM_VERSION 0 + +#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */ +#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */ +#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */ +#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */ +#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */ +#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */ +#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */ +#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ +#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ +#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ +#define XFS_FSOP_GEOM_FLAGS_PROJID32 0x0800 /* 32-bit project IDs */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ +#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ +#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */ +#define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */ +#define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */ + +/* + * Minimum and maximum sizes need for growth checks. + * + * Block counts are in units of filesystem blocks, not basic blocks. + */ +#define XFS_MIN_AG_BLOCKS 64 +#define XFS_MIN_LOG_BLOCKS 512ULL +#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) +#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) + +/* keep the maximum size under 2^31 by a small amount */ +#define XFS_MAX_LOG_BYTES \ + ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) + +/* Used for sanity checks on superblock */ +#define XFS_MAX_DBLOCKS(s) ((xfs_rfsblock_t)(s)->sb_agcount * (s)->sb_agblocks) +#define XFS_MIN_DBLOCKS(s) ((xfs_rfsblock_t)((s)->sb_agcount - 1) * \ + (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) + +/* + * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT + */ +typedef struct xfs_growfs_data { + __u64 newblocks; /* new data subvol size, fsblocks */ + __u32 imaxpct; /* new inode space percentage limit */ +} xfs_growfs_data_t; + +typedef struct xfs_growfs_log { + __u32 newblocks; /* new log size, fsblocks */ + __u32 isint; /* 1 if new log is internal */ +} xfs_growfs_log_t; + +typedef struct xfs_growfs_rt { + __u64 newblocks; /* new realtime size, fsblocks */ + __u32 extsize; /* new realtime extent size, fsblocks */ +} xfs_growfs_rt_t; + + +/* + * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE + */ +typedef struct xfs_bstime { + time_t tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} xfs_bstime_t; + +typedef struct xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + xfs_bstime_t bs_atime; /* access time */ + xfs_bstime_t bs_mtime; /* modify time */ + xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid_lo; /* lower part of project id */ +#define bs_projid bs_projid_lo /* (previously just bs_projid) */ + __u16 bs_forkoff; /* inode fork offset in bytes */ + __u16 bs_projid_hi; /* higher part of project id */ + unsigned char bs_pad[10]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} xfs_bstat_t; + +/* + * Project quota id helpers (previously projid was 16bit only + * and using two 16bit values to hold new 32bit projid was choosen + * to retain compatibility with "old" filesystems). + */ +static inline __uint32_t +bstat_get_projid(struct xfs_bstat *bs) +{ + return (__uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo; +} + +/* + * The user-level BulkStat Request interface structure. + */ +typedef struct xfs_fsop_bulkreq { + __u64 __user *lastip; /* last inode # pointer */ + __s32 icount; /* count of entries in buffer */ + void __user *ubuffer;/* user buffer for inode desc. */ + __s32 __user *ocount; /* output count pointer */ +} xfs_fsop_bulkreq_t; + + +/* + * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). + */ +typedef struct xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} xfs_inogrp_t; + + +/* + * Error injection. + */ +typedef struct xfs_error_injection { + __s32 fd; + __s32 errtag; +} xfs_error_injection_t; + + +/* + * Speculative preallocation trimming. + */ +#define XFS_EOFBLOCKS_VERSION 1 +struct xfs_fs_eofblocks { + __u32 eof_version; + __u32 eof_flags; + uid_t eof_uid; + gid_t eof_gid; + prid_t eof_prid; + __u32 pad32; + __u64 eof_min_file_size; + __u64 pad64[12]; +}; + +/* eof_flags values */ +#define XFS_EOF_FLAGS_SYNC (1 << 0) /* sync/wait mode scan */ +#define XFS_EOF_FLAGS_UID (1 << 1) /* filter by uid */ +#define XFS_EOF_FLAGS_GID (1 << 2) /* filter by gid */ +#define XFS_EOF_FLAGS_PRID (1 << 3) /* filter by project id */ +#define XFS_EOF_FLAGS_MINFILESIZE (1 << 4) /* filter by min file size */ +#define XFS_EOF_FLAGS_UNION (1 << 5) /* union filter algorithm; + * kernel only, not included in + * valid mask */ +#define XFS_EOF_FLAGS_VALID \ + (XFS_EOF_FLAGS_SYNC | \ + XFS_EOF_FLAGS_UID | \ + XFS_EOF_FLAGS_GID | \ + XFS_EOF_FLAGS_PRID | \ + XFS_EOF_FLAGS_MINFILESIZE) + + +/* + * The user-level Handle Request interface structure. + */ +typedef struct xfs_fsop_handlereq { + __u32 fd; /* fd for FD_TO_HANDLE */ + void __user *path; /* user pathname */ + __u32 oflags; /* open flags */ + void __user *ihandle;/* user supplied handle */ + __u32 ihandlen; /* user supplied length */ + void __user *ohandle;/* user buffer for handle */ + __u32 __user *ohandlen;/* user buffer length */ +} xfs_fsop_handlereq_t; + +/* + * Compound structures for passing args through Handle Request interfaces + * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle + * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and + * XFS_IOC_ATTRMULTI_BY_HANDLE + */ + +typedef struct xfs_fsop_setdm_handlereq { + struct xfs_fsop_handlereq hreq; /* handle information */ + struct fsdmidata __user *data; /* DMAPI data */ +} xfs_fsop_setdm_handlereq_t; + +typedef struct xfs_attrlist_cursor { + __u32 opaque[4]; +} xfs_attrlist_cursor_t; + +typedef struct xfs_fsop_attrlist_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ + __u32 flags; /* which namespace to use */ + __u32 buflen; /* length of buffer supplied */ + void __user *buffer; /* returned names */ +} xfs_fsop_attrlist_handlereq_t; + +typedef struct xfs_attr_multiop { + __u32 am_opcode; +#define ATTR_OP_GET 1 /* return the indicated attr's value */ +#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ +#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ + __s32 am_error; + void __user *am_attrname; + void __user *am_attrvalue; + __u32 am_length; + __u32 am_flags; +} xfs_attr_multiop_t; + +typedef struct xfs_fsop_attrmulti_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + __u32 opcount;/* count of following multiop */ + struct xfs_attr_multiop __user *ops; /* attr_multi data */ +} xfs_fsop_attrmulti_handlereq_t; + +/* + * per machine unique filesystem identifier types. + */ +typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ + +typedef struct xfs_fid { + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; + __u32 fid_gen; /* generation number */ + __u64 fid_ino; /* 64 bits inode number */ +} xfs_fid_t; + +typedef struct xfs_handle { + union { + __s64 align; /* force alignment of ha_fid */ + xfs_fsid_t _ha_fsid; /* unique file system identifier */ + } ha_u; + xfs_fid_t ha_fid; /* file system specific file ID */ +} xfs_handle_t; +#define ha_fsid ha_u._ha_fsid + +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ + - (char *) &(handle)) \ + + (handle).ha_fid.fid_len) + +/* + * Structure passed to XFS_IOC_SWAPEXT + */ +typedef struct xfs_swapext +{ + __int64_t sx_version; /* version */ +#define XFS_SX_VERSION 0 + __int64_t sx_fdtarget; /* fd of target file */ + __int64_t sx_fdtmp; /* fd of tmp file */ + xfs_off_t sx_offset; /* offset into file */ + xfs_off_t sx_length; /* leng from offset */ + char sx_pad[16]; /* pad space, unused */ + xfs_bstat_t sx_stat; /* stat of target b4 copy */ +} xfs_swapext_t; + +/* + * Flags for going down operation + */ +#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ +#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ +#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ + +/* + * ioctl commands that are used by Linux filesystems + */ +#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS +#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS +#define XFS_IOC_GETVERSION FS_IOC_GETVERSION + +/* + * ioctl commands that replace IRIX fcntl()'s + * For 'documentation' purposed more than anything else, + * the "cmd #" field reflects the IRIX fcntl number. + */ +#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) +#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) +#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) +#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) +#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) +#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) +#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) +#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) +#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) +#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) +#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) +#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) +#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) +#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) +/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ +/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ +#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) +#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64) +#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks) + +/* + * ioctl commands that replace IRIX syssgi()'s + */ +#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) +#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) +#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) +#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) +#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) +#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) +#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) +#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) +#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) +#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) +#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) +#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) +#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks) +#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) +#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) +#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) +/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ + +/* XFS_IOC_FREEZE -- FIFREEZE 119 */ +/* XFS_IOC_THAW -- FITHAW 120 */ +#ifndef FIFREEZE +#define XFS_IOC_FREEZE _IOWR('X', 119, int) +#define XFS_IOC_THAW _IOWR('X', 120, int) +#endif + +#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) +#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) +#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) +#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) +#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) +/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ + + +#ifndef HAVE_BBMACROS +/* + * Block I/O parameterization. A basic block (BB) is the lowest size of + * filesystem allocation, and must equal 512. Length units given to bio + * routines are in BB's. + */ +#define BBSHIFT 9 +#define BBSIZE (1<> BBSHIFT) +#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOB(bbs) ((bbs) << BBSHIFT) +#endif + +#endif /* __XFS_FS_H__ */ diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h deleted file mode 100644 index 18dc721..0000000 --- a/fs/xfs/xfs_fs.h +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (c) 1995-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_FS_H__ -#define __XFS_FS_H__ - -/* - * SGI's XFS filesystem's major stuff (constants, structures) - */ - -/* - * Direct I/O attribute record used with XFS_IOC_DIOINFO - * d_miniosz is the min xfer size, xfer size multiple and file seek offset - * alignment. - */ -#ifndef HAVE_DIOATTR -struct dioattr { - __u32 d_mem; /* data buffer memory alignment */ - __u32 d_miniosz; /* min xfer size */ - __u32 d_maxiosz; /* max xfer size */ -}; -#endif - -/* - * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR. - */ -#ifndef HAVE_FSXATTR -struct fsxattr { - __u32 fsx_xflags; /* xflags field value (get/set) */ - __u32 fsx_extsize; /* extsize field value (get/set)*/ - __u32 fsx_nextents; /* nextents field value (get) */ - __u32 fsx_projid; /* project identifier (get/set) */ - unsigned char fsx_pad[12]; -}; -#endif - -/* - * Flags for the bs_xflags/fsx_xflags field - * There should be a one-to-one correspondence between these flags and the - * XFS_DIFLAG_s. - */ -#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ -#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ -#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ -#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */ -#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ -#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ -#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ -#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ -#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ -#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ -#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ -#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ -#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ -#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ -#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ - -/* - * Structure for XFS_IOC_GETBMAP. - * On input, fill in bmv_offset and bmv_length of the first structure - * to indicate the area of interest in the file, and bmv_entries with - * the number of array elements given back. The first structure is - * updated on return to give the offset and length for the next call. - */ -#ifndef HAVE_GETBMAP -struct getbmap { - __s64 bmv_offset; /* file offset of segment in blocks */ - __s64 bmv_block; /* starting block (64-bit daddr_t) */ - __s64 bmv_length; /* length of segment, blocks */ - __s32 bmv_count; /* # of entries in array incl. 1st */ - __s32 bmv_entries; /* # of entries filled in (output) */ -}; -#endif - -/* - * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries - * are used exactly as in the getbmap structure. The getbmapx structure - * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field - * is only used for the first structure. It contains input flags - * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled - * in by the XFS_IOC_GETBMAPX command for each returned structure after - * the first. - */ -#ifndef HAVE_GETBMAPX -struct getbmapx { - __s64 bmv_offset; /* file offset of segment in blocks */ - __s64 bmv_block; /* starting block (64-bit daddr_t) */ - __s64 bmv_length; /* length of segment, blocks */ - __s32 bmv_count; /* # of entries in array incl. 1st */ - __s32 bmv_entries; /* # of entries filled in (output). */ - __s32 bmv_iflags; /* input flags (1st structure) */ - __s32 bmv_oflags; /* output flags (after 1st structure)*/ - __s32 bmv_unused1; /* future use */ - __s32 bmv_unused2; /* future use */ -}; -#endif - -/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ -#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ -#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ -#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ -#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ -#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ -#define BMV_IF_VALID \ - (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ - BMV_IF_DELALLOC|BMV_IF_NO_HOLES) - -/* bmv_oflags values - returned for each non-header segment */ -#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ -#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ -#define BMV_OF_LAST 0x4 /* segment is the last in the file */ - -/* - * Structure for XFS_IOC_FSSETDM. - * For use by backup and restore programs to set the XFS on-disk inode - * fields di_dmevmask and di_dmstate. These must be set to exactly and - * only values previously obtained via xfs_bulkstat! (Specifically the - * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) - */ -#ifndef HAVE_FSDMIDATA -struct fsdmidata { - __u32 fsd_dmevmask; /* corresponds to di_dmevmask */ - __u16 fsd_padding; - __u16 fsd_dmstate; /* corresponds to di_dmstate */ -}; -#endif - -/* - * File segment locking set data type for 64 bit access. - * Also used for all the RESV/FREE interfaces. - */ -typedef struct xfs_flock64 { - __s16 l_type; - __s16 l_whence; - __s64 l_start; - __s64 l_len; /* len == 0 means until end of file */ - __s32 l_sysid; - __u32 l_pid; - __s32 l_pad[4]; /* reserve area */ -} xfs_flock64_t; - -/* - * Output for XFS_IOC_FSGEOMETRY_V1 - */ -typedef struct xfs_fsop_geom_v1 { - __u32 blocksize; /* filesystem (data) block size */ - __u32 rtextsize; /* realtime extent size */ - __u32 agblocks; /* fsblocks in an AG */ - __u32 agcount; /* number of allocation groups */ - __u32 logblocks; /* fsblocks in the log */ - __u32 sectsize; /* (data) sector size, bytes */ - __u32 inodesize; /* inode size in bytes */ - __u32 imaxpct; /* max allowed inode space(%) */ - __u64 datablocks; /* fsblocks in data subvolume */ - __u64 rtblocks; /* fsblocks in realtime subvol */ - __u64 rtextents; /* rt extents in realtime subvol*/ - __u64 logstart; /* starting fsblock of the log */ - unsigned char uuid[16]; /* unique id of the filesystem */ - __u32 sunit; /* stripe unit, fsblocks */ - __u32 swidth; /* stripe width, fsblocks */ - __s32 version; /* structure version */ - __u32 flags; /* superblock version flags */ - __u32 logsectsize; /* log sector size, bytes */ - __u32 rtsectsize; /* realtime sector size, bytes */ - __u32 dirblocksize; /* directory block size, bytes */ -} xfs_fsop_geom_v1_t; - -/* - * Output for XFS_IOC_FSGEOMETRY - */ -typedef struct xfs_fsop_geom { - __u32 blocksize; /* filesystem (data) block size */ - __u32 rtextsize; /* realtime extent size */ - __u32 agblocks; /* fsblocks in an AG */ - __u32 agcount; /* number of allocation groups */ - __u32 logblocks; /* fsblocks in the log */ - __u32 sectsize; /* (data) sector size, bytes */ - __u32 inodesize; /* inode size in bytes */ - __u32 imaxpct; /* max allowed inode space(%) */ - __u64 datablocks; /* fsblocks in data subvolume */ - __u64 rtblocks; /* fsblocks in realtime subvol */ - __u64 rtextents; /* rt extents in realtime subvol*/ - __u64 logstart; /* starting fsblock of the log */ - unsigned char uuid[16]; /* unique id of the filesystem */ - __u32 sunit; /* stripe unit, fsblocks */ - __u32 swidth; /* stripe width, fsblocks */ - __s32 version; /* structure version */ - __u32 flags; /* superblock version flags */ - __u32 logsectsize; /* log sector size, bytes */ - __u32 rtsectsize; /* realtime sector size, bytes */ - __u32 dirblocksize; /* directory block size, bytes */ - __u32 logsunit; /* log stripe unit, bytes */ -} xfs_fsop_geom_t; - -/* Output for XFS_FS_COUNTS */ -typedef struct xfs_fsop_counts { - __u64 freedata; /* free data section blocks */ - __u64 freertx; /* free rt extents */ - __u64 freeino; /* free inodes */ - __u64 allocino; /* total allocated inodes */ -} xfs_fsop_counts_t; - -/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ -typedef struct xfs_fsop_resblks { - __u64 resblks; - __u64 resblks_avail; -} xfs_fsop_resblks_t; - -#define XFS_FSOP_GEOM_VERSION 0 - -#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */ -#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */ -#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */ -#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */ -#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */ -#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */ -#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */ -#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */ -#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ -#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ -#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ -#define XFS_FSOP_GEOM_FLAGS_PROJID32 0x0800 /* 32-bit project IDs */ -#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ -#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ -#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */ -#define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */ -#define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */ - -/* - * Minimum and maximum sizes need for growth checks. - * - * Block counts are in units of filesystem blocks, not basic blocks. - */ -#define XFS_MIN_AG_BLOCKS 64 -#define XFS_MIN_LOG_BLOCKS 512ULL -#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) -#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) - -/* keep the maximum size under 2^31 by a small amount */ -#define XFS_MAX_LOG_BYTES \ - ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) - -/* Used for sanity checks on superblock */ -#define XFS_MAX_DBLOCKS(s) ((xfs_rfsblock_t)(s)->sb_agcount * (s)->sb_agblocks) -#define XFS_MIN_DBLOCKS(s) ((xfs_rfsblock_t)((s)->sb_agcount - 1) * \ - (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) - -/* - * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT - */ -typedef struct xfs_growfs_data { - __u64 newblocks; /* new data subvol size, fsblocks */ - __u32 imaxpct; /* new inode space percentage limit */ -} xfs_growfs_data_t; - -typedef struct xfs_growfs_log { - __u32 newblocks; /* new log size, fsblocks */ - __u32 isint; /* 1 if new log is internal */ -} xfs_growfs_log_t; - -typedef struct xfs_growfs_rt { - __u64 newblocks; /* new realtime size, fsblocks */ - __u32 extsize; /* new realtime extent size, fsblocks */ -} xfs_growfs_rt_t; - - -/* - * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE - */ -typedef struct xfs_bstime { - time_t tv_sec; /* seconds */ - __s32 tv_nsec; /* and nanoseconds */ -} xfs_bstime_t; - -typedef struct xfs_bstat { - __u64 bs_ino; /* inode number */ - __u16 bs_mode; /* type and mode */ - __u16 bs_nlink; /* number of links */ - __u32 bs_uid; /* user id */ - __u32 bs_gid; /* group id */ - __u32 bs_rdev; /* device value */ - __s32 bs_blksize; /* block size */ - __s64 bs_size; /* file size */ - xfs_bstime_t bs_atime; /* access time */ - xfs_bstime_t bs_mtime; /* modify time */ - xfs_bstime_t bs_ctime; /* inode change time */ - int64_t bs_blocks; /* number of blocks */ - __u32 bs_xflags; /* extended flags */ - __s32 bs_extsize; /* extent size */ - __s32 bs_extents; /* number of extents */ - __u32 bs_gen; /* generation count */ - __u16 bs_projid_lo; /* lower part of project id */ -#define bs_projid bs_projid_lo /* (previously just bs_projid) */ - __u16 bs_forkoff; /* inode fork offset in bytes */ - __u16 bs_projid_hi; /* higher part of project id */ - unsigned char bs_pad[10]; /* pad space, unused */ - __u32 bs_dmevmask; /* DMIG event mask */ - __u16 bs_dmstate; /* DMIG state info */ - __u16 bs_aextents; /* attribute number of extents */ -} xfs_bstat_t; - -/* - * Project quota id helpers (previously projid was 16bit only - * and using two 16bit values to hold new 32bit projid was choosen - * to retain compatibility with "old" filesystems). - */ -static inline __uint32_t -bstat_get_projid(struct xfs_bstat *bs) -{ - return (__uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo; -} - -/* - * The user-level BulkStat Request interface structure. - */ -typedef struct xfs_fsop_bulkreq { - __u64 __user *lastip; /* last inode # pointer */ - __s32 icount; /* count of entries in buffer */ - void __user *ubuffer;/* user buffer for inode desc. */ - __s32 __user *ocount; /* output count pointer */ -} xfs_fsop_bulkreq_t; - - -/* - * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). - */ -typedef struct xfs_inogrp { - __u64 xi_startino; /* starting inode number */ - __s32 xi_alloccount; /* # bits set in allocmask */ - __u64 xi_allocmask; /* mask of allocated inodes */ -} xfs_inogrp_t; - - -/* - * Error injection. - */ -typedef struct xfs_error_injection { - __s32 fd; - __s32 errtag; -} xfs_error_injection_t; - - -/* - * Speculative preallocation trimming. - */ -#define XFS_EOFBLOCKS_VERSION 1 -struct xfs_fs_eofblocks { - __u32 eof_version; - __u32 eof_flags; - uid_t eof_uid; - gid_t eof_gid; - prid_t eof_prid; - __u32 pad32; - __u64 eof_min_file_size; - __u64 pad64[12]; -}; - -/* eof_flags values */ -#define XFS_EOF_FLAGS_SYNC (1 << 0) /* sync/wait mode scan */ -#define XFS_EOF_FLAGS_UID (1 << 1) /* filter by uid */ -#define XFS_EOF_FLAGS_GID (1 << 2) /* filter by gid */ -#define XFS_EOF_FLAGS_PRID (1 << 3) /* filter by project id */ -#define XFS_EOF_FLAGS_MINFILESIZE (1 << 4) /* filter by min file size */ -#define XFS_EOF_FLAGS_UNION (1 << 5) /* union filter algorithm; - * kernel only, not included in - * valid mask */ -#define XFS_EOF_FLAGS_VALID \ - (XFS_EOF_FLAGS_SYNC | \ - XFS_EOF_FLAGS_UID | \ - XFS_EOF_FLAGS_GID | \ - XFS_EOF_FLAGS_PRID | \ - XFS_EOF_FLAGS_MINFILESIZE) - - -/* - * The user-level Handle Request interface structure. - */ -typedef struct xfs_fsop_handlereq { - __u32 fd; /* fd for FD_TO_HANDLE */ - void __user *path; /* user pathname */ - __u32 oflags; /* open flags */ - void __user *ihandle;/* user supplied handle */ - __u32 ihandlen; /* user supplied length */ - void __user *ohandle;/* user buffer for handle */ - __u32 __user *ohandlen;/* user buffer length */ -} xfs_fsop_handlereq_t; - -/* - * Compound structures for passing args through Handle Request interfaces - * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle - * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and - * XFS_IOC_ATTRMULTI_BY_HANDLE - */ - -typedef struct xfs_fsop_setdm_handlereq { - struct xfs_fsop_handlereq hreq; /* handle information */ - struct fsdmidata __user *data; /* DMAPI data */ -} xfs_fsop_setdm_handlereq_t; - -typedef struct xfs_attrlist_cursor { - __u32 opaque[4]; -} xfs_attrlist_cursor_t; - -typedef struct xfs_fsop_attrlist_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ - __u32 flags; /* which namespace to use */ - __u32 buflen; /* length of buffer supplied */ - void __user *buffer; /* returned names */ -} xfs_fsop_attrlist_handlereq_t; - -typedef struct xfs_attr_multiop { - __u32 am_opcode; -#define ATTR_OP_GET 1 /* return the indicated attr's value */ -#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ -#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ - __s32 am_error; - void __user *am_attrname; - void __user *am_attrvalue; - __u32 am_length; - __u32 am_flags; -} xfs_attr_multiop_t; - -typedef struct xfs_fsop_attrmulti_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - __u32 opcount;/* count of following multiop */ - struct xfs_attr_multiop __user *ops; /* attr_multi data */ -} xfs_fsop_attrmulti_handlereq_t; - -/* - * per machine unique filesystem identifier types. - */ -typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ - -typedef struct xfs_fid { - __u16 fid_len; /* length of remainder */ - __u16 fid_pad; - __u32 fid_gen; /* generation number */ - __u64 fid_ino; /* 64 bits inode number */ -} xfs_fid_t; - -typedef struct xfs_handle { - union { - __s64 align; /* force alignment of ha_fid */ - xfs_fsid_t _ha_fsid; /* unique file system identifier */ - } ha_u; - xfs_fid_t ha_fid; /* file system specific file ID */ -} xfs_handle_t; -#define ha_fsid ha_u._ha_fsid - -#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ - - (char *) &(handle)) \ - + (handle).ha_fid.fid_len) - -/* - * Structure passed to XFS_IOC_SWAPEXT - */ -typedef struct xfs_swapext -{ - __int64_t sx_version; /* version */ -#define XFS_SX_VERSION 0 - __int64_t sx_fdtarget; /* fd of target file */ - __int64_t sx_fdtmp; /* fd of tmp file */ - xfs_off_t sx_offset; /* offset into file */ - xfs_off_t sx_length; /* leng from offset */ - char sx_pad[16]; /* pad space, unused */ - xfs_bstat_t sx_stat; /* stat of target b4 copy */ -} xfs_swapext_t; - -/* - * Flags for going down operation - */ -#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ -#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ -#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ - -/* - * ioctl commands that are used by Linux filesystems - */ -#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS -#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS -#define XFS_IOC_GETVERSION FS_IOC_GETVERSION - -/* - * ioctl commands that replace IRIX fcntl()'s - * For 'documentation' purposed more than anything else, - * the "cmd #" field reflects the IRIX fcntl number. - */ -#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) -#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) -#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) -#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) -#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) -#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) -#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) -#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) -#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) -#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) -#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) -#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) -#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) -#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) -#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) -/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ -/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ -#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) -#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64) -#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks) - -/* - * ioctl commands that replace IRIX syssgi()'s - */ -#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) -#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) -#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) -#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) -#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) -#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) -#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) -#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) -#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) -#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) -#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) -#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) -#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) -#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) -#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks) -#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) -#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) -#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) -/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ - -/* XFS_IOC_FREEZE -- FIFREEZE 119 */ -/* XFS_IOC_THAW -- FITHAW 120 */ -#ifndef FIFREEZE -#define XFS_IOC_FREEZE _IOWR('X', 119, int) -#define XFS_IOC_THAW _IOWR('X', 120, int) -#endif - -#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) -#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) -#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) -#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) -#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) -/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ - - -#ifndef HAVE_BBMACROS -/* - * Block I/O parameterization. A basic block (BB) is the lowest size of - * filesystem allocation, and must equal 512. Length units given to bio - * routines are in BB's. - */ -#define BBSHIFT 9 -#define BBSIZE (1<> BBSHIFT) -#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) -#define BBTOB(bbs) ((bbs) << BBSHIFT) -#endif - -#endif /* __XFS_FS_H__ */ -- cgit v0.10.2 From 5ebdc213ac02877e23fe7594d4b92b120488aac9 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 9 Jan 2015 10:46:31 +1100 Subject: xfs: move xfs_types.h to libxfs The types used by the core XFS code are common between kernel and userspace. xfs_types.h is duplicated in both kernel and userspace, so move it to libxfs along with all the other shared code. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h new file mode 100644 index 0000000..b79dc66 --- /dev/null +++ b/fs/xfs/libxfs/xfs_types.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __XFS_TYPES_H__ +#define __XFS_TYPES_H__ + +typedef __uint32_t prid_t; /* project ID */ + +typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef __uint32_t xfs_agino_t; /* inode # within allocation grp */ +typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ +typedef __uint32_t xfs_agnumber_t; /* allocation group number */ +typedef __int32_t xfs_extnum_t; /* # of extents in a file */ +typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ +typedef __int64_t xfs_fsize_t; /* bytes in a file */ +typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ + +typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ +typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ + +typedef __int64_t xfs_lsn_t; /* log sequence number */ +typedef __int32_t xfs_tid_t; /* transaction identifier */ + +typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ +typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ + +typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __uint64_t xfs_fileoff_t; /* block number in a file */ +typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ + +typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ + +/* + * Null values for the types. + */ +#define NULLFSBLOCK ((xfs_fsblock_t)-1) +#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) +#define NULLRTBLOCK ((xfs_rtblock_t)-1) +#define NULLFILEOFF ((xfs_fileoff_t)-1) + +#define NULLAGBLOCK ((xfs_agblock_t)-1) +#define NULLAGNUMBER ((xfs_agnumber_t)-1) +#define NULLEXTNUM ((xfs_extnum_t)-1) + +#define NULLCOMMITLSN ((xfs_lsn_t)-1) + +#define NULLFSINO ((xfs_ino_t)-1) +#define NULLAGINO ((xfs_agino_t)-1) + +/* + * Max values for extlen, extnum, aextnum. + */ +#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ +#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ +#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ + +/* + * Minimum and maximum blocksize and sectorsize. + * The blocksize upper limit is pretty much arbitrary. + * The sectorsize upper limit is due to sizeof(sb_sectsize). + */ +#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ +#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) +#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) +#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ +#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) +#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) + +/* + * Inode fork identifiers. + */ +#define XFS_DATA_FORK 0 +#define XFS_ATTR_FORK 1 + +/* + * Min numbers of data/attr fork btree root pointers. + */ +#define MINDBTPTRS 3 +#define MINABTPTRS 2 + +/* + * MAXNAMELEN is the length (including the terminating null) of + * the longest permissible file (component) name. + */ +#define MAXNAMELEN 256 + +typedef enum { + XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi +} xfs_lookup_t; + +typedef enum { + XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, + XFS_BTNUM_FINOi, XFS_BTNUM_MAX +} xfs_btnum_t; + +struct xfs_name { + const unsigned char *name; + int len; + int type; +}; + +/* + * uid_t and gid_t are hard-coded to 32 bits in the inode. + * Hence, an 'id' in a dquot is 32 bits.. + */ +typedef __uint32_t xfs_dqid_t; + +/* + * Constants for bit manipulations. + */ +#define XFS_NBBYLOG 3 /* log2(NBBY) */ +#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ +#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) +#define XFS_NBWORD (1 << XFS_NBWORDLOG) +#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) + + +#endif /* __XFS_TYPES_H__ */ diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h deleted file mode 100644 index b79dc66..0000000 --- a/fs/xfs/xfs_types.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_TYPES_H__ -#define __XFS_TYPES_H__ - -typedef __uint32_t prid_t; /* project ID */ - -typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ -typedef __uint32_t xfs_agino_t; /* inode # within allocation grp */ -typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ -typedef __uint32_t xfs_agnumber_t; /* allocation group number */ -typedef __int32_t xfs_extnum_t; /* # of extents in a file */ -typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ -typedef __int64_t xfs_fsize_t; /* bytes in a file */ -typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ - -typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ -typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ - -typedef __int64_t xfs_lsn_t; /* log sequence number */ -typedef __int32_t xfs_tid_t; /* transaction identifier */ - -typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ -typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ - -typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ -typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ -typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ -typedef __uint64_t xfs_fileoff_t; /* block number in a file */ -typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ - -typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ -typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ - -/* - * Null values for the types. - */ -#define NULLFSBLOCK ((xfs_fsblock_t)-1) -#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) -#define NULLRTBLOCK ((xfs_rtblock_t)-1) -#define NULLFILEOFF ((xfs_fileoff_t)-1) - -#define NULLAGBLOCK ((xfs_agblock_t)-1) -#define NULLAGNUMBER ((xfs_agnumber_t)-1) -#define NULLEXTNUM ((xfs_extnum_t)-1) - -#define NULLCOMMITLSN ((xfs_lsn_t)-1) - -#define NULLFSINO ((xfs_ino_t)-1) -#define NULLAGINO ((xfs_agino_t)-1) - -/* - * Max values for extlen, extnum, aextnum. - */ -#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ -#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ -#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ - -/* - * Minimum and maximum blocksize and sectorsize. - * The blocksize upper limit is pretty much arbitrary. - * The sectorsize upper limit is due to sizeof(sb_sectsize). - */ -#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ -#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ -#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) -#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) -#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ -#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ -#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) -#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) - -/* - * Inode fork identifiers. - */ -#define XFS_DATA_FORK 0 -#define XFS_ATTR_FORK 1 - -/* - * Min numbers of data/attr fork btree root pointers. - */ -#define MINDBTPTRS 3 -#define MINABTPTRS 2 - -/* - * MAXNAMELEN is the length (including the terminating null) of - * the longest permissible file (component) name. - */ -#define MAXNAMELEN 256 - -typedef enum { - XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi -} xfs_lookup_t; - -typedef enum { - XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, - XFS_BTNUM_FINOi, XFS_BTNUM_MAX -} xfs_btnum_t; - -struct xfs_name { - const unsigned char *name; - int len; - int type; -}; - -/* - * uid_t and gid_t are hard-coded to 32 bits in the inode. - * Hence, an 'id' in a dquot is 32 bits.. - */ -typedef __uint32_t xfs_dqid_t; - -/* - * Constants for bit manipulations. - */ -#define XFS_NBBYLOG 3 /* log2(NBBY) */ -#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ -#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) -#define XFS_NBWORD (1 << XFS_NBWORDLOG) -#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) - - -#endif /* __XFS_TYPES_H__ */ -- cgit v0.10.2 From 9799b438ce21662fa173ffc0b30d93567a71dfa0 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 9 Jan 2015 10:46:49 +1100 Subject: xfs: move struct xfs_bmalloca to libxfs It no long is used for stack splits, so strip the kernel workqueue bits from it and push it back into libxfs/xfs_bmap.h so that it can be shared with the userspace code. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 44db6db..856f53c 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -28,6 +28,37 @@ struct xfs_trans; extern kmem_zone_t *xfs_bmap_free_item_zone; /* + * Argument structure for xfs_bmap_alloc. + */ +struct xfs_bmalloca { + xfs_fsblock_t *firstblock; /* i/o first block allocated */ + struct xfs_bmap_free *flist; /* bmap freelist */ + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_inode *ip; /* incore inode pointer */ + struct xfs_bmbt_irec prev; /* extent before the new one */ + struct xfs_bmbt_irec got; /* extent after, or delayed */ + + xfs_fileoff_t offset; /* offset in file filling in */ + xfs_extlen_t length; /* i/o length asked/allocated */ + xfs_fsblock_t blkno; /* starting block of new extent */ + + struct xfs_btree_cur *cur; /* btree cursor */ + xfs_extnum_t idx; /* current extent index */ + int nallocs;/* number of extents alloc'd */ + int logflags;/* flags for transaction logging */ + + xfs_extlen_t total; /* total blocks needed for xaction */ + xfs_extlen_t minlen; /* minimum allocation size (blocks) */ + xfs_extlen_t minleft; /* amount must be left after alloc */ + bool eof; /* set if allocating past last extent */ + bool wasdel; /* replacing a delayed allocation */ + bool userdata;/* set if is user data */ + bool aeof; /* allocated space at eof */ + bool conv; /* overwriting unwritten extents */ + int flags; +}; + +/* * List of extents to be free "later". * The list is kept sorted on xbf_startblock. */ diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h index 2fdb72d..1fce0f3 100644 --- a/fs/xfs/xfs_bmap_util.h +++ b/fs/xfs/xfs_bmap_util.h @@ -26,40 +26,7 @@ struct xfs_ifork; struct xfs_inode; struct xfs_mount; struct xfs_trans; - -/* - * Argument structure for xfs_bmap_alloc. - */ -struct xfs_bmalloca { - xfs_fsblock_t *firstblock; /* i/o first block allocated */ - struct xfs_bmap_free *flist; /* bmap freelist */ - struct xfs_trans *tp; /* transaction pointer */ - struct xfs_inode *ip; /* incore inode pointer */ - struct xfs_bmbt_irec prev; /* extent before the new one */ - struct xfs_bmbt_irec got; /* extent after, or delayed */ - - xfs_fileoff_t offset; /* offset in file filling in */ - xfs_extlen_t length; /* i/o length asked/allocated */ - xfs_fsblock_t blkno; /* starting block of new extent */ - - struct xfs_btree_cur *cur; /* btree cursor */ - xfs_extnum_t idx; /* current extent index */ - int nallocs;/* number of extents alloc'd */ - int logflags;/* flags for transaction logging */ - - xfs_extlen_t total; /* total blocks needed for xaction */ - xfs_extlen_t minlen; /* minimum allocation size (blocks) */ - xfs_extlen_t minleft; /* amount must be left after alloc */ - bool eof; /* set if allocating past last extent */ - bool wasdel; /* replacing a delayed allocation */ - bool userdata;/* set if is user data */ - bool aeof; /* allocated space at eof */ - bool conv; /* overwriting unwritten extents */ - int flags; - struct completion *done; - struct work_struct work; - int result; -}; +struct xfs_bmalloca; int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist, int *committed); -- cgit v0.10.2 From aa5d95c1b57792119804c587b9a468019219d7e0 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 9 Jan 2015 10:47:14 +1100 Subject: xfs: move xfs_bmap_finish prototype This function is used libxfs code, but is implemented separately in userspace. Move the function prototype to xfs_bmap.h so that the prototype is shared even if the implementations aren't. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 856f53c..b9d8a49 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -180,6 +180,8 @@ void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); void xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len, struct xfs_bmap_free *flist, struct xfs_mount *mp); void xfs_bmap_cancel(struct xfs_bmap_free *flist); +int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist, + int *committed); void xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork); int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip, xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork); diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h index 1fce0f3..736429a 100644 --- a/fs/xfs/xfs_bmap_util.h +++ b/fs/xfs/xfs_bmap_util.h @@ -28,8 +28,6 @@ struct xfs_mount; struct xfs_trans; struct xfs_bmalloca; -int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist, - int *committed); int xfs_bmap_rtalloc(struct xfs_bmalloca *ap); int xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff, int whichfork, int *eof); -- cgit v0.10.2 From 64af7a6ea5a4c7e12ae79415250d054424b7e0c2 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 9 Jan 2015 10:47:43 +1100 Subject: xfs: remove deprecated sysctls xfsbufd_centisecs and age_buffer_centisecs were due for removal in 3.14. We forgot to do that - it's now well past time to remove these deprecated, unused sysctls. Signed-off-by: Dave Chinner Reviewed-by: Eric Sandeen Signed-off-by: Dave Chinner diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt index 5be51fd..7077103 100644 --- a/Documentation/filesystems/xfs.txt +++ b/Documentation/filesystems/xfs.txt @@ -348,16 +348,13 @@ The following sysctls are available for the XFS filesystem: Deprecated Sysctls ================== - fs.xfs.xfsbufd_centisecs (Min: 50 Default: 100 Max: 3000) - Dirty metadata is now tracked by the log subsystem and - flushing is driven by log space and idling demands. The - xfsbufd no longer exists, so this syctl does nothing. +None at present. - Due for removal in 3.14. - fs.xfs.age_buffer_centisecs (Min: 100 Default: 1500 Max: 720000) - Dirty metadata is now tracked by the log subsystem and - flushing is driven by log space and idling demands. The - xfsbufd no longer exists, so this syctl does nothing. +Removed Sysctls +=============== - Due for removal in 3.14. + Name Removed + ---- ------- + fs.xfs.xfsbufd_centisec v3.20 + fs.xfs.age_buffer_centisecs v3.20 diff --git a/fs/xfs/xfs_sysctl.c b/fs/xfs/xfs_sysctl.c index 1743b9f..a0c8067 100644 --- a/fs/xfs/xfs_sysctl.c +++ b/fs/xfs/xfs_sysctl.c @@ -149,24 +149,6 @@ static struct ctl_table xfs_table[] = { .extra2 = &xfs_params.inherit_noatim.max }, { - .procname = "xfsbufd_centisecs", - .data = &xfs_params.xfs_buf_timer.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.xfs_buf_timer.min, - .extra2 = &xfs_params.xfs_buf_timer.max - }, - { - .procname = "age_buffer_centisecs", - .data = &xfs_params.xfs_buf_age.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.xfs_buf_age.min, - .extra2 = &xfs_params.xfs_buf_age.max - }, - { .procname = "inherit_nosymlinks", .data = &xfs_params.inherit_nosym.val, .maxlen = sizeof(int), -- cgit v0.10.2 From d32057fc84c141af22ddf07b58e52570e52369cd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 9 Jan 2015 10:48:12 +1100 Subject: xfs: pass a 64-bit count argument to xfs_iomap_write_unwritten The code is already ready for it, and the pnfs layout commit code expects to be able to pass a larger than 32-bit argument. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index c980e2a..ccb1dd0 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -802,7 +802,7 @@ int xfs_iomap_write_unwritten( xfs_inode_t *ip, xfs_off_t offset, - size_t count) + xfs_off_t count) { xfs_mount_t *mp = ip->i_mount; xfs_fileoff_t offset_fsb; diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index 411fbb8..8688e66 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -27,6 +27,6 @@ int xfs_iomap_write_delay(struct xfs_inode *, xfs_off_t, size_t, struct xfs_bmbt_irec *); int xfs_iomap_write_allocate(struct xfs_inode *, xfs_off_t, struct xfs_bmbt_irec *); -int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, size_t); +int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t); #endif /* __XFS_IOMAP_H__*/ -- cgit v0.10.2 From 43fd1fce9643586e0995ee5d11fb40641575348a Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 9 Jan 2015 10:48:58 +1100 Subject: xfs: fix implicit bool to int conversion try_wait_for_completion returns bool so the wrapper function xfs_dqflock_nowait should probably also return bool and not int. Signed-off-by: Nicholas Mc Guire Reviewed-by: Brian Foster Signed-off-by: Dave Chinner diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h index c24c67e..2f536f3 100644 --- a/fs/xfs/xfs_dquot.h +++ b/fs/xfs/xfs_dquot.h @@ -86,7 +86,7 @@ static inline void xfs_dqflock(xfs_dquot_t *dqp) wait_for_completion(&dqp->q_flush); } -static inline int xfs_dqflock_nowait(xfs_dquot_t *dqp) +static inline bool xfs_dqflock_nowait(xfs_dquot_t *dqp) { return try_wait_for_completion(&dqp->q_flush); } -- cgit v0.10.2 From 3c01b9a896c9c592d9edc7439d5e5cf6c411d014 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Mon, 1 Dec 2014 17:39:34 +0530 Subject: gpio: moxart: convert to use basic mmio gpio library This patch converts MOXART GPIO driver to use basic_mmio_gpio generic library. Signed-off-by: Kamlakant Patel Acked-by: Alexandre Courbot Tested-by: Jonas Jensen Signed-off-by: Linus Walleij diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 633ec21..e367296 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -200,6 +200,7 @@ config GPIO_F7188X config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART + select GPIO_GENERIC help Select this option to enable GPIO driver for MOXA ART SoC devices. diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index 31e2551..c3ab46e 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -23,21 +23,12 @@ #include #include #include +#include #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_IN 0x04 #define GPIO_PIN_DIRECTION 0x08 -struct moxart_gpio_chip { - struct gpio_chip gpio; - void __iomem *base; -}; - -static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) -{ - return container_of(chip, struct moxart_gpio_chip, gpio); -} - static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); @@ -48,90 +39,60 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) pinctrl_free_gpio(offset); } -static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_DATA_OUT; - u32 reg = readl(ioaddr); - - if (value) - reg = reg | BIT(offset); - else - reg = reg & ~BIT(offset); - - writel(reg, ioaddr); -} - static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - u32 ret = readl(gc->base + GPIO_PIN_DIRECTION); + struct bgpio_chip *bgc = to_bgpio_chip(chip); + u32 ret = bgc->read_reg(bgc->reg_dir); if (ret & BIT(offset)) - return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset)); + return !!(bgc->read_reg(bgc->reg_set) & BIT(offset)); else - return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); -} - -static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) & ~BIT(offset), ioaddr); - return 0; -} - -static int moxart_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - moxart_gpio_set(chip, offset, value); - writel(readl(ioaddr) | BIT(offset), ioaddr); - return 0; + return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset)); } -static struct gpio_chip moxart_template_chip = { - .label = "moxart-gpio", - .request = moxart_gpio_request, - .free = moxart_gpio_free, - .direction_input = moxart_gpio_direction_input, - .direction_output = moxart_gpio_direction_output, - .set = moxart_gpio_set, - .get = moxart_gpio_get, - .ngpio = 32, - .owner = THIS_MODULE, -}; - static int moxart_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - struct moxart_gpio_chip *mgc; + struct bgpio_chip *bgc; + void __iomem *base; int ret; - mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); - if (!mgc) + bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; - mgc->gpio = moxart_template_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mgc->base = devm_ioremap_resource(dev, res); - if (IS_ERR(mgc->base)) - return PTR_ERR(mgc->base); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); - mgc->gpio.dev = dev; + ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN, + base + GPIO_DATA_OUT, NULL, + base + GPIO_PIN_DIRECTION, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + return ret; + } - ret = gpiochip_add(&mgc->gpio); + bgc->gc.label = "moxart-gpio"; + bgc->gc.request = moxart_gpio_request; + bgc->gc.free = moxart_gpio_free; + bgc->gc.get = moxart_gpio_get; + bgc->data = bgc->read_reg(bgc->reg_set); + bgc->gc.base = 0; + bgc->gc.ngpio = 32; + bgc->gc.dev = dev; + bgc->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&bgc->gc); if (ret) { dev_err(dev, "%s: gpiochip_add failed\n", dev->of_node->full_name); return ret; } - return 0; + return ret; } static const struct of_device_id moxart_gpio_match[] = { -- cgit v0.10.2 From b9dfe0bed999d23ee8838d389637dd8aef83fafa Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 9 Jan 2015 10:53:21 +0100 Subject: livepatch: handle ancient compilers with more grace We are aborting a build in case when gcc doesn't support fentry on x86_64 (regs->ip modification can't really reliably work with mcount). This however breaks allmodconfig for people with older gccs that don't support -mfentry. Turn the build-time failure into runtime failure, resulting in the whole infrastructure not being initialized if CC_USING_FENTRY is unset. Reported-by: Andrew Morton Signed-off-by: Jiri Kosina Signed-off-by: Andrew Morton Acked-by: Josh Poimboeuf diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h index b5608d7..26e5813 100644 --- a/arch/x86/include/asm/livepatch.h +++ b/arch/x86/include/asm/livepatch.h @@ -25,9 +25,13 @@ #include #ifdef CONFIG_LIVE_PATCHING +static inline int klp_check_compiler_support(void) +{ #ifndef CC_USING_FENTRY -#error Your compiler must support -mfentry for live patching to work + return 1; #endif + return 0; +} extern int klp_write_module_reloc(struct module *mod, unsigned long type, unsigned long loc, unsigned long value); diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 6f63879..ce42d3b 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -911,6 +911,12 @@ static int klp_init(void) { int ret; + ret = klp_check_compiler_support(); + if (ret) { + pr_info("Your compiler is too old; turning off.\n"); + return -EINVAL; + } + ret = register_module_notifier(&klp_module_nb); if (ret) return ret; -- cgit v0.10.2 From 005b3f574a0a53f476a62da5c861c1c9bf8177b7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 8 Jan 2015 14:37:12 -0500 Subject: HID: logitech-hidpp: store the name of the device in struct hidpp If a disconnect occurs while getting the actual name of the device (which can take several HID transactions), the name of the device will be the hid name, provided by the Unifying Receiver. This means that in some cases, the user space will see a different name that what it usually sees when there is no disconnect. We should store the name of the device in the struct hidpp. That way, if a disconnect occurs while we are accessing the name, hidpp_connect_event() can fail, and the input node is not created. The input node will be created only if we have a connection which lasts long enough to retrieve all the requested information: name, protocol, and specific configuration. Reviewed-by: Peter Wu Tested-by: Peter Wu Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index cf57955..acb632d 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -89,6 +89,7 @@ struct hidpp_device { struct hid_device *hid_dev; struct mutex send_mutex; void *send_receive_buf; + char *name; /* will never be NULL and should not be freed */ wait_queue_head_t wait; bool answer_available; u8 protocol_major; @@ -1080,6 +1081,7 @@ static void hidpp_input_close(struct input_dev *dev) static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) { struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev); + struct hidpp_device *hidpp = hid_get_drvdata(hdev); if (!input_dev) return NULL; @@ -1088,7 +1090,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) input_dev->open = hidpp_input_open; input_dev->close = hidpp_input_close; - input_dev->name = hdev->name; + input_dev->name = hidpp->name; input_dev->phys = hdev->phys; input_dev->uniq = hdev->uniq; input_dev->id.bustype = hdev->bus; @@ -1130,22 +1132,28 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) hid_info(hdev, "HID++ %u.%u device connected.\n", hidpp->protocol_major, hidpp->protocol_minor); + if (!hidpp->name || hidpp->name == hdev->name) { + name = hidpp_get_device_name(hidpp); + if (!name) { + hid_err(hdev, + "unable to retrieve the name of the device"); + return; + } + + devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); + kfree(name); + if (!devm_name) + return; + + hidpp->name = devm_name; + } + input = hidpp_allocate_input(hdev); if (!input) { hid_err(hdev, "cannot allocate new input device: %d\n", ret); return; } - name = hidpp_get_device_name(hidpp); - if (!name) { - hid_err(hdev, "unable to retrieve the name of the device"); - } else { - devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); - if (devm_name) - input->name = devm_name; - kfree(name); - } - hidpp_populate_input(hidpp, input, false); ret = input_register_device(input); @@ -1168,6 +1176,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENOMEM; hidpp->hid_dev = hdev; + hidpp->name = hdev->name; hid_set_drvdata(hdev, hidpp); hidpp->quirks = id->driver_data; -- cgit v0.10.2 From 8f6cb409f016e52b753a93e393622770556d1ab9 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 5 Jan 2015 13:25:10 -0500 Subject: GFS2: Eliminate __gfs2_glock_remove_from_lru Since the only caller of function __gfs2_glock_remove_from_lru locks the same spin_lock as gfs2_glock_remove_from_lru, the functions can be combined. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a23524a..aeb7bc9 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -173,19 +173,14 @@ void gfs2_glock_add_to_lru(struct gfs2_glock *gl) spin_unlock(&lru_lock); } -static void __gfs2_glock_remove_from_lru(struct gfs2_glock *gl) +static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) { + spin_lock(&lru_lock); if (!list_empty(&gl->gl_lru)) { list_del_init(&gl->gl_lru); atomic_dec(&lru_count); clear_bit(GLF_LRU, &gl->gl_flags); } -} - -static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) -{ - spin_lock(&lru_lock); - __gfs2_glock_remove_from_lru(gl); spin_unlock(&lru_lock); } @@ -205,9 +200,7 @@ void gfs2_glock_put(struct gfs2_glock *gl) lockref_mark_dead(&gl->gl_lockref); - spin_lock(&lru_lock); - __gfs2_glock_remove_from_lru(gl); - spin_unlock(&lru_lock); + gfs2_glock_remove_from_lru(gl); spin_unlock(&gl->gl_lockref.lock); spin_lock_bucket(gl->gl_hash); hlist_bl_del_rcu(&gl->gl_list); -- cgit v0.10.2 From e5a7a72cd51a585b8f1a1e299bf88fff44b94440 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Fri, 9 Jan 2015 09:57:33 +0800 Subject: regulator: pfuze100-regulator: add pfuze3000 support Add pfuze3000 chip support. Signed-off-by: Robin Gong Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt index 34ef5d1..9b40db8 100644 --- a/Documentation/devicetree/bindings/regulator/pfuze100.txt +++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt @@ -1,7 +1,7 @@ PFUZE100 family of regulators Required properties: -- compatible: "fsl,pfuze100" or "fsl,pfuze200" +- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000" - reg: I2C slave address Required child node: @@ -14,6 +14,8 @@ Required child node: sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 --PFUZE200 sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6 + --PFUZE3000 + sw1a,sw1b,sw2,sw3,swbst,vsnvs,vrefddr,vldo1,vldo2,vccsd,v33,vldo3,vldo4 Each regulator is defined using the standard binding for regulators. @@ -205,3 +207,93 @@ Example 2: PFUZE200 }; }; }; + +Example 3: PFUZE3000 + + pmic: pfuze3000@08 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index c879dff..8cc8d18 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -56,7 +56,7 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 -enum chips { PFUZE100, PFUZE200 }; +enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 }; struct pfuze_regulator { struct regulator_desc desc; @@ -80,9 +80,18 @@ static const int pfuze100_vsnvs[] = { 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, }; +static const int pfuze3000_sw2lo[] = { + 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, +}; + +static const int pfuze3000_sw2hi[] = { + 2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000, +}; + static const struct i2c_device_id pfuze_device_id[] = { {.name = "pfuze100", .driver_data = PFUZE100}, {.name = "pfuze200", .driver_data = PFUZE200}, + {.name = "pfuze3000", .driver_data = PFUZE3000}, { } }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); @@ -90,6 +99,7 @@ MODULE_DEVICE_TABLE(i2c, pfuze_device_id); static const struct of_device_id pfuze_dt_ids[] = { { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, + { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000}, { } }; MODULE_DEVICE_TABLE(of, pfuze_dt_ids); @@ -219,6 +229,60 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x20, \ } +#define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \ + .desc = { \ + .name = #_name, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_ldo_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base), \ + .vsel_mask = 0x3, \ + .enable_reg = (base), \ + .enable_mask = 0x10, \ + }, \ + .stby_reg = (base), \ + .stby_mask = 0x20, \ +} + + +#define PFUZE3000_SW2_REG(_chip, _name, base, min, max, step) { \ + .desc = { \ + .name = #_name,\ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_sw_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0x7, \ + }, \ + .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ + .stby_mask = 0x7, \ +} + +#define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step) { \ + .desc = { \ + .name = #_name,\ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_sw_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0xf, \ + }, \ + .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ + .stby_mask = 0xf, \ +} + /* PFUZE100 */ static struct pfuze_regulator pfuze100_regulators[] = { PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), @@ -254,6 +318,22 @@ static struct pfuze_regulator pfuze200_regulators[] = { PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; +static struct pfuze_regulator pfuze3000_regulators[] = { + PFUZE100_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 700000, 1475000, 25000), + PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000), + PFUZE100_SWB_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), + PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), + PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst), + PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), + PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + static struct pfuze_regulator *pfuze_regulators; #ifdef CONFIG_OF @@ -294,6 +374,24 @@ static struct of_regulator_match pfuze200_matches[] = { { .name = "vgen6", }, }; +/* PFUZE3000 */ +static struct of_regulator_match pfuze3000_matches[] = { + + { .name = "sw1a", }, + { .name = "sw1b", }, + { .name = "sw2", }, + { .name = "sw3", }, + { .name = "swbst", }, + { .name = "vsnvs", }, + { .name = "vrefddr", }, + { .name = "vldo1", }, + { .name = "vldo2", }, + { .name = "vccsd", }, + { .name = "v33", }, + { .name = "vldo3", }, + { .name = "vldo4", }, +}; + static struct of_regulator_match *pfuze_matches; static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) @@ -313,6 +411,11 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) } switch (chip->chip_id) { + case PFUZE3000: + pfuze_matches = pfuze3000_matches; + ret = of_regulator_match(dev, parent, pfuze3000_matches, + ARRAY_SIZE(pfuze3000_matches)); + break; case PFUZE200: pfuze_matches = pfuze200_matches; ret = of_regulator_match(dev, parent, pfuze200_matches, @@ -378,7 +481,8 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip) * as ID=8 in PFUZE100 */ dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); - } else if ((value & 0x0f) != pfuze_chip->chip_id) { + } else if ((value & 0x0f) != pfuze_chip->chip_id && + (value & 0xf0) >> 4 != pfuze_chip->chip_id) { /* device id NOT match with your setting */ dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); return -ENODEV; @@ -417,7 +521,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, int i, ret; const struct of_device_id *match; u32 regulator_num; - u32 sw_check_start, sw_check_end; + u32 sw_check_start, sw_check_end, sw_hi = 0x40; pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip), GFP_KERNEL); @@ -458,13 +562,19 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* use the right regulators after identify the right device */ switch (pfuze_chip->chip_id) { + case PFUZE3000: + pfuze_regulators = pfuze3000_regulators; + regulator_num = ARRAY_SIZE(pfuze3000_regulators); + sw_check_start = PFUZE3000_SW2; + sw_check_end = PFUZE3000_SW2; + sw_hi = 1 << 3; + break; case PFUZE200: pfuze_regulators = pfuze200_regulators; regulator_num = ARRAY_SIZE(pfuze200_regulators); sw_check_start = PFUZE200_SW2; sw_check_end = PFUZE200_SW3B; break; - case PFUZE100: default: pfuze_regulators = pfuze100_regulators; @@ -474,7 +584,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client, break; } dev_info(&client->dev, "pfuze%s found.\n", - (pfuze_chip->chip_id == PFUZE100) ? "100" : "200"); + (pfuze_chip->chip_id == PFUZE100) ? "100" : + ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000")); memcpy(pfuze_chip->regulator_descs, pfuze_regulators, sizeof(pfuze_chip->regulator_descs)); @@ -498,10 +609,15 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* SW2~SW4 high bit check and modify the voltage value table */ if (i >= sw_check_start && i <= sw_check_end) { regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); - if (val & 0x40) { - desc->min_uV = 800000; - desc->uV_step = 50000; - desc->n_voltages = 51; + if (val & sw_hi) { + if (pfuze_chip->chip_id == PFUZE3000) { + desc->volt_table = pfuze3000_sw2hi; + desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi); + } else { + desc->min_uV = 800000; + desc->uV_step = 50000; + desc->n_voltages = 51; + } } } diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h index 364f7a7..70c6c66 100644 --- a/include/linux/regulator/pfuze100.h +++ b/include/linux/regulator/pfuze100.h @@ -49,6 +49,20 @@ #define PFUZE200_VGEN5 11 #define PFUZE200_VGEN6 12 +#define PFUZE3000_SW1A 0 +#define PFUZE3000_SW1B 1 +#define PFUZE3000_SW2 2 +#define PFUZE3000_SW3 3 +#define PFUZE3000_SWBST 4 +#define PFUZE3000_VSNVS 5 +#define PFUZE3000_VREFDDR 6 +#define PFUZE3000_VLDO1 7 +#define PFUZE3000_VLDO2 8 +#define PFUZE3000_VCCSD 9 +#define PFUZE3000_V33 10 +#define PFUZE3000_VLDO3 11 +#define PFUZE3000_VLDO4 12 + struct regulator_init_data; struct pfuze_regulator_platform_data { -- cgit v0.10.2 From 4e38bea60ebff6cc65abaf8c1c2c58e3c3c37dc0 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Tue, 23 Dec 2014 11:29:08 -0500 Subject: scsi: asc/ascq codes, sync to T10 2014/12/21 The last time these SCSI asc/ascq codes were synced with T10 was 2013/06/05. Sync the SCSI ASC/ASCQ number to string tables with those found at http://www.t10.org/lists/asc-num.txt dated 2014/12/21. Signed-off-by: Douglas Gilbert Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index e2068a2..55a7157 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -392,7 +392,7 @@ struct error_info { /* * The canonical list of T10 Additional Sense Codes is available at: - * http://www.t10.org/lists/asc-num.txt [most recent: 20130605] + * http://www.t10.org/lists/asc-num.txt [most recent: 20141221] */ static const struct error_info additional[] = @@ -421,6 +421,7 @@ static const struct error_info additional[] = {0x001E, "Conflicting SA creation request"}, {0x001F, "Logical unit transitioning to another power condition"}, {0x0020, "Extended copy information available"}, + {0x0021, "Atomic command aborted due to ACA"}, {0x0100, "No index/sector signal"}, @@ -446,6 +447,7 @@ static const struct error_info additional[] = {0x040C, "Logical unit not accessible, target port in unavailable " "state"}, {0x040D, "Logical unit not ready, structure check required"}, + {0x040E, "Logical unit not ready, security session in progress"}, {0x0410, "Logical unit not ready, auxiliary memory not accessible"}, {0x0411, "Logical unit not ready, notify (enable spinup) required"}, {0x0412, "Logical unit not ready, offline"}, @@ -462,6 +464,11 @@ static const struct error_info additional[] = {0x041C, "Logical unit not ready, additional power use not yet " "granted"}, {0x041D, "Logical unit not ready, configuration in progress"}, + {0x041E, "Logical unit not ready, microcode activation required"}, + {0x041F, "Logical unit not ready, microcode download required"}, + {0x0420, "Logical unit not ready, logical unit reset required"}, + {0x0421, "Logical unit not ready, hard reset required"}, + {0x0422, "Logical unit not ready, power cycle required"}, {0x0500, "Logical unit does not respond to selection"}, @@ -480,6 +487,7 @@ static const struct error_info additional[] = {0x0902, "Focus servo failure"}, {0x0903, "Spindle servo failure"}, {0x0904, "Head select fault"}, + {0x0905, "Vibration induced tracking error"}, {0x0A00, "Error log overflow"}, @@ -510,6 +518,7 @@ static const struct error_info additional[] = {0x0C0D, "Write error - not enough unsolicited data"}, {0x0C0E, "Multiple write errors"}, {0x0C0F, "Defects in error window"}, + {0x0C10, "Incomplete multiple atomic write operations"}, {0x0D00, "Error detected by third party temporary initiator"}, {0x0D01, "Third party device failure"}, @@ -635,6 +644,10 @@ static const struct error_info additional[] = {0x2101, "Invalid element address"}, {0x2102, "Invalid address for write"}, {0x2103, "Invalid write crossing layer jump"}, + {0x2104, "Unaligned write command"}, + {0x2105, "Write boundary violation"}, + {0x2106, "Attempt to read invalid data"}, + {0x2107, "Read boundary violation"}, {0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"}, @@ -691,6 +704,7 @@ static const struct error_info additional[] = {0x2705, "Permanent write protect"}, {0x2706, "Conditional write protect"}, {0x2707, "Space allocation failed write protect"}, + {0x2708, "Zone is read only"}, {0x2800, "Not ready to ready change, medium may have changed"}, {0x2801, "Import or export element accessed"}, @@ -743,10 +757,15 @@ static const struct error_info additional[] = {0x2C0A, "Partition or collection contains user objects"}, {0x2C0B, "Not reserved"}, {0x2C0C, "Orwrite generation does not match"}, + {0x2C0D, "Reset write pointer not allowed"}, + {0x2C0E, "Zone is offline"}, {0x2D00, "Overwrite error on update in place"}, {0x2E00, "Insufficient time for operation"}, + {0x2E01, "Command timeout before processing"}, + {0x2E02, "Command timeout during processing"}, + {0x2E03, "Command timeout during processing due to error recovery"}, {0x2F00, "Commands cleared by another initiator"}, {0x2F01, "Commands cleared by power loss notification"}, @@ -868,6 +887,7 @@ static const struct error_info additional[] = {0x3F13, "iSCSI IP address removed"}, {0x3F14, "iSCSI IP address changed"}, {0x3F15, "Inspect referrals sense descriptors"}, + {0x3F16, "Microcode has been changed without reset"}, /* * {0x40NN, "Ram failure"}, * {0x40NN, "Diagnostic failure on component nn"}, @@ -946,6 +966,11 @@ static const struct error_info additional[] = {0x5306, "Volume identifier missing"}, {0x5307, "Duplicate volume identifier"}, {0x5308, "Element status unknown"}, + {0x5309, "Data transfer device error - load failed"}, + {0x530a, "Data transfer device error - unload failed"}, + {0x530b, "Data transfer device error - unload missing"}, + {0x530c, "Data transfer device error - eject failed"}, + {0x530d, "Data transfer device error - library communication failed"}, {0x5400, "Scsi to host system interface failure"}, @@ -963,6 +988,7 @@ static const struct error_info additional[] = {0x550B, "Insufficient power for operation"}, {0x550C, "Insufficient resources to create rod"}, {0x550D, "Insufficient resources to create rod token"}, + {0x550E, "Insufficient zone resources"}, {0x5700, "Unable to recover table-of-contents"}, -- cgit v0.10.2 From 6583f6fb82296b737053dff154a1e7a9c174754e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 29 Dec 2014 09:40:56 -0800 Subject: scsi: fix scsi_error.c kernel-doc warning Fix kernel-doc warning in scsi_error.c: Warning(..//drivers/scsi/scsi_error.c:887): No description found for parameter 'hostt' Fixes: 883a030f989a17b81167f3a181cf93d741fa98b4 (scsi: document scsi_try_to_abort_cmd) Signed-off-by: Randy Dunlap Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 8afb016..9ac9eb1 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -868,6 +868,7 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) /** * scsi_try_to_abort_cmd - Ask host to abort a SCSI command + * @hostt: SCSI driver host template * @scmd: SCSI cmd used to send a target reset * * Return value: -- cgit v0.10.2 From eb9eea01d4d8ce86eeee52cdd40029fd1a549721 Mon Sep 17 00:00:00 2001 From: Rob Evers Date: Tue, 16 Dec 2014 11:01:18 -0500 Subject: scsi: avoid unnecessary GFP_ATOMIC allocation in scsi_report_lun_scan Signed-off-by: Rob Evers Reviewed-by: Ewan D. Milne Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 983aed1..9edae2f 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1416,7 +1416,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, * prevent us from finding any LUNs on this target. */ length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun); - lun_data = kmalloc(length, GFP_ATOMIC | + lun_data = kmalloc(length, GFP_KERNEL | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); if (!lun_data) { printk(ALLOC_FAILURE_MSG, __func__); -- cgit v0.10.2 From 2a904e5dd9b832fe70d86b70ce6e273d67e94389 Mon Sep 17 00:00:00 2001 From: Rob Evers Date: Tue, 16 Dec 2014 11:01:19 -0500 Subject: scsi: use set/get_unaligned_be32 in report_luns Signed-off-by: Rob Evers Reviewed-by: Ewan D. Milne Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 9edae2f..b7948d2 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1367,7 +1368,6 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, unsigned int retries; int result; struct scsi_lun *lunp, *lun_data; - u8 *data; struct scsi_sense_hdr sshdr; struct scsi_device *sdev; struct Scsi_Host *shost = dev_to_shost(&starget->dev); @@ -1433,10 +1433,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * bytes 6 - 9: length of the command. */ - scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff; - scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff; - scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff; - scsi_cmd[9] = (unsigned char) length & 0xff; + put_unaligned_be32(length, &scsi_cmd[6]); scsi_cmd[10] = 0; /* reserved */ scsi_cmd[11] = 0; /* control */ @@ -1484,9 +1481,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * Get the length from the first four bytes of lun_data. */ - data = (u8 *) lun_data->scsi_lun; - length = ((data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | (data[3] << 0)); + length = get_unaligned_be32(lun_data->scsi_lun); num_luns = (length / sizeof(struct scsi_lun)); if (num_luns > max_scsi_report_luns) { -- cgit v0.10.2 From acd6d73826224c20c44f505f56b0503f022d695c Mon Sep 17 00:00:00 2001 From: Rob Evers Date: Tue, 16 Dec 2014 11:01:20 -0500 Subject: scsi: retry report-luns when reported LU count requres more memory Update scsi_report_lun_scan to initially always report up to 511 LUs, as the previous default max_report_luns did. Retry in a loop if not enough memory is available for the number of LUs reported. Parameter max_report_luns is removed as it is no longer used. Signed-off-by: Rob Evers Reviewed-by: Ewan D. Milne Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b7948d2..0deb385 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -99,20 +99,6 @@ char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT; module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO); MODULE_PARM_DESC(scan, "sync, async or none"); -/* - * max_scsi_report_luns: the maximum number of LUNS that will be - * returned from the REPORT LUNS command. 8 times this value must - * be allocated. In theory this could be up to an 8 byte value, but - * in practice, the maximum number of LUNs suppored by any device - * is about 16k. - */ -static unsigned int max_scsi_report_luns = 511; - -module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(max_report_luns, - "REPORT LUNS maximum number of LUNS received (should be" - " between 1 and 16384)"); - static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18; module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR); @@ -1407,15 +1393,11 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * Allocate enough to hold the header (the same size as one scsi_lun) - * plus the max number of luns we are requesting. - * - * Reallocating and trying again (with the exact amount we need) - * would be nice, but then we need to somehow limit the size - * allocated based on the available memory and the limits of - * kmalloc - we don't want a kmalloc() failure of a huge value to - * prevent us from finding any LUNs on this target. + * plus the number of luns we are requesting. 511 was the default + * value of the now removed max_report_luns parameter. */ - length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun); + length = (511 + 1) * sizeof(struct scsi_lun); +retry: lun_data = kmalloc(length, GFP_KERNEL | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); if (!lun_data) { @@ -1481,17 +1463,16 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * Get the length from the first four bytes of lun_data. */ + if (get_unaligned_be32(lun_data->scsi_lun) + + sizeof(struct scsi_lun) > length) { + length = get_unaligned_be32(lun_data->scsi_lun) + + sizeof(struct scsi_lun); + kfree(lun_data); + goto retry; + } length = get_unaligned_be32(lun_data->scsi_lun); num_luns = (length / sizeof(struct scsi_lun)); - if (num_luns > max_scsi_report_luns) { - sdev_printk(KERN_WARNING, sdev, - "Only %d (max_scsi_report_luns)" - " of %d luns reported, try increasing" - " max_scsi_report_luns.\n", - max_scsi_report_luns, num_luns); - num_luns = max_scsi_report_luns; - } SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, "scsi scan: REPORT LUN scan\n")); -- cgit v0.10.2 From ed09dcc8bd7fe0991af7737e675996cbd022f38f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Dec 2014 14:46:14 -0800 Subject: ses: close potential registration race The slot and address fields have a small window of instability when userspace can read them before initialization. Separate enclosure_component allocation from registration. Signed-off-by: Dan Williams Signed-off-by: Song Liu Reviewed-by: Jens Axboe Cc: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 180a544..e18278a 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -273,27 +273,26 @@ enclosure_component_find_by_name(struct enclosure_device *edev, static const struct attribute_group *enclosure_component_groups[]; /** - * enclosure_component_register - add a particular component to an enclosure + * enclosure_component_alloc - prepare a new enclosure component * @edev: the enclosure to add the component * @num: the device number * @type: the type of component being added * @name: an optional name to appear in sysfs (leave NULL if none) * - * Registers the component. The name is optional for enclosures that - * give their components a unique name. If not, leave the field NULL - * and a name will be assigned. + * The name is optional for enclosures that give their components a unique + * name. If not, leave the field NULL and a name will be assigned. * * Returns a pointer to the enclosure component or an error. */ struct enclosure_component * -enclosure_component_register(struct enclosure_device *edev, - unsigned int number, - enum enclosure_component_type type, - const char *name) +enclosure_component_alloc(struct enclosure_device *edev, + unsigned int number, + enum enclosure_component_type type, + const char *name) { struct enclosure_component *ecomp; struct device *cdev; - int err, i; + int i; char newname[COMPONENT_NAME_SIZE]; if (number >= edev->components) @@ -327,14 +326,30 @@ enclosure_component_register(struct enclosure_device *edev, cdev->release = enclosure_component_release; cdev->groups = enclosure_component_groups; + return ecomp; +} +EXPORT_SYMBOL_GPL(enclosure_component_alloc); + +/** + * enclosure_component_register - publishes an initialized enclosure component + * @ecomp: component to add + * + * Returns 0 on successful registration, releases the component otherwise + */ +int enclosure_component_register(struct enclosure_component *ecomp) +{ + struct device *cdev; + int err; + + cdev = &ecomp->cdev; err = device_register(cdev); if (err) { ecomp->number = -1; put_device(cdev); - return ERR_PTR(err); + return err; } - return ecomp; + return 0; } EXPORT_SYMBOL_GPL(enclosure_component_register); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index b7e79e7..7dd9cf5 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -423,16 +423,23 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { if (create) - ecomp = enclosure_component_register(edev, - components++, - type_ptr[0], - name); + ecomp = enclosure_component_alloc( + edev, + components++, + type_ptr[0], + name); else ecomp = &edev->component[components++]; - if (!IS_ERR(ecomp) && addl_desc_ptr) - ses_process_descriptor(ecomp, - addl_desc_ptr); + if (!IS_ERR(ecomp)) { + if (addl_desc_ptr) + ses_process_descriptor( + ecomp, + addl_desc_ptr); + if (create) + enclosure_component_register( + ecomp); + } } if (desc_ptr) desc_ptr += len; diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index 9a33c5f..a835d33 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -120,8 +120,9 @@ enclosure_register(struct device *, const char *, int, struct enclosure_component_callbacks *); void enclosure_unregister(struct enclosure_device *); struct enclosure_component * -enclosure_component_register(struct enclosure_device *, unsigned int, - enum enclosure_component_type, const char *); +enclosure_component_alloc(struct enclosure_device *, unsigned int, + enum enclosure_component_type, const char *); +int enclosure_component_register(struct enclosure_component *); int enclosure_add_device(struct enclosure_device *enclosure, int component, struct device *dev); int enclosure_remove_device(struct enclosure_device *, struct device *); -- cgit v0.10.2 From 15a0fbbc8e0d4c135b069c34258fbaebad471dd7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Dec 2014 14:46:15 -0800 Subject: ses: generate KOBJ_CHANGE on enclosure attach In support of a /dev/disk/by-slot populated with data from the enclosure and ses modules udev needs notification when the new interface files/links are available. Otherwise, any udev rules specified for the disk cannot assume that the enclosure topology has settled. Signed-off-by: Dan Williams Signed-off-by: Song Liu Reviewed-by: Jens Axboe Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 7dd9cf5..6662b0c 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -349,7 +349,8 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev, if (scomp->addr != efd->addr) continue; - enclosure_add_device(edev, i, efd->dev); + if (enclosure_add_device(edev, i, efd->dev) == 0) + kobject_uevent(&efd->dev->kobj, KOBJ_CHANGE); return 1; } return 0; -- cgit v0.10.2 From 967f7bab0eaaa74d7d01a56d45aa309f78fb87dd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Dec 2014 14:46:16 -0800 Subject: ses: add enclosure logical id Export the NAA logical id for the enclosure. This is optionally available from the sas_transport_class, but it is really a property of the enclosure. Signed-off-by: Dan Williams Signed-off-by: Song Liu Reviewed-by: Jens Axboe Cc: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index e18278a..958ee98 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -432,8 +432,21 @@ static ssize_t components_show(struct device *cdev, } static DEVICE_ATTR_RO(components); +static ssize_t id_show(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev); + + if (edev->cb->show_id) + return edev->cb->show_id(edev, buf); + return -EINVAL; +} +static DEVICE_ATTR_RO(id); + static struct attribute *enclosure_class_attrs[] = { &dev_attr_components.attr, + &dev_attr_id.attr, NULL, }; ATTRIBUTE_GROUPS(enclosure_class); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 6662b0c..1041556 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -258,6 +258,14 @@ static int ses_set_active(struct enclosure_device *edev, return ses_set_page2_descriptor(edev, ecomp, desc); } +static int ses_show_id(struct enclosure_device *edev, char *buf) +{ + struct ses_device *ses_dev = edev->scratch; + unsigned long long id = get_unaligned_be64(ses_dev->page1+8+4); + + return sprintf(buf, "%#llx\n", id); +} + static struct enclosure_component_callbacks ses_enclosure_callbacks = { .get_fault = ses_get_fault, .set_fault = ses_set_fault, @@ -265,6 +273,7 @@ static struct enclosure_component_callbacks ses_enclosure_callbacks = { .get_locate = ses_get_locate, .set_locate = ses_set_locate, .set_active = ses_set_active, + .show_id = ses_show_id, }; struct ses_host_edev { diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index a835d33..807622b 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -79,6 +79,7 @@ struct enclosure_component_callbacks { int (*set_locate)(struct enclosure_device *, struct enclosure_component *, enum enclosure_component_setting); + int (*show_id)(struct enclosure_device *, char *buf); }; -- cgit v0.10.2 From 921ce7f5786052749a22a75780f5ce1a456bcdc6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Dec 2014 14:46:17 -0800 Subject: ses: add reliable slot attribute The name provided by firmware is in a vendor specific format, publish the slot number to have a reliable mechanism for identifying slots across firmware implementations. If the enclosure does not provide a slot number fallback to the component number which is guaranteed unique, and usually mirrors the slot number. Cleaned up the unused ses_component.desc in the process. Signed-off-by: Dan Williams Signed-off-by: Song Liu Reviewed-by: Jens Axboe Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 958ee98..b62314d 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -145,8 +145,10 @@ enclosure_register(struct device *dev, const char *name, int components, if (err) goto err; - for (i = 0; i < components; i++) + for (i = 0; i < components; i++) { edev->component[i].number = -1; + edev->component[i].slot = -1; + } mutex_lock(&container_list_lock); list_add_tail(&edev->node, &container_list); @@ -589,6 +591,20 @@ static ssize_t get_component_type(struct device *cdev, return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); } +static ssize_t get_component_slot(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int slot; + + /* if the enclosure does not override then use 'number' as a stand-in */ + if (ecomp->slot >= 0) + slot = ecomp->slot; + else + slot = ecomp->number; + + return snprintf(buf, 40, "%d\n", slot); +} static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, set_component_fault); @@ -599,6 +615,7 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active, static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, set_component_locate); static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL); +static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL); static struct attribute *enclosure_component_attrs[] = { &dev_attr_fault.attr, @@ -606,6 +623,7 @@ static struct attribute *enclosure_component_attrs[] = { &dev_attr_active.attr, &dev_attr_locate.attr, &dev_attr_type.attr, + &dev_attr_slot.attr, NULL }; ATTRIBUTE_GROUPS(enclosure_component); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 1041556..433de8e 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -47,7 +47,6 @@ struct ses_device { struct ses_component { u64 addr; - unsigned char *desc; }; static int ses_probe(struct device *dev) @@ -307,19 +306,26 @@ static void ses_process_descriptor(struct enclosure_component *ecomp, int invalid = desc[0] & 0x80; enum scsi_protocol proto = desc[0] & 0x0f; u64 addr = 0; + int slot = -1; struct ses_component *scomp = ecomp->scratch; unsigned char *d; - scomp->desc = desc; - if (invalid) return; switch (proto) { + case SCSI_PROTOCOL_FCP: + if (eip) { + d = desc + 4; + slot = d[3]; + } + break; case SCSI_PROTOCOL_SAS: - if (eip) + if (eip) { + d = desc + 4; + slot = d[3]; d = desc + 8; - else + } else d = desc + 4; /* only take the phy0 addr */ addr = (u64)d[12] << 56 | @@ -335,6 +341,7 @@ static void ses_process_descriptor(struct enclosure_component *ecomp, /* FIXME: Need to add more protocols than just SAS */ break; } + ecomp->slot = slot; scomp->addr = addr; } diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index 807622b..0f826c1 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -92,6 +92,7 @@ struct enclosure_component { int fault; int active; int locate; + int slot; enum enclosure_status status; }; -- cgit v0.10.2 From 08024885a2a3ed432716e9d50046a620a5b2df05 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Tue, 30 Dec 2014 14:46:18 -0800 Subject: ses: Add power_status to SES device slot Add power_status to SES device slot, so we can power on/off the HDDs behind the enclosure. Check firmware status in ses_set_* before sending control pages to firmware. Signed-off-by: Song Liu Acked-by: Dan Williams Reviewed-by: Jens Axboe Cc: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index b62314d..38552a3 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -148,6 +148,7 @@ enclosure_register(struct device *dev, const char *name, int components, for (i = 0; i < components; i++) { edev->component[i].number = -1; edev->component[i].slot = -1; + edev->component[i].power_status = 1; } mutex_lock(&container_list_lock); @@ -583,6 +584,40 @@ static ssize_t set_component_locate(struct device *cdev, return count; } +static ssize_t get_component_power_status(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + if (edev->cb->get_power_status) + edev->cb->get_power_status(edev, ecomp); + return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off"); +} + +static ssize_t set_component_power_status(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int val; + + if (strncmp(buf, "on", 2) == 0 && + (buf[2] == '\n' || buf[2] == '\0')) + val = 1; + else if (strncmp(buf, "off", 3) == 0 && + (buf[3] == '\n' || buf[3] == '\0')) + val = 0; + else + return -EINVAL; + + if (edev->cb->set_power_status) + edev->cb->set_power_status(edev, ecomp, val); + return count; +} + static ssize_t get_component_type(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -614,6 +649,8 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active, set_component_active); static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, set_component_locate); +static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status, + set_component_power_status); static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL); static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL); @@ -622,6 +659,7 @@ static struct attribute *enclosure_component_attrs[] = { &dev_attr_status.attr, &dev_attr_active.attr, &dev_attr_locate.attr, + &dev_attr_power_status.attr, &dev_attr_type.attr, &dev_attr_slot.attr, NULL diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 433de8e..dcb0d76 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -67,6 +67,20 @@ static int ses_probe(struct device *dev) #define SES_TIMEOUT (30 * HZ) #define SES_RETRIES 3 +static void init_device_slot_control(unsigned char *dest_desc, + struct enclosure_component *ecomp, + unsigned char *status) +{ + memcpy(dest_desc, status, 4); + dest_desc[0] = 0; + /* only clear byte 1 for ENCLOSURE_COMPONENT_DEVICE */ + if (ecomp->type == ENCLOSURE_COMPONENT_DEVICE) + dest_desc[1] = 0; + dest_desc[2] &= 0xde; + dest_desc[3] &= 0x3c; +} + + static int ses_recv_diag(struct scsi_device *sdev, int page_code, void *buf, int bufflen) { @@ -178,14 +192,22 @@ static int ses_set_fault(struct enclosure_device *edev, struct enclosure_component *ecomp, enum enclosure_component_setting val) { - unsigned char desc[4] = {0 }; + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); switch (val) { case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ + desc[3] &= 0xdf; break; case ENCLOSURE_SETTING_ENABLED: - desc[3] = 0x20; + desc[3] |= 0x20; break; default: /* SES doesn't do the SGPIO blink settings */ @@ -219,14 +241,22 @@ static int ses_set_locate(struct enclosure_device *edev, struct enclosure_component *ecomp, enum enclosure_component_setting val) { - unsigned char desc[4] = {0 }; + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); switch (val) { case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ + desc[2] &= 0xfd; break; case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; + desc[2] |= 0x02; break; default: /* SES doesn't do the SGPIO blink settings */ @@ -239,15 +269,23 @@ static int ses_set_active(struct enclosure_device *edev, struct enclosure_component *ecomp, enum enclosure_component_setting val) { - unsigned char desc[4] = {0 }; + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); switch (val) { case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ + desc[2] &= 0x7f; ecomp->active = 0; break; case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x80; + desc[2] |= 0x80; ecomp->active = 1; break; default: @@ -265,12 +303,53 @@ static int ses_show_id(struct enclosure_device *edev, char *buf) return sprintf(buf, "%#llx\n", id); } +static void ses_get_power_status(struct enclosure_device *edev, + struct enclosure_component *ecomp) +{ + unsigned char *desc; + + desc = ses_get_page2_descriptor(edev, ecomp); + if (desc) + ecomp->power_status = (desc[3] & 0x10) ? 0 : 1; +} + +static int ses_set_power_status(struct enclosure_device *edev, + struct enclosure_component *ecomp, + int val) +{ + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); + + switch (val) { + /* power = 1 is device_off = 0 and vice versa */ + case 0: + desc[3] |= 0x10; + break; + case 1: + desc[3] &= 0xef; + break; + default: + return -EINVAL; + } + ecomp->power_status = val; + return ses_set_page2_descriptor(edev, ecomp, desc); +} + static struct enclosure_component_callbacks ses_enclosure_callbacks = { .get_fault = ses_get_fault, .set_fault = ses_set_fault, .get_status = ses_get_status, .get_locate = ses_get_locate, .set_locate = ses_set_locate, + .get_power_status = ses_get_power_status, + .set_power_status = ses_set_power_status, .set_active = ses_set_active, .show_id = ses_show_id, }; @@ -449,6 +528,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, ecomp = &edev->component[components++]; if (!IS_ERR(ecomp)) { + ses_get_power_status(edev, ecomp); if (addl_desc_ptr) ses_process_descriptor( ecomp, diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index 0f826c1..7be22da 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -79,6 +79,11 @@ struct enclosure_component_callbacks { int (*set_locate)(struct enclosure_device *, struct enclosure_component *, enum enclosure_component_setting); + void (*get_power_status)(struct enclosure_device *, + struct enclosure_component *); + int (*set_power_status)(struct enclosure_device *, + struct enclosure_component *, + int); int (*show_id)(struct enclosure_device *, char *buf); }; @@ -94,6 +99,7 @@ struct enclosure_component { int locate; int slot; enum enclosure_status status; + int power_status; }; struct enclosure_device { -- cgit v0.10.2 From 19c8ead7252bb66147011a361bb0c74dcb18e213 Mon Sep 17 00:00:00 2001 From: "Ewan D. Milne" Date: Thu, 4 Dec 2014 11:49:27 -0500 Subject: scsi_debug: Add REPORTED LUNS DATA HAS CHANGED Unit Attention Generate a REPORTED LUNS DATA HAS CHANGED Unit Attention if sysfs "max_luns" is used to change the number of scsi_debug LUNs. This is only done if scsi_debug_scsi_level is SPC-3 or above. Additionally, implement SPC-4 behavior which only generates this Unit Attention on the first LUN on the target to receive a command after the change. This condition is cleared when a REPORT LUNS command is received. Signed-off-by: Ewan D. Milne Acked-by: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 7b8b51b..1435b15 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -80,6 +80,8 @@ static const char *scsi_debug_version_date = "20141022"; #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define UA_RESET_ASC 0x29 #define UA_CHANGED_ASC 0x2a +#define TARGET_CHANGED_ASC 0x3f +#define LUNS_CHANGED_ASCQ 0x0e #define INSUFF_RES_ASC 0x55 #define INSUFF_RES_ASCQ 0x3 #define POWER_ON_RESET_ASCQ 0x0 @@ -180,7 +182,8 @@ static const char *scsi_debug_version_date = "20141022"; #define SDEBUG_UA_BUS_RESET 1 #define SDEBUG_UA_MODE_CHANGED 2 #define SDEBUG_UA_CAPACITY_CHANGED 3 -#define SDEBUG_NUM_UAS 4 +#define SDEBUG_UA_LUNS_CHANGED 4 +#define SDEBUG_NUM_UAS 5 /* for check_readiness() */ #define UAS_ONLY 1 /* check for UAs only */ @@ -782,6 +785,22 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) /* return -ENOTTY; // correct return but upsets fdisk */ } +static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) +{ + struct sdebug_host_info *sdhp; + struct sdebug_dev_info *dp; + + spin_lock(&sdebug_host_list_lock); + list_for_each_entry(sdhp, &sdebug_host_list, host_list) { + list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { + if ((devip->sdbg_host == dp->sdbg_host) && + (devip->target == dp->target)) + clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); + } + } + spin_unlock(&sdebug_host_list_lock); +} + static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, struct sdebug_dev_info * devip) { @@ -817,6 +836,23 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, if (debug) cp = "capacity data changed"; break; + case SDEBUG_UA_LUNS_CHANGED: + /* + * SPC-3 behavior is to report a UNIT ATTENTION with + * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN + * on the target, until a REPORT LUNS command is + * received. SPC-4 behavior is to report it only once. + * NOTE: scsi_debug_scsi_level does not use the same + * values as struct scsi_device->scsi_level. + */ + if (scsi_debug_scsi_level >= 6) /* SPC-4 and above */ + clear_luns_changed_on_target(devip); + mk_sense_buffer(SCpnt, UNIT_ATTENTION, + TARGET_CHANGED_ASC, + LUNS_CHANGED_ASCQ); + if (debug) + cp = "reported luns data has changed"; + break; default: pr_warn("%s: unexpected unit attention code=%d\n", __func__, k); @@ -3229,6 +3265,7 @@ static int resp_report_luns(struct scsi_cmnd * scp, unsigned char arr[SDEBUG_RLUN_ARR_SZ]; unsigned char * max_addr; + clear_luns_changed_on_target(devip); alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); shortish = (alloc_len < 4); if (shortish || (select_report > 2)) { @@ -4369,10 +4406,27 @@ static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, size_t count) { int n; + bool changed; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + changed = (scsi_debug_max_luns != n); scsi_debug_max_luns = n; sdebug_max_tgts_luns(); + if (changed && (scsi_debug_scsi_level >= 5)) { /* >= SPC-3 */ + struct sdebug_host_info *sdhp; + struct sdebug_dev_info *dp; + + spin_lock(&sdebug_host_list_lock); + list_for_each_entry(sdhp, &sdebug_host_list, + host_list) { + list_for_each_entry(dp, &sdhp->dev_info_list, + dev_list) { + set_bit(SDEBUG_UA_LUNS_CHANGED, + dp->uas_bm); + } + } + spin_unlock(&sdebug_host_list_lock); + } return count; } return -EINVAL; -- cgit v0.10.2 From acafd0b920e1a4a94a03f1911b4fb87e2081f235 Mon Sep 17 00:00:00 2001 From: "Ewan D. Milne" Date: Thu, 4 Dec 2014 11:49:28 -0500 Subject: scsi_debug: Implement WRITE BUFFER command Accept the WRITE BUFFER command and do nothing other than set the appropriate "microcode has been changed" UA on the LU. >From an earlier patch by Doug Gilbert. Signed-off-by: Ewan D. Milne Acked-by: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1435b15..8bcf6ad 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -93,6 +93,8 @@ static const char *scsi_debug_version_date = "20141022"; #define THRESHOLD_EXCEEDED 0x5d #define LOW_POWER_COND_ON 0x5e #define MISCOMPARE_VERIFY_ASC 0x1d +#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ +#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 /* Additional Sense Code Qualifier (ASCQ) */ #define ACK_NAK_TO 0x3 @@ -183,7 +185,9 @@ static const char *scsi_debug_version_date = "20141022"; #define SDEBUG_UA_MODE_CHANGED 2 #define SDEBUG_UA_CAPACITY_CHANGED 3 #define SDEBUG_UA_LUNS_CHANGED 4 -#define SDEBUG_NUM_UAS 5 +#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ +#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 +#define SDEBUG_NUM_UAS 7 /* for check_readiness() */ #define UAS_ONLY 1 /* check for UAs only */ @@ -329,6 +333,7 @@ static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); struct opcode_info_t { u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff @@ -483,8 +488,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* WRITE_BUFFER */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, + {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, + 0, 0, 0, 0} }, /* WRITE_BUFFER */ {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, @@ -836,6 +842,19 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, if (debug) cp = "capacity data changed"; break; + case SDEBUG_UA_MICROCODE_CHANGED: + mk_sense_buffer(SCpnt, UNIT_ATTENTION, + TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ); + if (debug) + cp = "microcode has been changed"; + break; + case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: + mk_sense_buffer(SCpnt, UNIT_ATTENTION, + TARGET_CHANGED_ASC, + MICROCODE_CHANGED_WO_RESET_ASCQ); + if (debug) + cp = "microcode has been changed without reset"; + break; case SDEBUG_UA_LUNS_CHANGED: /* * SPC-3 behavior is to report a UNIT ATTENTION with @@ -3069,6 +3088,55 @@ resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); } +/* Note the mode field is in the same position as the (lower) service action + * field. For the Report supported operation codes command, SPC-4 suggests + * each mode of this command should be reported separately; for future. */ +static int +resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + u8 *cmd = scp->cmnd; + struct scsi_device *sdp = scp->device; + struct sdebug_dev_info *dp; + u8 mode; + + mode = cmd[1] & 0x1f; + switch (mode) { + case 0x4: /* download microcode (MC) and activate (ACT) */ + /* set UAs on this device only */ + set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); + set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); + break; + case 0x5: /* download MC, save and ACT */ + set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); + break; + case 0x6: /* download MC with offsets and ACT */ + /* set UAs on most devices (LUs) in this target */ + list_for_each_entry(dp, + &devip->sdbg_host->dev_info_list, + dev_list) + if (dp->target == sdp->id) { + set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); + if (devip != dp) + set_bit(SDEBUG_UA_MICROCODE_CHANGED, + dp->uas_bm); + } + break; + case 0x7: /* download MC with offsets, save, and ACT */ + /* set UA on all devices (LUs) in this target */ + list_for_each_entry(dp, + &devip->sdbg_host->dev_info_list, + dev_list) + if (dp->target == sdp->id) + set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, + dp->uas_bm); + break; + default: + /* do nothing for this command for other mode values */ + break; + } + return 0; +} + static int resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { -- cgit v0.10.2 From 2195d9690464445d0c30ee8170030a8e696f2053 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 27 Jul 2014 17:11:18 +0200 Subject: 3w-9xxx.c: Cleaning up missing null-terminate in conjunction with strncpy Replacing strncpy with strlcpy to avoid strings that lacks null terminate. And use the sizeof on the to string rather than strlen on the from string. Signed-off-by: Rickard Strandqvist Acked-by: Adam Radford Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index cd4129f..7600639 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -608,7 +608,8 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) } /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); + strlcpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, + sizeof(tw_dev->tw_compat_info.driver_version)); tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; -- cgit v0.10.2 From c51e3a4fc45dab1b96159f02a610cccf58d1cfe3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Dec 2014 13:56:10 +0300 Subject: mpt2sas: issue_reset is uninitialized The "issue_reset" variable can be used uninitialized. It should be set to false at the start. Also I cleaned up the types by using bool. Signed-off-by: Dan Carpenter Acked-by: Sreekanth Reddy Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 58e4521..3fb01d1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3236,7 +3236,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3300,7 +3300,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4); if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; + issue_reset = true; goto issue_host_reset; } if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) @@ -3341,7 +3341,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3398,7 +3398,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SepRequest_t)/4); if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; + issue_reset = true; goto issue_host_reset; } if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) -- cgit v0.10.2 From eb44552b98b414f00762ede69e5a8398bb50766f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Dec 2014 13:57:05 +0300 Subject: mpt3sas: issue_reset is uninitialized The "issue_reset" can be used uninitialized. It should be set to false at the start. Also I cleaned up the types a little by using bool. Signed-off-by: Dan Carpenter Acked-by: Sreekanth Reddy Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 1560115..b9c2739 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3419,7 +3419,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3483,7 +3483,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4); if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) - issue_reset = 1; + issue_reset = true; goto issue_host_reset; } if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) @@ -3523,7 +3523,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3581,7 +3581,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SepRequest_t)/4); if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) - issue_reset = 1; + issue_reset = false; goto issue_host_reset; } if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) -- cgit v0.10.2 From 37c0b105ae61113b98a81529cccc3a8404ba68b7 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 2 Jan 2015 15:18:13 +0100 Subject: esp_scsi: remove check for ESP_MAX_TAGS 'num_tags' is an unsigned char, so the check for 'ESP_MAX_TAGS' (which is set to 256) is pointless. Acked-by: Geert Uytterhoeven Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index ce5bd52..065b25d 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2396,8 +2396,6 @@ int scsi_esp_register(struct esp *esp, struct device *dev) if (!esp->num_tags) esp->num_tags = ESP_DEFAULT_TAGS; - else if (esp->num_tags >= ESP_MAX_TAG) - esp->num_tags = ESP_MAX_TAG - 1; esp->host->transportt = esp_transport_template; esp->host->max_lun = ESP_MAX_LUN; esp->host->cmd_per_lun = 2; -- cgit v0.10.2 From d454c91f74fcefce5cd545cf98c565ed882bf81a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 30 Dec 2014 12:08:58 -0500 Subject: lpfc: correct device removal deadlock after link bounce This patch, applicable to 8G/4G/2G adapters, adds a call that resumes transmit operations after a link bounce. Without it, targets that tried to suspend exchanges after a link bounce (such as tape devices using sequence level error recovery) would never resume io operation, causing scan failures, and eventually deadlocks if a device removal request is made. Signed-off-by: James Smart Signed-off-by: Dick Kennedy Reviewed-by: Ewan D. Milne Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4c25485..c66088d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2225,6 +2225,15 @@ lpfc_adisc_done(struct lpfc_vport *vport) if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && !(vport->fc_flag & FC_RSCN_MODE) && (phba->sli_rev < LPFC_SLI_REV4)) { + /* The ADISCs are complete. Doesn't matter if they + * succeeded or failed because the ADISC completion + * routine guarantees to call the state machine and + * the RPI is either unregistered (failed ADISC response) + * or the RPI is still valid and the node is marked + * mapped for a target. The exchanges should be in the + * correct state. This code is specific to SLI3. + */ + lpfc_issue_clear_la(phba, vport); lpfc_issue_reg_vpi(phba, vport); return; } -- cgit v0.10.2 From ead3700d893654d440edcb66fb3767a0c0db54cf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 29 Dec 2014 20:05:09 -0800 Subject: storvsc: use cmd_size to allocate per-command data STORVSC uses its own momory pool to manage device request data. However, the SCSI layer already has a mechanisim for allocating additional memory for each command issued to device driver. This patch removes the memory pool in STORVSC and makes it use SCSI layer to allocate memory for device request data. Reviewed-by: Long Li Signed-off-by: Christoph Hellwig Signed-off-by: K. Y. Srinivasan Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 4cff0dd..14ee98e 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -309,14 +308,6 @@ enum storvsc_request_type { * This is the end of Protocol specific defines. */ - -/* - * We setup a mempool to allocate request structures for this driver - * on a per-lun basis. The following define specifies the number of - * elements in the pool. - */ - -#define STORVSC_MIN_BUF_NR 64 static int storvsc_ringbuffer_size = (20 * PAGE_SIZE); module_param(storvsc_ringbuffer_size, int, S_IRUGO); @@ -346,7 +337,6 @@ static void storvsc_on_channel_callback(void *context); #define STORVSC_IDE_MAX_CHANNELS 1 struct storvsc_cmd_request { - struct list_head entry; struct scsi_cmnd *cmd; unsigned int bounce_sgl_count; @@ -357,7 +347,6 @@ struct storvsc_cmd_request { /* Synchronize the request/response if needed */ struct completion wait_event; - unsigned char *sense_buffer; struct hv_multipage_buffer data_buffer; struct vstor_packet vstor_packet; }; @@ -389,11 +378,6 @@ struct storvsc_device { struct storvsc_cmd_request reset_request; }; -struct stor_mem_pools { - struct kmem_cache *request_pool; - mempool_t *request_mempool; -}; - struct hv_host_device { struct hv_device *dev; unsigned int port; @@ -1070,10 +1054,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) { struct scsi_cmnd *scmnd = cmd_request->cmd; struct hv_host_device *host_dev = shost_priv(scmnd->device->host); - void (*scsi_done_fn)(struct scsi_cmnd *); struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; - struct stor_mem_pools *memp = scmnd->device->hostdata; struct Scsi_Host *host; struct storvsc_device *stor_dev; struct hv_device *dev = host_dev->dev; @@ -1109,14 +1091,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) cmd_request->data_buffer.len - vm_srb->data_transfer_length); - scsi_done_fn = scmnd->scsi_done; - - scmnd->host_scribble = NULL; - scmnd->scsi_done = NULL; - - scsi_done_fn(scmnd); - - mempool_free(cmd_request, memp->request_mempool); + scmnd->scsi_done(scmnd); } static void storvsc_on_io_completion(struct hv_device *device, @@ -1160,7 +1135,7 @@ static void storvsc_on_io_completion(struct hv_device *device, SRB_STATUS_AUTOSENSE_VALID) { /* autosense data available */ - memcpy(request->sense_buffer, + memcpy(request->cmd->sense_buffer, vstor_packet->vm_srb.sense_data, vstor_packet->vm_srb.sense_info_length); @@ -1378,55 +1353,6 @@ static int storvsc_do_io(struct hv_device *device, return ret; } -static int storvsc_device_alloc(struct scsi_device *sdevice) -{ - struct stor_mem_pools *memp; - int number = STORVSC_MIN_BUF_NR; - - memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL); - if (!memp) - return -ENOMEM; - - memp->request_pool = - kmem_cache_create(dev_name(&sdevice->sdev_dev), - sizeof(struct storvsc_cmd_request), 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (!memp->request_pool) - goto err0; - - memp->request_mempool = mempool_create(number, mempool_alloc_slab, - mempool_free_slab, - memp->request_pool); - - if (!memp->request_mempool) - goto err1; - - sdevice->hostdata = memp; - - return 0; - -err1: - kmem_cache_destroy(memp->request_pool); - -err0: - kfree(memp); - return -ENOMEM; -} - -static void storvsc_device_destroy(struct scsi_device *sdevice) -{ - struct stor_mem_pools *memp = sdevice->hostdata; - - if (!memp) - return; - - mempool_destroy(memp->request_mempool); - kmem_cache_destroy(memp->request_pool); - kfree(memp); - sdevice->hostdata = NULL; -} - static int storvsc_device_configure(struct scsi_device *sdevice) { scsi_change_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS); @@ -1561,13 +1487,11 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) int ret; struct hv_host_device *host_dev = shost_priv(host); struct hv_device *dev = host_dev->dev; - struct storvsc_cmd_request *cmd_request; - unsigned int request_size = 0; + struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd); int i; struct scatterlist *sgl; unsigned int sg_count = 0; struct vmscsi_request *vm_srb; - struct stor_mem_pools *memp = scmnd->device->hostdata; if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) { /* @@ -1584,25 +1508,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) } } - request_size = sizeof(struct storvsc_cmd_request); - - cmd_request = mempool_alloc(memp->request_mempool, - GFP_ATOMIC); - - /* - * We might be invoked in an interrupt context; hence - * mempool_alloc() can fail. - */ - if (!cmd_request) - return SCSI_MLQUEUE_DEVICE_BUSY; - - memset(cmd_request, 0, sizeof(struct storvsc_cmd_request)); - /* Setup the cmd request */ cmd_request->cmd = scmnd; - scmnd->host_scribble = (unsigned char *)cmd_request; - vm_srb = &cmd_request->vstor_packet.vm_srb; vm_srb->win8_extension.time_out_value = 60; @@ -1637,9 +1545,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); - cmd_request->sense_buffer = scmnd->sense_buffer; - - cmd_request->data_buffer.len = scsi_bufflen(scmnd); if (scsi_sg_count(scmnd)) { sgl = (struct scatterlist *)scsi_sglist(scmnd); @@ -1651,10 +1556,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) create_bounce_buffer(sgl, scsi_sg_count(scmnd), scsi_bufflen(scmnd), vm_srb->data_in); - if (!cmd_request->bounce_sgl) { - ret = SCSI_MLQUEUE_HOST_BUSY; - goto queue_error; - } + if (!cmd_request->bounce_sgl) + return SCSI_MLQUEUE_HOST_BUSY; cmd_request->bounce_sgl_count = ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >> @@ -1692,27 +1595,21 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); - ret = SCSI_MLQUEUE_DEVICE_BUSY; - goto queue_error; + return SCSI_MLQUEUE_DEVICE_BUSY; } return 0; - -queue_error: - mempool_free(cmd_request, memp->request_mempool); - scmnd->host_scribble = NULL; - return ret; } static struct scsi_host_template scsi_driver = { .module = THIS_MODULE, .name = "storvsc_host_t", + .cmd_size = sizeof(struct storvsc_cmd_request), .bios_param = storvsc_get_chs, .queuecommand = storvsc_queuecommand, .eh_host_reset_handler = storvsc_host_reset_handler, + .proc_name = "storvsc_host", .eh_timed_out = storvsc_eh_timed_out, - .slave_alloc = storvsc_device_alloc, - .slave_destroy = storvsc_device_destroy, .slave_configure = storvsc_device_configure, .cmd_per_lun = 255, .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS, -- cgit v0.10.2 From 2a09ed3d97ff8b5b377f86da9b9afd9ebd97b362 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 16 Dec 2014 13:21:42 -0800 Subject: storvsc: in responce to a scan event, scan the host The virtual HBA that storvsc implements can support multiple channels and targets. So, scan the host when the host notifies that a scan is needed. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 14ee98e..ab0bb98 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -410,21 +410,16 @@ done: kfree(wrk); } -static void storvsc_bus_scan(struct work_struct *work) +static void storvsc_host_scan(struct work_struct *work) { struct storvsc_scan_work *wrk; - int id, order_id; + struct Scsi_Host *host; wrk = container_of(work, struct storvsc_scan_work, work); - for (id = 0; id < wrk->host->max_id; ++id) { - if (wrk->host->reverse_ordering) - order_id = wrk->host->max_id - id - 1; - else - order_id = id; - - scsi_scan_target(&wrk->host->shost_gendev, 0, - order_id, SCAN_WILD_CARD, 1); - } + host = wrk->host; + + scsi_scan_host(host); + kfree(wrk); } @@ -1173,7 +1168,7 @@ static void storvsc_on_receive(struct hv_device *device, if (!work) return; - INIT_WORK(&work->work, storvsc_bus_scan); + INIT_WORK(&work->work, storvsc_host_scan); work->host = stor_device->host; schedule_work(&work->work); break; -- cgit v0.10.2 From 34a716bc345ba06c34aa33d09536fcb607523818 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 16 Dec 2014 13:21:43 -0800 Subject: storvsc: force discovery of LUNs that may have been removed. The host asks the guest to scan when a LUN is removed or added. The only way a guest can identify the removed LUN is when an I/O is attempted on a removed LUN - the SRB status code indicates that the LUN is invalid. We currently handle this SRB status and remove the device. Rather than waiting for an I/O to remove the device, force the discovery of LUNs that may have been removed prior to discovering LUNs that may have been added. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index ab0bb98..ae8293a 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -414,10 +414,36 @@ static void storvsc_host_scan(struct work_struct *work) { struct storvsc_scan_work *wrk; struct Scsi_Host *host; + struct scsi_device *sdev; + unsigned long flags; wrk = container_of(work, struct storvsc_scan_work, work); host = wrk->host; + /* + * Before scanning the host, first check to see if any of the + * currrently known devices have been hot removed. We issue a + * "unit ready" command against all currently known devices. + * This I/O will result in an error for devices that have been + * removed. As part of handling the I/O error, we remove the device. + * + * When a LUN is added or removed, the host sends us a signal to + * scan the host. Thus we are forced to discover the LUNs that + * may have been removed this way. + */ + mutex_lock(&host->scan_mutex); + spin_lock_irqsave(host->host_lock, flags); + list_for_each_entry(sdev, &host->__devices, siblings) { + spin_unlock_irqrestore(host->host_lock, flags); + scsi_test_unit_ready(sdev, 1, 1, NULL); + spin_lock_irqsave(host->host_lock, flags); + continue; + } + spin_unlock_irqrestore(host->host_lock, flags); + mutex_unlock(&host->scan_mutex); + /* + * Now scan the host to discover LUNs that may have been added. + */ scsi_scan_host(host); kfree(wrk); -- cgit v0.10.2 From 0fb8db29f2a02e8451e4e56d364c706f70a9ef00 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 16 Dec 2014 13:21:44 -0800 Subject: storvsc: fix a bug in storvsc limits Commit 4cd83ecdac20d30725b4f96e5d7814a1e290bc7e changed the limits to reflect the values on the host. It turns out that WS2008R2 cannot correctly handle these new limits. Fix this bug by setting the limits based on the host. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index ae8293a..caa9f0e 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1678,6 +1678,9 @@ static int storvsc_probe(struct hv_device *device, bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); int target = 0; struct storvsc_device *stor_device; + int max_luns_per_target; + int max_targets; + int max_channels; /* * Based on the windows host we are running on, @@ -1691,12 +1694,18 @@ static int storvsc_probe(struct hv_device *device, vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); vmstor_current_major = VMSTOR_WIN7_MAJOR; vmstor_current_minor = VMSTOR_WIN7_MINOR; + max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET; + max_targets = STORVSC_IDE_MAX_TARGETS; + max_channels = STORVSC_IDE_MAX_CHANNELS; break; default: sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = 0; vmstor_current_major = VMSTOR_WIN8_MAJOR; vmstor_current_minor = VMSTOR_WIN8_MINOR; + max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET; + max_targets = STORVSC_MAX_TARGETS; + max_channels = STORVSC_MAX_CHANNELS; break; } @@ -1744,9 +1753,9 @@ static int storvsc_probe(struct hv_device *device, break; case SCSI_GUID: - host->max_lun = STORVSC_MAX_LUNS_PER_TARGET; - host->max_id = STORVSC_MAX_TARGETS; - host->max_channel = STORVSC_MAX_CHANNELS - 1; + host->max_lun = max_luns_per_target; + host->max_id = max_targets; + host->max_channel = max_channels - 1; break; default: -- cgit v0.10.2 From b0a93d96b2814c725161f91a4e35d0c29ec0f95b Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 16 Dec 2014 13:21:45 -0800 Subject: storvsc: force SPC-3 compliance on win8 and win8 r2 hosts On win8 and win8 r2 hosts force SPC-3 compliance for MSFT virtual disks. Ubuntu has been carrying a similar patch outside the tree for a while now. Starting with win10, the host will support SPC-3 compliance. Based on all the testing that has been done on win8 and win8 r2 hosts, we are comfortable claiming SPC-3 compliance on these hosts as well. This will enable TRIM support on these hosts. Suggested by: James Bottomley Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index caa9f0e..efc6e44 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1394,6 +1394,19 @@ static int storvsc_device_configure(struct scsi_device *sdevice) */ sdevice->sdev_bflags |= msft_blist_flags; + /* + * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3 + * if the device is a MSFT virtual device. + */ + if (!strncmp(sdevice->vendor, "Msft", 4)) { + switch (vmbus_proto_version) { + case VERSION_WIN8: + case VERSION_WIN8_1: + sdevice->scsi_level = SCSI_SPC_3; + break; + } + } + return 0; } -- cgit v0.10.2 From ded85c193a391a84076d5c6a7a5668fe164a490e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:42 +0100 Subject: scsi: Implement per-cpu logging buffer Implement a per-cpu buffer for formatting messages to avoid line breaks up under high load. This patch implements scmd_printk() and sdev_prefix_printk() using the per-cpu buffer and makes sdev_printk() a wrapper for sdev_prefix_printk(). Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 58158f1..447c2d2 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -167,7 +167,7 @@ scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o -scsi_mod-y += scsi_trace.o +scsi_mod-y += scsi_trace.o scsi_logging.o scsi_mod-$(CONFIG_PM) += scsi_pm.o hv_storvsc-y := storvsc_drv.o diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c new file mode 100644 index 0000000..09d65de --- /dev/null +++ b/drivers/scsi/scsi_logging.c @@ -0,0 +1,124 @@ +/* + * scsi_logging.c + * + * Copyright (C) 2014 SUSE Linux Products GmbH + * Copyright (C) 2014 Hannes Reinecke + * + * This file is released under the GPLv2 + */ + +#include +#include + +#include +#include +#include +#include + +#define SCSI_LOG_SPOOLSIZE 4096 +#define SCSI_LOG_BUFSIZE 128 + +#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG +#warning SCSI logging bitmask too large +#endif + +struct scsi_log_buf { + char buffer[SCSI_LOG_SPOOLSIZE]; + unsigned long map; +}; + +static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log); + +static char *scsi_log_reserve_buffer(size_t *len) +{ + struct scsi_log_buf *buf; + unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE; + unsigned long idx = 0; + + preempt_disable(); + buf = this_cpu_ptr(&scsi_format_log); + idx = find_first_zero_bit(&buf->map, map_bits); + if (likely(idx < map_bits)) { + while (test_and_set_bit(idx, &buf->map)) { + idx = find_next_zero_bit(&buf->map, map_bits, idx); + if (idx >= map_bits) + break; + } + } + if (WARN_ON(idx >= map_bits)) { + preempt_enable(); + return NULL; + } + *len = SCSI_LOG_BUFSIZE; + return buf->buffer + idx * SCSI_LOG_BUFSIZE; +} + +static void scsi_log_release_buffer(char *bufptr) +{ + struct scsi_log_buf *buf; + unsigned long idx; + int ret; + + buf = this_cpu_ptr(&scsi_format_log); + if (bufptr >= buf->buffer && + bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) { + idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE; + ret = test_and_clear_bit(idx, &buf->map); + WARN_ON(!ret); + } + preempt_enable(); +} + +int sdev_prefix_printk(const char *level, const struct scsi_device *sdev, + const char *name, const char *fmt, ...) +{ + va_list args; + char *logbuf; + size_t off = 0, logbuf_len; + int ret; + + if (!sdev) + return 0; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return 0; + + if (name) + off += scnprintf(logbuf + off, logbuf_len - off, + "[%s] ", name); + va_start(args, fmt); + off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); + va_end(args); + ret = dev_printk(level, &sdev->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); + return ret; +} +EXPORT_SYMBOL(sdev_prefix_printk); + +int scmd_printk(const char *level, const struct scsi_cmnd *scmd, + const char *fmt, ...) +{ + struct gendisk *disk = scmd->request->rq_disk; + va_list args; + char *logbuf; + size_t off = 0, logbuf_len; + int ret; + + if (!scmd || !scmd->cmnd) + return 0; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return 0; + if (disk) + off += scnprintf(logbuf + off, logbuf_len - off, + "[%s] ", disk->disk_name); + va_start(args, fmt); + off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); + va_end(args); + ret = dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); + return ret; +} +EXPORT_SYMBOL(scmd_printk); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 3a4edd1..d1aad4d 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -230,9 +230,6 @@ struct scsi_dh_data { #define transport_class_to_sdev(class_dev) \ to_scsi_device(class_dev->parent) -#define sdev_printk(prefix, sdev, fmt, a...) \ - dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a) - #define sdev_dbg(sdev, fmt, a...) \ dev_dbg(&(sdev)->sdev_gendev, fmt, ##a) @@ -240,16 +237,14 @@ struct scsi_dh_data { * like scmd_printk, but the device name is passed in * as a string pointer */ -#define sdev_prefix_printk(l, sdev, p, fmt, a...) \ - (p) ? \ - sdev_printk(l, sdev, "[%s] " fmt, p, ##a) : \ - sdev_printk(l, sdev, fmt, ##a) - -#define scmd_printk(prefix, scmd, fmt, a...) \ - (scmd)->request->rq_disk ? \ - sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \ - (scmd)->request->rq_disk->disk_name, ##a) : \ - sdev_printk(prefix, (scmd)->device, fmt, ##a) +extern int sdev_prefix_printk(const char *, const struct scsi_device *, + const char *, const char *, ...); + +#define sdev_printk(l, sdev, fmt, a...) \ + sdev_prefix_printk(l, sdev, NULL, fmt, ##a) + +extern int scmd_printk(const char *, const struct scsi_cmnd *, + const char *, ...); #define scmd_dbg(scmd, fmt, a...) \ do { \ -- cgit v0.10.2 From aa66ab35f2b31e96f4b60e675b2d6ffc51d472eb Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:43 +0100 Subject: scsi: log request tag for scmd_printk() The request tag provides a concise identification of a SCSI command, so we should be printing that out for scmd_printk(). Suggested-by: Christoph Hellwig Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index 09d65de..4d20132 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -114,6 +114,10 @@ int scmd_printk(const char *level, const struct scsi_cmnd *scmd, if (disk) off += scnprintf(logbuf + off, logbuf_len - off, "[%s] ", disk->disk_name); + + if (scmd->request->tag >= 0) + off += scnprintf(logbuf + off, logbuf_len - off, + "tag#%d ", scmd->request->tag); va_start(args, fmt); off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); va_end(args); -- cgit v0.10.2 From 9e5ed2a5b3662c6f398023042c02aaa527099a3d Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:44 +0100 Subject: scsi: use external buffer for command logging Use an external buffer for __scsi_print_command() and move command logging over to use the per-cpu logging buffer. With that we can guarantee the command always will always be formatted in one line. So we can even print out a variable length command correctly across several lines. Finally rename __scsi_print_command() to __scsi_format_comment() to better reflect the functionality. Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 6bac8a7..79e462f 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -195,8 +195,10 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, retry: errno = 0; if (debug) { - DPRINTK("command: "); - __scsi_print_command(cmd, cmd_len); + char logbuf[SCSI_LOG_BUFSIZE]; + + __scsi_format_command(logbuf, sizeof(logbuf), cmd, cmd_len); + DPRINTK("command: %s", logbuf); } result = scsi_execute_req(ch->device, cmd, direction, buffer, diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 55a7157..7792960 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -24,8 +24,6 @@ #define THIRD_PARTY_COPY_OUT 0x83 #define THIRD_PARTY_COPY_IN 0x84 -#define VENDOR_SPECIFIC_CDB 0xc0 - struct sa_name_list { int opcode; const struct value_name_pair *arr; @@ -281,8 +279,8 @@ static struct sa_name_list sa_names_arr[] = { }; #endif /* CONFIG_SCSI_CONSTANTS */ -static bool scsi_opcode_sa_name(int opcode, int service_action, - const char **cdb_name, const char **sa_name) +bool scsi_opcode_sa_name(int opcode, int service_action, + const char **cdb_name, const char **sa_name) { struct sa_name_list *sa_name_ptr; const struct value_name_pair *arr = NULL; @@ -315,74 +313,6 @@ static bool scsi_opcode_sa_name(int opcode, int service_action, return true; } -static void print_opcode_name(const unsigned char *cdbp, size_t cdb_len) -{ - int sa, cdb0; - const char *cdb_name = NULL, *sa_name = NULL; - - cdb0 = cdbp[0]; - if (cdb0 == VARIABLE_LENGTH_CMD) { - if (cdb_len < 10) { - printk("short variable length command, len=%zu", - cdb_len); - return; - } - sa = (cdbp[8] << 8) + cdbp[9]; - } else - sa = cdbp[1] & 0x1f; - - if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) { - if (cdb_name) - printk("%s", cdb_name); - else if (cdb0 >= VENDOR_SPECIFIC_CDB) - printk("cdb[0]=0x%x (vendor)", cdb0); - else if (cdb0 >= 0x60 && cdb0 < 0x7e) - printk("cdb[0]=0x%x (reserved)", cdb0); - else - printk("cdb[0]=0x%x", cdb0); - } else { - if (sa_name) - printk("%s", sa_name); - else if (cdb_name) - printk("%s, sa=0x%x", cdb_name, sa); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - } -} - -void __scsi_print_command(const unsigned char *cdb, size_t cdb_len) -{ - int k, len; - - print_opcode_name(cdb, cdb_len); - len = scsi_command_size(cdb); - if (cdb_len < len) - len = cdb_len; - /* print out all bytes in cdb */ - for (k = 0; k < len; ++k) - printk(" %02x", cdb[k]); - printk("\n"); -} -EXPORT_SYMBOL(__scsi_print_command); - -void scsi_print_command(struct scsi_cmnd *cmd) -{ - int k; - - if (cmd->cmnd == NULL) - return; - - scmd_printk(KERN_INFO, cmd, "CDB: "); - print_opcode_name(cmd->cmnd, cmd->cmd_len); - - /* print out all bytes in cdb */ - printk(":"); - for (k = 0; k < cmd->cmd_len; ++k) - printk(" %02x", cmd->cmnd[k]); - printk("\n"); -} -EXPORT_SYMBOL(scsi_print_command); - #ifdef CONFIG_SCSI_CONSTANTS struct error_info { diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index 4d20132..afba995 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -13,10 +13,10 @@ #include #include #include +#include #include #define SCSI_LOG_SPOOLSIZE 4096 -#define SCSI_LOG_BUFSIZE 128 #if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG #warning SCSI logging bitmask too large @@ -69,6 +69,24 @@ static void scsi_log_release_buffer(char *bufptr) preempt_enable(); } +static size_t scmd_format_header(char *logbuf, size_t logbuf_len, + struct gendisk *disk, int tag) +{ + size_t off = 0; + + if (disk) + off += scnprintf(logbuf + off, logbuf_len - off, + "[%s] ", disk->disk_name); + + if (WARN_ON(off >= logbuf_len)) + return off; + + if (tag >= 0) + off += scnprintf(logbuf + off, logbuf_len - off, + "tag#%d ", tag); + return off; +} + int sdev_prefix_printk(const char *level, const struct scsi_device *sdev, const char *name, const char *fmt, ...) { @@ -87,9 +105,11 @@ int sdev_prefix_printk(const char *level, const struct scsi_device *sdev, if (name) off += scnprintf(logbuf + off, logbuf_len - off, "[%s] ", name); - va_start(args, fmt); - off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); - va_end(args); + if (!WARN_ON(off >= logbuf_len)) { + va_start(args, fmt); + off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); + va_end(args); + } ret = dev_printk(level, &sdev->sdev_gendev, "%s", logbuf); scsi_log_release_buffer(logbuf); return ret; @@ -111,18 +131,152 @@ int scmd_printk(const char *level, const struct scsi_cmnd *scmd, logbuf = scsi_log_reserve_buffer(&logbuf_len); if (!logbuf) return 0; - if (disk) - off += scnprintf(logbuf + off, logbuf_len - off, - "[%s] ", disk->disk_name); - - if (scmd->request->tag >= 0) - off += scnprintf(logbuf + off, logbuf_len - off, - "tag#%d ", scmd->request->tag); - va_start(args, fmt); - off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); - va_end(args); + off = scmd_format_header(logbuf, logbuf_len, disk, + scmd->request->tag); + if (off < logbuf_len) { + va_start(args, fmt); + off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); + va_end(args); + } ret = dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf); scsi_log_release_buffer(logbuf); return ret; } EXPORT_SYMBOL(scmd_printk); + +static size_t scsi_format_opcode_name(char *buffer, size_t buf_len, + const unsigned char *cdbp) +{ + int sa, cdb0; + const char *cdb_name = NULL, *sa_name = NULL; + size_t off; + + cdb0 = cdbp[0]; + if (cdb0 == VARIABLE_LENGTH_CMD) { + int len = scsi_varlen_cdb_length(cdbp); + + if (len < 10) { + off = scnprintf(buffer, buf_len, + "short variable length command, len=%d", + len); + return off; + } + sa = (cdbp[8] << 8) + cdbp[9]; + } else + sa = cdbp[1] & 0x1f; + + if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) { + if (cdb_name) + off = scnprintf(buffer, buf_len, "%s", cdb_name); + else { + off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0); + if (WARN_ON(off >= buf_len)) + return off; + if (cdb0 >= VENDOR_SPECIFIC_CDB) + off += scnprintf(buffer + off, buf_len - off, + " (vendor)"); + else if (cdb0 >= 0x60 && cdb0 < 0x7e) + off += scnprintf(buffer + off, buf_len - off, + " (reserved)"); + } + } else { + if (sa_name) + off = scnprintf(buffer, buf_len, "%s", sa_name); + else if (cdb_name) + off = scnprintf(buffer, buf_len, "%s, sa=0x%x", + cdb_name, sa); + else + off = scnprintf(buffer, buf_len, + "opcode=0x%x, sa=0x%x", cdb0, sa); + } + WARN_ON(off >= buf_len); + return off; +} + +size_t __scsi_format_command(char *logbuf, size_t logbuf_len, + const unsigned char *cdb, size_t cdb_len) +{ + int len, k; + size_t off; + + off = scsi_format_opcode_name(logbuf, logbuf_len, cdb); + if (off >= logbuf_len) + return off; + len = scsi_command_size(cdb); + if (cdb_len < len) + len = cdb_len; + /* print out all bytes in cdb */ + for (k = 0; k < len; ++k) { + if (off > logbuf_len - 3) + break; + off += scnprintf(logbuf + off, logbuf_len - off, + " %02x", cdb[k]); + } + return off; +} +EXPORT_SYMBOL(__scsi_format_command); + +void scsi_print_command(struct scsi_cmnd *cmd) +{ + struct gendisk *disk = cmd->request->rq_disk; + int k; + char *logbuf; + size_t off, logbuf_len; + + if (!cmd->cmnd) + return; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + off = scmd_format_header(logbuf, logbuf_len, disk, cmd->request->tag); + if (off >= logbuf_len) + goto out_printk; + off += scnprintf(logbuf + off, logbuf_len - off, "CDB: "); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + off += scsi_format_opcode_name(logbuf + off, logbuf_len - off, + cmd->cmnd); + if (off >= logbuf_len) + goto out_printk; + + /* print out all bytes in cdb */ + if (cmd->cmd_len > 16) { + /* Print opcode in one line and use separate lines for CDB */ + off += scnprintf(logbuf + off, logbuf_len - off, "\n"); + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, logbuf); + scsi_log_release_buffer(logbuf); + for (k = 0; k < cmd->cmd_len; k += 16) { + size_t linelen = min(cmd->cmd_len - k, 16); + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + break; + off = scmd_format_header(logbuf, logbuf_len, disk, + cmd->request->tag); + if (!WARN_ON(off > logbuf_len - 58)) { + off += scnprintf(logbuf + off, logbuf_len - off, + "CDB[%02x]: ", k); + hex_dump_to_buffer(&cmd->cmnd[k], linelen, + 16, 1, logbuf + off, + logbuf_len - off, false); + } + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, + logbuf); + scsi_log_release_buffer(logbuf); + } + return; + } + if (!WARN_ON(off > logbuf_len - 49)) { + off += scnprintf(logbuf + off, logbuf_len - off, " "); + hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1, + logbuf + off, logbuf_len - off, + false); + } +out_printk: + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, logbuf); + scsi_log_release_buffer(logbuf); +} +EXPORT_SYMBOL(scsi_print_command); diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index fb929fa..e8deb9c 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -188,6 +188,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; struct request_sense *sense = cgc->sense; + char logbuf[SCSI_LOG_BUFSIZE]; SDev = cd->device; @@ -257,14 +258,20 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; #ifdef DEBUG - __scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE); + __scsi_format_command(logbuf, sizeof(logbuf), + cgc->cmd, CDROM_PACKET_SIZE); + sr_printk(KERN_INFO, cd, + "CDROM (ioctl) invalid command: %s\n", + logbuf); scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr); #endif break; default: + __scsi_format_command(logbuf, sizeof(logbuf), + cgc->cmd, CDROM_PACKET_SIZE); sr_printk(KERN_ERR, cd, - "CDROM (ioctl) error, command: "); - __scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE); + "CDROM (ioctl) error, command: %s\n", + logbuf); scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr); err = -EIO; } diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 8a7f8ad..d0a66aa 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -195,6 +195,9 @@ enum scsi_timeouts { #define ATA_16 0x85 /* 16-byte pass-thru */ #define ATA_12 0xa1 /* 12-byte pass-thru */ +/* Vendor specific CDBs start here */ +#define VENDOR_SPECIFIC_CDB 0xc0 + /* * SCSI command lengths */ diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 7982795..c7ed7b8 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -5,8 +5,12 @@ struct scsi_cmnd; struct scsi_device; struct scsi_sense_hdr; +#define SCSI_LOG_BUFSIZE 128 + +extern bool scsi_opcode_sa_name(int, int, const char **, const char **); extern void scsi_print_command(struct scsi_cmnd *); -extern void __scsi_print_command(const unsigned char *, size_t); +extern size_t __scsi_format_command(char *, size_t, + const unsigned char *, size_t); extern void scsi_show_extd_sense(const struct scsi_device *, const char *, unsigned char, unsigned char); extern void scsi_show_sense_hdr(const struct scsi_device *, const char *, -- cgit v0.10.2 From cbba5b0ee4c6c2fc8b78a21d0900099d480cf2e9 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:45 +0100 Subject: libata: use __scsi_format_command() libata already uses an internal buffer, so we should be using __scsi_format_command() here. Tested-by: Robert Elliott Reviewed-by: Robert Elliott Acked-by: Tejun Heo Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 3dbec89..9179f11 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2482,6 +2482,7 @@ static void ata_eh_link_report(struct ata_link *link) struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; const u8 *cdb = qc->cdb; + size_t cdb_len = qc->dev->cdb_len; char data_buf[20] = ""; char cdb_buf[70] = ""; @@ -2509,16 +2510,12 @@ static void ata_eh_link_report(struct ata_link *link) } if (ata_is_atapi(qc->tf.protocol)) { - if (qc->scsicmd) - scsi_print_command(qc->scsicmd); - else - snprintf(cdb_buf, sizeof(cdb_buf), - "cdb %02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n ", - cdb[0], cdb[1], cdb[2], cdb[3], - cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11], - cdb[12], cdb[13], cdb[14], cdb[15]); + if (qc->scsicmd) { + cdb = qc->scsicmd->cmnd; + cdb_len = qc->scsicmd->cmd_len; + } + __scsi_format_command(cdb_buf, sizeof(cdb_buf), + cdb, cdb_len); } else { const char *descr = ata_get_cmd_descript(cmd->command); if (descr) -- cgit v0.10.2 From 2104551969e8011e72788dc5674609d437448cf6 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:46 +0100 Subject: scsi: use per-cpu buffer for formatting sense Convert sense buffer logging to use the per-cpu buffer to avoid line breakup. Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 7792960..a23ef75 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1246,113 +1246,6 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) } EXPORT_SYMBOL(scsi_extd_sense_format); -void -scsi_show_extd_sense(const struct scsi_device *sdev, const char *name, - unsigned char asc, unsigned char ascq) -{ - const char *extd_sense_fmt = NULL; - const char *extd_sense_str = scsi_extd_sense_format(asc, ascq, - &extd_sense_fmt); - - if (extd_sense_str) { - if (extd_sense_fmt) - sdev_prefix_printk(KERN_INFO, sdev, name, - "Add. Sense: %s (%s%x)", - extd_sense_str, extd_sense_fmt, - ascq); - else - sdev_prefix_printk(KERN_INFO, sdev, name, - "Add. Sense: %s", extd_sense_str); - - } else { - sdev_prefix_printk(KERN_INFO, sdev, name, - "%sASC=0x%x %sASCQ=0x%x\n", - asc >= 0x80 ? "<> " : "", asc, - ascq >= 0x80 ? "<> " : "", ascq); - } -} -EXPORT_SYMBOL(scsi_show_extd_sense); - -void -scsi_show_sense_hdr(const struct scsi_device *sdev, const char *name, - const struct scsi_sense_hdr *sshdr) -{ - const char *sense_txt; - - sense_txt = scsi_sense_key_string(sshdr->sense_key); - if (sense_txt) - sdev_prefix_printk(KERN_INFO, sdev, name, - "Sense Key : %s [%s]%s\n", sense_txt, - scsi_sense_is_deferred(sshdr) ? - "deferred" : "current", - sshdr->response_code >= 0x72 ? - " [descriptor]" : ""); - else - sdev_prefix_printk(KERN_INFO, sdev, name, - "Sense Key : 0x%x [%s]%s", sshdr->sense_key, - scsi_sense_is_deferred(sshdr) ? - "deferred" : "current", - sshdr->response_code >= 0x72 ? - " [descriptor]" : ""); -} -EXPORT_SYMBOL(scsi_show_sense_hdr); - -/* - * Print normalized SCSI sense header with a prefix. - */ -void -scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name, - const struct scsi_sense_hdr *sshdr) -{ - scsi_show_sense_hdr(sdev, name, sshdr); - scsi_show_extd_sense(sdev, name, sshdr->asc, sshdr->ascq); -} -EXPORT_SYMBOL(scsi_print_sense_hdr); - -static void -scsi_dump_sense_buffer(const unsigned char *sense_buffer, int sense_len) -{ - int k, num; - - num = (sense_len < 32) ? sense_len : 32; - printk("Unrecognized sense data (in hex):"); - for (k = 0; k < num; ++k) { - if (0 == (k % 16)) { - printk("\n"); - printk(KERN_INFO " "); - } - printk("%02x ", sense_buffer[k]); - } - printk("\n"); - return; -} - -/* Normalize and print sense buffer with name prefix */ -void __scsi_print_sense(const struct scsi_device *sdev, const char *name, - const unsigned char *sense_buffer, int sense_len) -{ - struct scsi_sense_hdr sshdr; - - if (!scsi_normalize_sense(sense_buffer, sense_len, &sshdr)) { - scsi_dump_sense_buffer(sense_buffer, sense_len); - return; - } - scsi_show_sense_hdr(sdev, name, &sshdr); - scsi_show_extd_sense(sdev, name, sshdr.asc, sshdr.ascq); -} -EXPORT_SYMBOL(__scsi_print_sense); - -/* Normalize and print sense buffer in SCSI command */ -void scsi_print_sense(const struct scsi_cmnd *cmd) -{ - struct gendisk *disk = cmd->request->rq_disk; - const char *disk_name = disk ? disk->disk_name : NULL; - - __scsi_print_sense(cmd->device, disk_name, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE); -} -EXPORT_SYMBOL(scsi_print_sense); - #ifdef CONFIG_SCSI_CONSTANTS static const char * const hostbyte_table[]={ diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index afba995..c7cba31 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -69,14 +69,20 @@ static void scsi_log_release_buffer(char *bufptr) preempt_enable(); } -static size_t scmd_format_header(char *logbuf, size_t logbuf_len, - struct gendisk *disk, int tag) +static inline const char *scmd_name(const struct scsi_cmnd *scmd) +{ + return scmd->request->rq_disk ? + scmd->request->rq_disk->disk_name : NULL; +} + +static size_t sdev_format_header(char *logbuf, size_t logbuf_len, + const char *name, int tag) { size_t off = 0; - if (disk) + if (name) off += scnprintf(logbuf + off, logbuf_len - off, - "[%s] ", disk->disk_name); + "[%s] ", name); if (WARN_ON(off >= logbuf_len)) return off; @@ -119,7 +125,6 @@ EXPORT_SYMBOL(sdev_prefix_printk); int scmd_printk(const char *level, const struct scsi_cmnd *scmd, const char *fmt, ...) { - struct gendisk *disk = scmd->request->rq_disk; va_list args; char *logbuf; size_t off = 0, logbuf_len; @@ -131,7 +136,7 @@ int scmd_printk(const char *level, const struct scsi_cmnd *scmd, logbuf = scsi_log_reserve_buffer(&logbuf_len); if (!logbuf) return 0; - off = scmd_format_header(logbuf, logbuf_len, disk, + off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd), scmd->request->tag); if (off < logbuf_len) { va_start(args, fmt); @@ -218,7 +223,6 @@ EXPORT_SYMBOL(__scsi_format_command); void scsi_print_command(struct scsi_cmnd *cmd) { - struct gendisk *disk = cmd->request->rq_disk; int k; char *logbuf; size_t off, logbuf_len; @@ -230,7 +234,8 @@ void scsi_print_command(struct scsi_cmnd *cmd) if (!logbuf) return; - off = scmd_format_header(logbuf, logbuf_len, disk, cmd->request->tag); + off = sdev_format_header(logbuf, logbuf_len, + scmd_name(cmd), cmd->request->tag); if (off >= logbuf_len) goto out_printk; off += scnprintf(logbuf + off, logbuf_len - off, "CDB: "); @@ -254,7 +259,8 @@ void scsi_print_command(struct scsi_cmnd *cmd) logbuf = scsi_log_reserve_buffer(&logbuf_len); if (!logbuf) break; - off = scmd_format_header(logbuf, logbuf_len, disk, + off = sdev_format_header(logbuf, logbuf_len, + scmd_name(cmd), cmd->request->tag); if (!WARN_ON(off > logbuf_len - 58)) { off += scnprintf(logbuf + off, logbuf_len - off, @@ -280,3 +286,145 @@ out_printk: scsi_log_release_buffer(logbuf); } EXPORT_SYMBOL(scsi_print_command); + +static size_t +scsi_format_extd_sense(char *buffer, size_t buf_len, + unsigned char asc, unsigned char ascq) +{ + size_t off = 0; + const char *extd_sense_fmt = NULL; + const char *extd_sense_str = scsi_extd_sense_format(asc, ascq, + &extd_sense_fmt); + + if (extd_sense_str) { + off = scnprintf(buffer, buf_len, "Add. Sense: %s", + extd_sense_str); + if (extd_sense_fmt) + off += scnprintf(buffer + off, buf_len - off, + "(%s%x)", extd_sense_fmt, ascq); + } else { + if (asc >= 0x80) + off = scnprintf(buffer, buf_len, "<>"); + off += scnprintf(buffer + off, buf_len - off, + "ASC=0x%x ", asc); + if (ascq >= 0x80) + off += scnprintf(buffer + off, buf_len - off, + "<>"); + off += scnprintf(buffer + off, buf_len - off, + "ASCQ=0x%x ", ascq); + } + return off; +} + +static size_t +scsi_format_sense_hdr(char *buffer, size_t buf_len, + const struct scsi_sense_hdr *sshdr) +{ + const char *sense_txt; + size_t off; + + off = scnprintf(buffer, buf_len, "Sense Key : "); + sense_txt = scsi_sense_key_string(sshdr->sense_key); + if (sense_txt) + off += scnprintf(buffer + off, buf_len - off, + "%s ", sense_txt); + else + off += scnprintf(buffer + off, buf_len - off, + "0x%x ", sshdr->sense_key); + off += scnprintf(buffer + off, buf_len - off, + scsi_sense_is_deferred(sshdr) ? "[deferred] " : "[current] "); + + if (sshdr->response_code >= 0x72) + off += scnprintf(buffer + off, buf_len - off, "[descriptor] "); + return off; +} + +static void +scsi_log_dump_sense(const struct scsi_device *sdev, const char *name, int tag, + const unsigned char *sense_buffer, int sense_len) +{ + char *logbuf; + size_t logbuf_len; + int i; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + for (i = 0; i < sense_len; i += 16) { + int len = min(sense_len - i, 16); + size_t off; + + off = sdev_format_header(logbuf, logbuf_len, + name, tag); + hex_dump_to_buffer(&sense_buffer[i], len, 16, 1, + logbuf + off, logbuf_len - off, + false); + dev_printk(KERN_INFO, &sdev->sdev_gendev, logbuf); + } + scsi_log_release_buffer(logbuf); +} + +static void +scsi_log_print_sense_hdr(const struct scsi_device *sdev, const char *name, + int tag, const struct scsi_sense_hdr *sshdr) +{ + char *logbuf; + size_t off, logbuf_len; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + off = sdev_format_header(logbuf, logbuf_len, name, tag); + off += scsi_format_sense_hdr(logbuf + off, logbuf_len - off, sshdr); + dev_printk(KERN_INFO, &sdev->sdev_gendev, logbuf); + scsi_log_release_buffer(logbuf); + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + off = sdev_format_header(logbuf, logbuf_len, name, tag); + off += scsi_format_extd_sense(logbuf + off, logbuf_len - off, + sshdr->asc, sshdr->ascq); + dev_printk(KERN_INFO, &sdev->sdev_gendev, logbuf); + scsi_log_release_buffer(logbuf); +} + +static void +scsi_log_print_sense(const struct scsi_device *sdev, const char *name, int tag, + const unsigned char *sense_buffer, int sense_len) +{ + struct scsi_sense_hdr sshdr; + + if (scsi_normalize_sense(sense_buffer, sense_len, &sshdr)) + scsi_log_print_sense_hdr(sdev, name, tag, &sshdr); + else + scsi_log_dump_sense(sdev, name, tag, sense_buffer, sense_len); +} + +/* + * Print normalized SCSI sense header with a prefix. + */ +void +scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name, + const struct scsi_sense_hdr *sshdr) +{ + scsi_log_print_sense_hdr(sdev, name, -1, sshdr); +} +EXPORT_SYMBOL(scsi_print_sense_hdr); + +/* Normalize and print sense buffer with name prefix */ +void __scsi_print_sense(const struct scsi_device *sdev, const char *name, + const unsigned char *sense_buffer, int sense_len) +{ + scsi_log_print_sense(sdev, name, -1, sense_buffer, sense_len); +} +EXPORT_SYMBOL(__scsi_print_sense); + +/* Normalize and print sense buffer in SCSI command */ +void scsi_print_sense(const struct scsi_cmnd *cmd) +{ + scsi_log_print_sense(cmd->device, scmd_name(cmd), cmd->request->tag, + cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); +} +EXPORT_SYMBOL(scsi_print_sense); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3995169..ebf35cb6 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3318,11 +3318,8 @@ module_exit(exit_sd); static void sd_print_sense_hdr(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr) { - scsi_show_sense_hdr(sdkp->device, - sdkp->disk ? sdkp->disk->disk_name : NULL, sshdr); - scsi_show_extd_sense(sdkp->device, - sdkp->disk ? sdkp->disk->disk_name : NULL, - sshdr->asc, sshdr->ascq); + scsi_print_sense_hdr(sdkp->device, + sdkp->disk ? sdkp->disk->disk_name : NULL, sshdr); } static void sd_print_result(const struct scsi_disk *sdkp, const char *msg, diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2e4614b..5d60a86 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4714,10 +4714,8 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, sdev_printk(KERN_WARNING, sdp, "START_STOP failed for power mode: %d, result %x\n", pwr_mode, ret); - if (driver_byte(ret) & DRIVER_SENSE) { - scsi_show_sense_hdr(sdp, NULL, &sshdr); - scsi_show_extd_sense(sdp, NULL, sshdr.asc, sshdr.ascq); - } + if (driver_byte(ret) & DRIVER_SENSE) + scsi_print_sense_hdr(sdp, NULL, &sshdr); } if (!ret) -- cgit v0.10.2 From 026f8da8da4ce3423bf89e8e9091f55ae3863eda Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:47 +0100 Subject: scsi: use per-cpu buffer for formatting scsi_print_result() Convert scsi_print_result() to use the per-cpu buffer for decoding the command result and disposition. Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index a23ef75..956fbdd 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1316,25 +1316,3 @@ const char *scsi_mlreturn_string(int result) return NULL; } EXPORT_SYMBOL(scsi_mlreturn_string); - -void scsi_print_result(struct scsi_cmnd *cmd, const char *msg, int disposition) -{ - const char *mlret_string = scsi_mlreturn_string(disposition); - const char *hb_string = scsi_hostbyte_string(cmd->result); - const char *db_string = scsi_driverbyte_string(cmd->result); - - if (hb_string || db_string) - scmd_printk(KERN_INFO, cmd, - "%s%s Result: hostbyte=%s driverbyte=%s", - msg ? msg : "", - mlret_string ? mlret_string : "UNKNOWN", - hb_string ? hb_string : "invalid", - db_string ? db_string : "invalid"); - else - scmd_printk(KERN_INFO, cmd, - "%s%s Result: hostbyte=0x%02x driverbyte=0x%02x", - msg ? msg : "", - mlret_string ? mlret_string : "UNKNOWN", - host_byte(cmd->result), driver_byte(cmd->result)); -} -EXPORT_SYMBOL(scsi_print_result); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index e028854..7f028cb 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -572,7 +572,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) SCSI_LOG_MLCOMPLETE_BITS); if (((level > 0) && (cmd->result || disposition != SUCCESS)) || (level > 1)) { - scsi_print_result(cmd, "Done: ", disposition); + scsi_print_result(cmd, "Done", disposition); scsi_print_command(cmd); if (status_byte(cmd->result) & CHECK_CONDITION) scsi_print_sense(cmd); diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index c7cba31..6128303 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -428,3 +428,62 @@ void scsi_print_sense(const struct scsi_cmnd *cmd) cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); } EXPORT_SYMBOL(scsi_print_sense); + +void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg, + int disposition) +{ + char *logbuf; + size_t off, logbuf_len; + const char *mlret_string = scsi_mlreturn_string(disposition); + const char *hb_string = scsi_hostbyte_string(cmd->result); + const char *db_string = scsi_driverbyte_string(cmd->result); + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + off = sdev_format_header(logbuf, logbuf_len, + scmd_name(cmd), cmd->request->tag); + + if (off >= logbuf_len) + goto out_printk; + + if (msg) { + off += scnprintf(logbuf + off, logbuf_len - off, + "%s: ", msg); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + } + if (mlret_string) + off += scnprintf(logbuf + off, logbuf_len - off, + "%s ", mlret_string); + else + off += scnprintf(logbuf + off, logbuf_len - off, + "UNKNOWN(0x%02x) ", disposition); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + off += scnprintf(logbuf + off, logbuf_len - off, "Result: "); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + if (hb_string) + off += scnprintf(logbuf + off, logbuf_len - off, + "hostbyte=%s ", hb_string); + else + off += scnprintf(logbuf + off, logbuf_len - off, + "hostbyte=0x%02x ", host_byte(cmd->result)); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + if (db_string) + off += scnprintf(logbuf + off, logbuf_len - off, + "driverbyte=%s", db_string); + else + off += scnprintf(logbuf + off, logbuf_len - off, + "driverbyte=0x%02x", driver_byte(cmd->result)); +out_printk: + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, logbuf); + scsi_log_release_buffer(logbuf); +} +EXPORT_SYMBOL(scsi_print_result); diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index c7ed7b8..365b674 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -21,7 +21,7 @@ extern void scsi_print_sense(const struct scsi_cmnd *); extern void __scsi_print_sense(const struct scsi_device *, const char *name, const unsigned char *sense_buffer, int sense_len); -extern void scsi_print_result(struct scsi_cmnd *, const char *, int); +extern void scsi_print_result(const struct scsi_cmnd *, const char *, int); extern const char *scsi_hostbyte_string(int); extern const char *scsi_driverbyte_string(int); extern const char *scsi_mlreturn_string(int); -- cgit v0.10.2 From 2dd951ecd511756f405ae9324db87bb0159f6225 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:48 +0100 Subject: scsi: Conditionally compile in constants.c Instead of having constants.c littered with ifdef statements we should be moving dummy functions into the header and condintionally compile in constants.c if selected. And update the Kconfig description to reflect the actual size difference. Suggested-by: Christoph Hellwig Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 9c92f41..b021bcb 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -201,12 +201,12 @@ config SCSI_ENCLOSURE certain enclosure conditions to be reported and is not required. config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" + bool "Verbose SCSI error reporting (kernel size +=75K)" depends on SCSI help The error messages regarding your SCSI hardware will be easier to understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. + 75 KB. If in doubt, say Y. config SCSI_LOGGING bool "SCSI logging facility" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 447c2d2..dee160a 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -159,9 +159,9 @@ obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/ # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o - -scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ +scsi_mod-y += scsi.o hosts.o scsi_ioctl.o \ scsicam.o scsi_error.o scsi_lib.o +scsi_mod-$(CONFIG_SCSI_CONSTANTS) += constants.o scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 956fbdd..fa09d4b 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -18,8 +18,6 @@ #include #include - - /* Commands with service actions that change the command name */ #define THIRD_PARTY_COPY_OUT 0x83 #define THIRD_PARTY_COPY_IN 0x84 @@ -35,7 +33,6 @@ struct value_name_pair { const char * name; }; -#ifdef CONFIG_SCSI_CONSTANTS static const char * cdb_byte0_names[] = { /* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense", /* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL, @@ -259,26 +256,6 @@ static struct sa_name_list sa_names_arr[] = { {0, NULL, 0}, }; -#else /* ifndef CONFIG_SCSI_CONSTANTS */ -static const char *cdb_byte0_names[0]; - -static struct sa_name_list sa_names_arr[] = { - {VARIABLE_LENGTH_CMD, NULL, 0}, - {MAINTENANCE_IN, NULL, 0}, - {MAINTENANCE_OUT, NULL, 0}, - {PERSISTENT_RESERVE_IN, NULL, 0}, - {PERSISTENT_RESERVE_OUT, NULL, 0}, - {SERVICE_ACTION_IN_12, NULL, 0}, - {SERVICE_ACTION_OUT_12, NULL, 0}, - {SERVICE_ACTION_BIDIRECTIONAL, NULL, 0}, - {SERVICE_ACTION_IN_16, NULL, 0}, - {SERVICE_ACTION_OUT_16, NULL, 0}, - {THIRD_PARTY_COPY_IN, NULL, 0}, - {THIRD_PARTY_COPY_OUT, NULL, 0}, - {0, NULL, 0}, -}; -#endif /* CONFIG_SCSI_CONSTANTS */ - bool scsi_opcode_sa_name(int opcode, int service_action, const char **cdb_name, const char **sa_name) { @@ -313,8 +290,6 @@ bool scsi_opcode_sa_name(int opcode, int service_action, return true; } -#ifdef CONFIG_SCSI_CONSTANTS - struct error_info { unsigned short code12; /* 0x0302 looks better than 0x03,0x02 */ const char * text; @@ -1203,15 +1178,12 @@ static const char * const snstext[] = { "Completed", /* F: command completed sense data reported, may occur for successful command */ }; -#endif /* Get sense key string or NULL if not available */ const char * scsi_sense_key_string(unsigned char key) { -#ifdef CONFIG_SCSI_CONSTANTS if (key <= 0xE) return snstext[key]; -#endif return NULL; } EXPORT_SYMBOL(scsi_sense_key_string); @@ -1223,7 +1195,6 @@ EXPORT_SYMBOL(scsi_sense_key_string); const char * scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) { -#ifdef CONFIG_SCSI_CONSTANTS int i; unsigned short code = ((asc << 8) | ascq); @@ -1239,15 +1210,10 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) return additional2[i].str; } } -#else - *fmt = NULL; -#endif return NULL; } EXPORT_SYMBOL(scsi_extd_sense_format); -#ifdef CONFIG_SCSI_CONSTANTS - static const char * const hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", @@ -1259,17 +1225,13 @@ static const char * const driverbyte_table[]={ "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"}; -#endif - const char *scsi_hostbyte_string(int result) { const char *hb_string = NULL; -#ifdef CONFIG_SCSI_CONSTANTS int hb = host_byte(result); if (hb < ARRAY_SIZE(hostbyte_table)) hb_string = hostbyte_table[hb]; -#endif return hb_string; } EXPORT_SYMBOL(scsi_hostbyte_string); @@ -1277,17 +1239,14 @@ EXPORT_SYMBOL(scsi_hostbyte_string); const char *scsi_driverbyte_string(int result) { const char *db_string = NULL; -#ifdef CONFIG_SCSI_CONSTANTS int db = driver_byte(result); if (db < ARRAY_SIZE(driverbyte_table)) db_string = driverbyte_table[db]; -#endif return db_string; } EXPORT_SYMBOL(scsi_driverbyte_string); -#ifdef CONFIG_SCSI_CONSTANTS #define scsi_mlreturn_name(result) { result, #result } static const struct value_name_pair scsi_mlreturn_arr[] = { scsi_mlreturn_name(NEEDS_RETRY), @@ -1300,11 +1259,9 @@ static const struct value_name_pair scsi_mlreturn_arr[] = { scsi_mlreturn_name(SCSI_RETURN_NOT_HANDLED), scsi_mlreturn_name(FAST_IO_FAIL) }; -#endif const char *scsi_mlreturn_string(int result) { -#ifdef CONFIG_SCSI_CONSTANTS const struct value_name_pair *arr = scsi_mlreturn_arr; int k; @@ -1312,7 +1269,6 @@ const char *scsi_mlreturn_string(int result) if (result == arr->value) return arr->name; } -#endif return NULL; } EXPORT_SYMBOL(scsi_mlreturn_string); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index e999496e..471ab06 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -47,6 +47,7 @@ #include +#include #include #include #include diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 365b674..f8170e9 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -7,7 +7,6 @@ struct scsi_sense_hdr; #define SCSI_LOG_BUFSIZE 128 -extern bool scsi_opcode_sa_name(int, int, const char **, const char **); extern void scsi_print_command(struct scsi_cmnd *); extern size_t __scsi_format_command(char *, size_t, const unsigned char *, size_t); @@ -22,11 +21,72 @@ extern void __scsi_print_sense(const struct scsi_device *, const char *name, const unsigned char *sense_buffer, int sense_len); extern void scsi_print_result(const struct scsi_cmnd *, const char *, int); -extern const char *scsi_hostbyte_string(int); -extern const char *scsi_driverbyte_string(int); -extern const char *scsi_mlreturn_string(int); + +#ifdef CONFIG_SCSI_CONSTANTS +extern bool scsi_opcode_sa_name(int, int, const char **, const char **); extern const char *scsi_sense_key_string(unsigned char); extern const char *scsi_extd_sense_format(unsigned char, unsigned char, const char **); +extern const char *scsi_mlreturn_string(int); +extern const char *scsi_hostbyte_string(int); +extern const char *scsi_driverbyte_string(int); +#else +static inline bool +scsi_opcode_sa_name(int cmd, int sa, + const char **cdb_name, const char **sa_name) +{ + *cdb_name = NULL; + switch (cmd) { + case VARIABLE_LENGTH_CMD: + case MAINTENANCE_IN: + case MAINTENANCE_OUT: + case PERSISTENT_RESERVE_IN: + case PERSISTENT_RESERVE_OUT: + case SERVICE_ACTION_IN_12: + case SERVICE_ACTION_OUT_12: + case SERVICE_ACTION_BIDIRECTIONAL: + case SERVICE_ACTION_IN_16: + case SERVICE_ACTION_OUT_16: + case EXTENDED_COPY: + case RECEIVE_COPY_RESULTS: + *sa_name = NULL; + return true; + default: + return false; + } +} + +static inline const char * +scsi_sense_key_string(unsigned char key) +{ + return NULL; +} + +static inline const char * +scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) +{ + *fmt = NULL; + return NULL; +} + +static inline const char * +scsi_mlreturn_string(int result) +{ + return NULL; +} + +static inline const char * +scsi_hostbyte_string(int result) +{ + return NULL; +} + +static inline const char * +scsi_driverbyte_string(int result) +{ + return NULL; +} + +#endif #endif /* _SCSI_SCSI_DBG_H */ -- cgit v0.10.2 From a4a6afb477a9e724a6ff7204e4199f0c2cd97d6a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:49 +0100 Subject: scsi: Do not display buffer pointers in scsi_log_send() scsi_log_send() would display buffer pointer for higher logging levels. This is not only of questionable value but also exposes kernel pointer to userspace, which is discouraged in some setups. So drop this message altogether. Tested-by: Robert Elliott Reviewed-by: Robert Elliott Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 7f028cb..08c90a7 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -531,7 +531,7 @@ void scsi_log_send(struct scsi_cmnd *cmd) * * 3: same as 2 * - * 4: same as 3 plus dump extra junk + * 4: same as 3 */ if (unlikely(scsi_logging_level)) { level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT, @@ -540,13 +540,6 @@ void scsi_log_send(struct scsi_cmnd *cmd) scmd_printk(KERN_INFO, cmd, "Send: scmd 0x%p\n", cmd); scsi_print_command(cmd); - if (level > 3) { - printk(KERN_INFO "buffer = 0x%p, bufflen = %d," - " queuecommand 0x%p\n", - scsi_sglist(cmd), scsi_bufflen(cmd), - cmd->device->host->hostt->queuecommand); - - } } } } -- cgit v0.10.2 From 470613b462a767aa8cca1e590928fcbc55bf39e5 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 8 Jan 2015 07:43:50 +0100 Subject: scsi: do not display kernel pointer in message logs It is not good practice to display the kernel pointer in any message logs, and it doesn't display any additional information. And as we know have block-layer assigned tags we can use them to differentiate the messages. So remove any pointer references from the displayed messages. Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 9ac9eb1..4cdaffc 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -124,41 +124,37 @@ scmd_eh_abort_handler(struct work_struct *work) if (scsi_host_eh_past_deadline(sdev->host)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p eh timeout, not aborting\n", - scmd)); + "eh timeout, not aborting\n")); } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "aborting command %p\n", scmd)); + "aborting command\n")); rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd); if (rtn == SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); if (scsi_host_eh_past_deadline(sdev->host)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p eh timeout, " - "not retrying aborted " - "command\n", scmd)); + "eh timeout, not retrying " + "aborted command\n")); } else if (!scsi_noretry_cmd(scmd) && (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, - "scmd %p retry " - "aborted command\n", scmd)); + "retry aborted command\n")); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); return; } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, - "scmd %p finish " - "aborted command\n", scmd)); + "finish aborted command\n")); scsi_finish_command(scmd); return; } } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p abort %s\n", scmd, + "cmd abort %s\n", (rtn == FAST_IO_FAIL) ? "not send" : "failed")); } @@ -167,8 +163,7 @@ scmd_eh_abort_handler(struct work_struct *work) if (!scsi_eh_scmd_add(scmd, 0)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, - "scmd %p terminate " - "aborted command\n", scmd)); + "terminate aborted command\n")); set_host_byte(scmd, DID_TIME_OUT); scsi_finish_command(scmd); } @@ -194,7 +189,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) scmd->eh_eflags &= ~SCSI_EH_ABORT_SCHEDULED; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p previous abort failed\n", scmd)); + "previous abort failed\n")); BUG_ON(delayed_work_pending(&scmd->abort_work)); return FAILED; } @@ -208,8 +203,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) spin_unlock_irqrestore(shost->host_lock, flags); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p not aborting, host in recovery\n", - scmd)); + "not aborting, host in recovery\n")); return FAILED; } @@ -219,8 +213,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED; SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "scmd %p abort scheduled\n", scmd)); + scmd_printk(KERN_INFO, scmd, "abort scheduled\n")); queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100); return SUCCESS; } @@ -737,8 +730,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) struct completion *eh_action; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s scmd: %p result: %x\n", - __func__, scmd, scmd->result)); + "%s result: %x\n", __func__, scmd->result)); eh_action = scmd->device->host->eh_action; if (eh_action) @@ -1053,8 +1045,8 @@ retry: scsi_log_completion(scmd, rtn); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: scmd: %p, timeleft: %ld\n", - __func__, scmd, timeleft)); + "%s timeleft: %ld\n", + __func__, timeleft)); /* * If there is time left scsi_eh_done got called, and we will examine @@ -1193,8 +1185,7 @@ int scsi_eh_get_sense(struct list_head *work_q, continue; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "sense requested for %p result %x\n", - scmd, scmd->result)); + "sense requested, result %x\n", scmd->result)); SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense(scmd)); rtn = scsi_decide_disposition(scmd); @@ -1236,7 +1227,7 @@ retry_tur: scmd->device->eh_timeout, 0); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: scmd %p rtn %x\n", __func__, scmd, rtn)); + "%s return: %x\n", __func__, rtn)); switch (rtn) { case NEEDS_RETRY: @@ -2093,8 +2084,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q) (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: flush retry cmd: %p\n", - current->comm, scmd)); + "%s: flush retry cmd\n", + current->comm)); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); } else { /* @@ -2106,8 +2097,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q) scmd->result |= (DRIVER_TIMEOUT << 24); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: flush finish cmd: %p\n", - current->comm, scmd)); + "%s: flush finish cmd\n", + current->comm)); scsi_finish_command(scmd); } } -- cgit v0.10.2 From 200aed582d6170a2687cd69095469b663f69f16f Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:05:58 +0530 Subject: megaraid_sas: endianness related bug fixes and code optimization This patch addresses below issues: 1) Few endianness bug fixes. 2) Break the iteration after (MAX_LOGICAL_DRIVES_EXT - 1)), instead of MAX_LOGICAL_DRIVES_EXT. 3) Optimization in MFI INIT frame before firing. 4) MFI IO frame should be 256bytes aligned. Code is optimized to reduce the size of frame for fusion adapters and make the MFI frame size calculation a bit transparent and readable. Cc: Signed-off-by: Kashyap Desai Signed-off-by: Sumit Saxena Signed-off-by: Chaitra Basappa Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ff283d2..401ed67 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3547,7 +3547,6 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) int i; u32 max_cmd; u32 sge_sz; - u32 sgl_sz; u32 total_sz; u32 frame_count; struct megasas_cmd *cmd; @@ -3566,24 +3565,23 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) } /* - * Calculated the number of 64byte frames required for SGL - */ - sgl_sz = sge_sz * instance->max_num_sge; - frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE; - frame_count = 15; - - /* - * We need one extra frame for the MFI command + * For MFI controllers. + * max_num_sge = 60 + * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) + * Total 960 byte (15 MFI frame of 64 byte) + * + * Fusion adapter require only 3 extra frame. + * max_num_sge = 16 (defined as MAX_IOCTL_SGE) + * max_sge_sz = 12 byte (sizeof megasas_sge64) + * Total 192 byte (3 MFI frame of 64 byte) */ - frame_count++; - + frame_count = instance->ctrl_context ? (3 + 1) : (15 + 1); total_sz = MEGAMFI_FRAME_SIZE * frame_count; /* * Use DMA pool facility provided by PCI layer */ instance->frame_dma_pool = pci_pool_create("megasas frame pool", - instance->pdev, total_sz, 64, - 0); + instance->pdev, total_sz, 256, 0); if (!instance->frame_dma_pool) { printk(KERN_DEBUG "megasas: failed to setup frame pool\n"); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 460c6a3..7cae1c2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -172,6 +172,7 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; struct MR_FW_RAID_MAP *pFwRaidMap = NULL; int i; + u16 ld_count; struct MR_DRV_RAID_MAP_ALL *drv_map = @@ -191,9 +192,10 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) fw_map_old = (struct MR_FW_RAID_MAP_ALL *) fusion->ld_map[(instance->map_id & 1)]; pFwRaidMap = &fw_map_old->raidMap; + ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount); #if VD_EXT_DEBUG - for (i = 0; i < le16_to_cpu(pFwRaidMap->ldCount); i++) { + for (i = 0; i < ld_count; i++) { dev_dbg(&instance->pdev->dev, "(%d) :Index 0x%x " "Target Id 0x%x Seq Num 0x%x Size 0/%llx\n", instance->unique_id, i, @@ -205,12 +207,12 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) memset(drv_map, 0, fusion->drv_map_sz); pDrvRaidMap->totalSize = pFwRaidMap->totalSize; - pDrvRaidMap->ldCount = (__le16)pFwRaidMap->ldCount; + pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) pDrvRaidMap->ldTgtIdToLd[i] = (u8)pFwRaidMap->ldTgtIdToLd[i]; - for (i = 0; i < le16_to_cpu(pDrvRaidMap->ldCount); i++) { + for (i = 0; i < ld_count; i++) { pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; #if VD_EXT_DEBUG dev_dbg(&instance->pdev->dev, @@ -252,7 +254,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) struct LD_LOAD_BALANCE_INFO *lbInfo; PLD_SPAN_INFO ldSpanInfo; struct MR_LD_RAID *raid; - int ldCount, num_lds; + u16 ldCount, num_lds; u16 ld; u32 expected_size; @@ -356,7 +358,7 @@ static int getSpanInfo(struct MR_DRV_RAID_MAP_ALL *map, for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { ld = MR_TargetIdToLdGet(ldCount, map); - if (ld >= MAX_LOGICAL_DRIVES_EXT) + if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) continue; raid = MR_LdRaidGet(ld, map); dev_dbg(&instance->pdev->dev, "LD %x: span_depth=%x\n", @@ -1157,7 +1159,7 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { ld = MR_TargetIdToLdGet(ldCount, map); - if (ld >= MAX_LOGICAL_DRIVES_EXT) + if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) continue; raid = MR_LdRaidGet(ld, map); for (element = 0; element < MAX_QUAD_DEPTH; element++) { diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 71557f6..b5362c1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -698,12 +698,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) cpu_to_le32(lower_32_bits(ioc_init_handle)); init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST)); - req_desc.Words = 0; + req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr)); + req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr)); req_desc.MFAIo.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_MFA << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - cpu_to_le32s((u32 *)&req_desc.MFAIo); - req_desc.Words |= cpu_to_le64(cmd->frame_phys_addr); + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); /* * disable the intr before firing the init frame diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 5ab7dae..56e6db2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -306,14 +306,9 @@ struct MPI2_RAID_SCSI_IO_REQUEST { * MPT RAID MFA IO Descriptor. */ struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR { -#if defined(__BIG_ENDIAN_BITFIELD) - u32 MessageAddress1:24; /* bits 31:8*/ - u32 RequestFlags:8; -#else u32 RequestFlags:8; - u32 MessageAddress1:24; /* bits 31:8*/ -#endif - u32 MessageAddress2; /* bits 61:32 */ + u32 MessageAddress1:24; + u32 MessageAddress2; }; /* Default Request Descriptor */ -- cgit v0.10.2 From 7497cde883b184ead109652f236df98d78090a90 Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:03 +0530 Subject: megaraid_sas: add support for secure JBOD This patch adds support for Secure Encrypting Drives (SED) in JBOD mode: 1) If the firmware supports SED JBOD, all non read/write commands to JBODs will be sent via firmware path, and read/write commands to JBODs will be sent via fastpath. 2) If the firmware does not support SED JBOD, driver will fall back to the old design, i.e. send all JBOD I/O via fastpath. Signed-off-by: Sumit Saxena Signed-off-by: Chaitra Basappa Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 0d44d91..b8b378d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -969,7 +969,20 @@ struct megasas_ctrl_info { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:25; + u32 reserved:12; + u32 discardCacheDuringLDDelete:1; + u32 supportSecurityonJBOD:1; + u32 supportCacheBypassModes:1; + u32 supportDisableSESMonitoring:1; + u32 supportForceFlash:1; + u32 supportNVDRAM:1; + u32 supportDrvActivityLEDSetting:1; + u32 supportAllowedOpsforDrvRemoval:1; + u32 supportHOQRebuild:1; + u32 supportForceTo512e:1; + u32 supportNVCacheErase:1; + u32 supportDebugQueue:1; + u32 supportSwZone:1; u32 supportCrashDump:1; u32 supportMaxExtLDs:1; u32 supportT10RebuildAssist:1; @@ -981,9 +994,22 @@ struct megasas_ctrl_info { u32 supportThermalPollInterval:1; u32 supportDisableImmediateIO:1; u32 supportT10RebuildAssist:1; - u32 supportMaxExtLDs:1; - u32 supportCrashDump:1; - u32 reserved:25; + u32 supportMaxExtLDs:1; + u32 supportCrashDump:1; + u32 supportSwZone:1; + u32 supportDebugQueue:1; + u32 supportNVCacheErase:1; + u32 supportForceTo512e:1; + u32 supportHOQRebuild:1; + u32 supportAllowedOpsforDrvRemoval:1; + u32 supportDrvActivityLEDSetting:1; + u32 supportNVDRAM:1; + u32 supportForceFlash:1; + u32 supportDisableSESMonitoring:1; + u32 supportCacheBypassModes:1; + u32 supportSecurityonJBOD:1; + u32 discardCacheDuringLDDelete:1; + u32 reserved:12; #endif } adapterOperations3; @@ -1022,6 +1048,13 @@ enum MR_MFI_MPT_PTHR_FLAGS { MFI_MPT_ATTACHED = 2, }; +enum MR_SCSI_CMD_TYPE { + READ_WRITE_LDIO = 0, + NON_READ_WRITE_LDIO = 1, + READ_WRITE_SYSPDIO = 2, + NON_READ_WRITE_SYSPDIO = 3, +}; + /* Frame Type */ #define IO_FRAME 0 #define PTHRU_FRAME 1 @@ -1194,19 +1227,23 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:27; + u32 reserved:25; + u32 security_protocol_cmds_fw:1; + u32 support_core_affinity:1; u32 support_ndrive_r1_lb:1; u32 support_max_255lds:1; - u32 reserved1:1; + u32 support_fastpath_wb:1; u32 support_additional_msix:1; u32 support_fp_remote_lun:1; #else u32 support_fp_remote_lun:1; u32 support_additional_msix:1; - u32 reserved1:1; + u32 support_fastpath_wb:1; u32 support_max_255lds:1; u32 support_ndrive_r1_lb:1; - u32 reserved:27; + u32 support_core_affinity:1; + u32 security_protocol_cmds_fw:1; + u32 reserved:25; #endif } mfi_capabilities; u32 reg; @@ -1638,13 +1675,14 @@ struct megasas_instance { u32 crash_dump_fw_support; u32 crash_dump_drv_support; u32 crash_dump_app_support; + u32 secure_jbod_support; spinlock_t crashdump_lock; struct megasas_register_set __iomem *reg_set; u32 *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY]; struct megasas_pd_list pd_list[MEGASAS_MAX_PD]; struct megasas_pd_list local_pd_list[MEGASAS_MAX_PD]; - u8 ld_ids[MEGASAS_MAX_LD_IDS]; + u8 ld_ids[MEGASAS_MAX_LD_IDS]; s8 init_id; u16 max_num_sge; @@ -1946,5 +1984,6 @@ void __megasas_return_cmd(struct megasas_instance *instance, void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion); +int megasas_cmd_type(struct scsi_cmnd *cmd); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 401ed67..9f37dde 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1417,16 +1417,15 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, } /** - * megasas_is_ldio - Checks if the cmd is for logical drive + * megasas_cmd_type - Checks if the cmd is for logical drive/sysPD + * and whether it's RW or non RW * @scmd: SCSI command * - * Called by megasas_queue_command to find out if the command to be queued - * is a logical drive command */ -inline int megasas_is_ldio(struct scsi_cmnd *cmd) +inline int megasas_cmd_type(struct scsi_cmnd *cmd) { - if (!MEGASAS_IS_LOGICAL(cmd)) - return 0; + int ret; + switch (cmd->cmnd[0]) { case READ_10: case WRITE_10: @@ -1436,10 +1435,14 @@ inline int megasas_is_ldio(struct scsi_cmnd *cmd) case WRITE_6: case READ_16: case WRITE_16: - return 1; + ret = (MEGASAS_IS_LOGICAL(cmd)) ? + READ_WRITE_LDIO : READ_WRITE_SYSPDIO; + break; default: - return 0; + ret = (MEGASAS_IS_LOGICAL(cmd)) ? + NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO; } + return ret; } /** @@ -1471,7 +1474,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance) if(!cmd->scmd) continue; printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); - if (megasas_is_ldio(cmd->scmd)){ + if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) { ldio = (struct megasas_io_frame *)cmd->frame; mfi_sgl = &ldio->sgl; sgcount = ldio->sge_count; @@ -1531,7 +1534,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance, /* * Logical drive command */ - if (megasas_is_ldio(scmd)) + if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) frame_count = megasas_build_ldio(instance, scmd, cmd); else frame_count = megasas_build_dcdb(instance, scmd, cmd); @@ -4629,6 +4632,11 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->crash_dump_h); instance->crash_dump_buf = NULL; } + + instance->secure_jbod_support = + ctrl_info->adapterOperations3.supportSecurityonJBOD; + if (instance->secure_jbod_support) + dev_info(&instance->pdev->dev, "Firmware supports Secure JBOD\n"); instance->max_sectors_per_req = instance->max_num_sge * PAGE_SIZE / 512; if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index b5362c1..af5ab9e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -63,7 +63,6 @@ extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance extern void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status); -int megasas_is_ldio(struct scsi_cmnd *cmd); int wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, int seconds); @@ -196,6 +195,7 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, cmd->scmd = NULL; cmd->sync_cmd_idx = (u32)ULONG_MAX; + memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); list_add(&cmd->list, (&fusion->cmd_pool)->next); spin_unlock_irqrestore(&fusion->mpt_pool_lock, flags); @@ -689,6 +689,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) = 1; init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb = 1; + init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw + = 1; /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -1284,6 +1286,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr = (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; + memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); } } @@ -1657,6 +1660,8 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, u32 device_id; struct MPI2_RAID_SCSI_IO_REQUEST *io_request; u16 pd_index = 0; + u16 os_timeout_value; + u16 timeout_limit; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; struct fusion_context *fusion = instance->ctrl_context; u8 span, physArm; @@ -1673,44 +1678,48 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); - - /* Check if this is a system PD I/O */ if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS && instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { - io_request->Function = 0; if (fusion->fast_path_io) io_request->DevHandle = local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; - io_request->RaidContext.timeoutValue = - local_map_ptr->raidMap.fpPdIoTimeoutSec; - io_request->RaidContext.regLockFlags = 0; - io_request->RaidContext.regLockRowLBA = 0; - io_request->RaidContext.regLockLength = 0; io_request->RaidContext.RAIDFlags = - MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << - MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - io_request->IoFlags |= cpu_to_le16( - MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); - cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - cmd->request_desc->SCSIIO.DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD + << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; + cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ? smp_processor_id() % instance->msix_vectors : 0; - /* - * If the command is for the tape device, set the - * FP timeout to the os layer timeout value. - */ - if (scmd->device->type == TYPE_TAPE) { - if ((scmd->request->timeout / HZ) > 0xFFFF) - io_request->RaidContext.timeoutValue = - 0xFFFF; - else - io_request->RaidContext.timeoutValue = - scmd->request->timeout / HZ; + os_timeout_value = scmd->request->timeout / HZ; + + if (instance->secure_jbod_support && + (megasas_cmd_type(scmd) == NON_READ_WRITE_SYSPDIO)) { + /* system pd firmware path */ + io_request->Function = + MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + io_request->RaidContext.timeoutValue = + cpu_to_le16(os_timeout_value); + } else { + /* system pd Fast Path */ + io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + io_request->RaidContext.regLockFlags = 0; + io_request->RaidContext.regLockRowLBA = 0; + io_request->RaidContext.regLockLength = 0; + timeout_limit = (scmd->device->type == TYPE_DISK) ? + 255 : 0xFFFF; + io_request->RaidContext.timeoutValue = + cpu_to_le16((os_timeout_value > timeout_limit) ? + timeout_limit : os_timeout_value); + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + io_request->IoFlags |= + cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); + + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); } } else { if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS) @@ -1810,7 +1819,7 @@ megasas_build_io_fusion(struct megasas_instance *instance, */ io_request->IoFlags = cpu_to_le16(scp->cmd_len); - if (megasas_is_ldio(scp)) + if (megasas_cmd_type(scp) == READ_WRITE_LDIO) megasas_build_ldio_fusion(instance, scp, cmd); else megasas_build_dcdb_fusion(instance, scp, cmd); -- cgit v0.10.2 From ab2f0608e16d64a23a2dcc8d83b966a0e0a281f3 Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:08 +0530 Subject: megaraid_sas: fix the problem of non-existing VD exposed to host This patch will address the issue of SCSI device created at OS level for non existing VD. ldTgtIdtoLd[] array has size 256 for Extended VD firmware and 128 for legacy firmware. Accessing indices beyond array size (OS will send TUR, INQUIRY.. commands upto device index 255), may return valid LD value and that particular SCSI command will be SUCCESS and creating SCSI device for non existing target(VD). For legacy firmware (64 VD firmware), invalidates LD (by setting LD value to 0xff) in LdTgtIdtoLd[] array for device index beyond 127, so that invalid LD(0xff) value should be returned beyond device index beyond 127. Cc: Signed-off-by: Kashyap Desai Signed-off-by: Sumit Saxena Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 7cae1c2..4f72287 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -212,6 +212,9 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) pDrvRaidMap->ldTgtIdToLd[i] = (u8)pFwRaidMap->ldTgtIdToLd[i]; + for (i = (MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS); + i < MAX_LOGICAL_DRIVES_EXT; i++) + pDrvRaidMap->ldTgtIdToLd[i] = 0xff; for (i = 0; i < ld_count; i++) { pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; #if VD_EXT_DEBUG diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index af5ab9e..7b23d34 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1725,9 +1725,19 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS) goto NonFastPath; + /* + * For older firmware, Driver should not access ldTgtIdToLd + * beyond index 127 and for Extended VD firmware, ldTgtIdToLd + * should not go beyond 255. + */ + + if ((!fusion->fast_path_io) || + (device_id >= instance->fw_supported_vd_count)) + goto NonFastPath; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); - if ((ld >= instance->fw_supported_vd_count) || - (!fusion->fast_path_io)) + + if (ld >= instance->fw_supported_vd_count) goto NonFastPath; raid = MR_LdRaidGet(ld, local_map_ptr); -- cgit v0.10.2 From c2ced1719a1b903350955a511e1666e6d05a7f5b Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:13 +0530 Subject: megaraid_sas: disable interrupt_mask before enabling hardware interrupts Update driver "mask_interrupts" before enable/disable hardware interrupt in order to avoid missing interrupts because of "mask_interrupts" still set to 1 and hardware interrupts are enabled. Cc: Signed-off-by: Sumit Saxena Signed-off-by: Chaitra Basappa Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 7b23d34..075c99e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -102,6 +102,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; regs = instance->reg_set; + + instance->mask_interrupts = 0; /* For Thunderbolt/Invader also clear intr on enable */ writel(~0, ®s->outbound_intr_status); readl(®s->outbound_intr_status); @@ -110,7 +112,6 @@ megasas_enable_intr_fusion(struct megasas_instance *instance) /* Dummy readl to force pci flush */ readl(®s->outbound_intr_mask); - instance->mask_interrupts = 0; } /** -- cgit v0.10.2 From c8dd61eff2780c481fcf919c1572e16e397c714e Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:18 +0530 Subject: megaraid_sas: complete outstanding IOCTLs before killing adapter Driver calls megasas_complete_cmd() to call wake_up() for each MFI frame that was issued through the ioctl() interface prior to the kill adapter. This ensures userspace ioctl() system calls issued just before a kill adapter don't get stuck in wait state and IOCTLs are returned to the application. Cc: Signed-off-by: Sumit Saxena Signed-off-by: Chaitra Basappa Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 9f37dde..d4e9c4e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1692,22 +1692,66 @@ static int megasas_slave_alloc(struct scsi_device *sdev) return 0; } +/* +* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a +* kill adapter +* @instance: Adapter soft state +* +*/ +void megasas_complete_outstanding_ioctls(struct megasas_instance *instance) +{ + int i; + struct megasas_cmd *cmd_mfi; + struct megasas_cmd_fusion *cmd_fusion; + struct fusion_context *fusion = instance->ctrl_context; + + /* Find all outstanding ioctls */ + if (fusion) { + for (i = 0; i < instance->max_fw_cmds; i++) { + cmd_fusion = fusion->cmd_list[i]; + if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) { + cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; + if (cmd_mfi->sync_cmd && + cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) + megasas_complete_cmd(instance, + cmd_mfi, DID_OK); + } + } + } else { + for (i = 0; i < instance->max_fw_cmds; i++) { + cmd_mfi = instance->cmd_list[i]; + if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd != + MFI_CMD_ABORT) + megasas_complete_cmd(instance, cmd_mfi, DID_OK); + } + } +} + + void megaraid_sas_kill_hba(struct megasas_instance *instance) { + /* Set critical error to block I/O & ioctls in case caller didn't */ + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + /* Wait 1 second to ensure IO or ioctls in build have posted */ + msleep(1000); if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - writel(MFI_STOP_ADP, &instance->reg_set->doorbell); + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + writel(MFI_STOP_ADP, + &instance->reg_set->doorbell); /* Flush */ readl(&instance->reg_set->doorbell); if (instance->mpio && instance->requestorId) memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); } else { - writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); + writel(MFI_STOP_ADP, + &instance->reg_set->inbound_doorbell); } + /* Complete outstanding ioctls when adapter is killed */ + megasas_complete_outstanding_ioctls(instance); } /** @@ -3031,10 +3075,9 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) "was tried multiple times during reset." "Shutting down the HBA\n", cmd, cmd->scmd, cmd->sync_cmd); + instance->instancet->disable_intr(instance); + atomic_set(&instance->fw_reset_no_pci_access, 1); megaraid_sas_kill_hba(instance); - - instance->adprecovery = - MEGASAS_HW_CRITICAL_ERROR; return; } } @@ -3168,8 +3211,8 @@ process_fw_state_change_wq(struct work_struct *work) if (megasas_transition_to_ready(instance, 1)) { printk(KERN_NOTICE "megaraid_sas:adapter not ready\n"); + atomic_set(&instance->fw_reset_no_pci_access, 1); megaraid_sas_kill_hba(instance); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; return ; } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 075c99e..df280b1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2631,7 +2631,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) instance->host->host_no); megaraid_sas_kill_hba(instance); instance->skip_heartbeat_timer_del = 1; - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; retval = FAILED; goto out; } @@ -2827,8 +2826,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) dev_info(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); - instance->adprecovery = - MEGASAS_HW_CRITICAL_ERROR; megaraid_sas_kill_hba(instance); retval = FAILED; } @@ -2877,7 +2874,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) "adapter scsi%d.\n", instance->host->host_no); megaraid_sas_kill_hba(instance); instance->skip_heartbeat_timer_del = 1; - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; retval = FAILED; } else { /* For VF: Restart HB timer if we didn't OCR */ -- cgit v0.10.2 From ae09a6c1fd421887fa4885adb7c55ccc8074c441 Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:23 +0530 Subject: megaraid_sas: reserve commands for IOCTLs and internal DCMDs 1) For fusion adapters, limit reserved frames for non SCSI commands to 8 (3 for parallel IOCTLs + 5 for driver's internal DCMDs). Earlier reserved commands for non SCSI IO frames was set to 32, so with this implementation, increased per controller "can_queue". Behavior of MFI controllers will remain unchanged. 2) Optimize the code related to per controller's 'can_queue' setting. Signed-off-by: Sumit Saxena Signed-off-by: Chaitra Basappa Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index b8b378d..793b2b3 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1082,6 +1082,8 @@ enum MR_SCSI_CMD_TYPE { */ #define MEGASAS_INT_CMDS 32 #define MEGASAS_SKINNY_INT_CMDS 5 +#define MEGASAS_FUSION_INTERNAL_CMDS 5 +#define MEGASAS_FUSION_IOCTL_CMDS 3 #define MEGASAS_MAX_MSIX_QUEUES 128 /* @@ -1687,9 +1689,8 @@ struct megasas_instance { u16 max_num_sge; u16 max_fw_cmds; - /* For Fusion its num IOCTL cmds, for others MFI based its - max_fw_cmds */ u16 max_mfi_cmds; + u16 max_scsi_cmds; u32 max_sectors_per_req; struct megasas_aen_event *ev; @@ -1765,7 +1766,7 @@ struct megasas_instance { u8 requestorId; char PlasmaFW111; char mpio; - int throttlequeuedepth; + u16 throttlequeuedepth; u8 mask_interrupts; u8 is_imr; }; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d4e9c4e..bf31dde 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -78,7 +78,7 @@ static int allow_vf_ioctls; module_param(allow_vf_ioctls, int, S_IRUGO); MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0"); -static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; +static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; module_param(throttlequeuedepth, int, S_IRUGO); MODULE_PARM_DESC(throttlequeuedepth, "Adapter queue depth when throttled due to I/O timeout. Default: 16"); @@ -1764,6 +1764,7 @@ void megasas_check_and_restore_queue_depth(struct megasas_instance *instance) { unsigned long flags; + if (instance->flag & MEGASAS_FW_BUSY && time_after(jiffies, instance->last_time + 5 * HZ) && atomic_read(&instance->fw_outstanding) < @@ -1771,13 +1772,8 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance) spin_lock_irqsave(instance->host->host_lock, flags); instance->flag &= ~MEGASAS_FW_BUSY; - if (instance->is_imr) { - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; + instance->host->can_queue = instance->max_scsi_cmds; spin_unlock_irqrestore(instance->host->host_lock, flags); } } @@ -4685,23 +4681,38 @@ static int megasas_init_fw(struct megasas_instance *instance) if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) instance->max_sectors_per_req = tmp_sectors; - /* Check for valid throttlequeuedepth module parameter */ - if (instance->is_imr) { - if (throttlequeuedepth > (instance->max_fw_cmds - - MEGASAS_SKINNY_INT_CMDS)) - instance->throttlequeuedepth = - MEGASAS_THROTTLE_QUEUE_DEPTH; - else - instance->throttlequeuedepth = throttlequeuedepth; + /* + * 1. For fusion adapters, 3 commands for IOCTL and 5 commands + * for driver's internal DCMDs. + * 2. For MFI skinny adapters, 5 commands for IOCTL + driver's + * internal DCMDs. + * 3. For rest of MFI adapters, 27 commands reserved for IOCTLs + * and 5 commands for drivers's internal DCMD. + */ + if (instance->ctrl_context) { + instance->max_scsi_cmds = instance->max_fw_cmds - + (MEGASAS_FUSION_INTERNAL_CMDS + + MEGASAS_FUSION_IOCTL_CMDS); + sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS); + } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + instance->max_scsi_cmds = instance->max_fw_cmds - + MEGASAS_SKINNY_INT_CMDS; + sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS); } else { - if (throttlequeuedepth > (instance->max_fw_cmds - - MEGASAS_INT_CMDS)) - instance->throttlequeuedepth = - MEGASAS_THROTTLE_QUEUE_DEPTH; - else - instance->throttlequeuedepth = throttlequeuedepth; + instance->max_scsi_cmds = instance->max_fw_cmds - + MEGASAS_INT_CMDS; + sema_init(&instance->ioctl_sem, (MEGASAS_INT_CMDS - 5)); } + /* Check for valid throttlequeuedepth module parameter */ + if (throttlequeuedepth && + throttlequeuedepth <= instance->max_scsi_cmds) + instance->throttlequeuedepth = throttlequeuedepth; + else + instance->throttlequeuedepth = + MEGASAS_THROTTLE_QUEUE_DEPTH; + /* * Setup tasklet for cmd completion */ @@ -4996,12 +5007,7 @@ static int megasas_io_attach(struct megasas_instance *instance) */ host->irq = instance->pdev->irq; host->unique_id = instance->unique_id; - if (instance->is_imr) { - host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; + host->can_queue = instance->max_scsi_cmds; host->this_id = instance->init_id; host->sg_tablesize = instance->max_num_sge; @@ -5264,12 +5270,10 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->init_id = MEGASAS_DEFAULT_INIT_ID; instance->ctrl_info = NULL; + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) instance->flag_ieee = 1; - sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS); - } else - sema_init(&instance->ioctl_sem, (MEGASAS_INT_CMDS - 5)); megasas_dbg_lvl = 0; instance->flag = 0; @@ -6264,9 +6268,6 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) goto out_kfree_ioc; } - /* - * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds - */ if (down_interruptible(&instance->ioctl_sem)) { error = -ERESTARTSYS; goto out_kfree_ioc; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index df280b1..675b5e7 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1019,8 +1019,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) * does not exceed max cmds that the FW can support */ instance->max_fw_cmds = instance->max_fw_cmds-1; - /* Only internal cmds (DCMD) need to have MFI frames */ - instance->max_mfi_cmds = MEGASAS_INT_CMDS; + + /* + * Only Driver's internal DCMDs and IOCTL DCMDs needs to have MFI frames + */ + instance->max_mfi_cmds = + MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS; max_cmd = instance->max_fw_cmds; -- cgit v0.10.2 From 1aecbc8d679e7eb61fa955eb97874b090c08a89d Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:28 +0530 Subject: megaraid_sas: remove redundant memset call struct fusion_context *fusion is already memset to '0', so remove a redundant call to memmset "fusion->load_balance_info" to '0'. Signed-off-by: Chaitra Basappa Signed-off-by: Sumit Saxena Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index bf31dde..890637f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5185,8 +5185,6 @@ static int megasas_probe_one(struct pci_dev *pdev, ((1 << PAGE_SHIFT) << instance->ctrl_context_pages)); INIT_LIST_HEAD(&fusion->cmd_pool); spin_lock_init(&fusion->mpt_pool_lock); - memset(fusion->load_balance_info, 0, - sizeof(struct LD_LOAD_BALANCE_INFO) * MAX_LOGICAL_DRIVES_EXT); } break; default: /* For all other supported controllers */ -- cgit v0.10.2 From 0128d5cf8f85c93b3c70ff03299c2839f3e6d21e Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@avagotech.com" Date: Mon, 5 Jan 2015 20:06:28 +0530 Subject: megaraid_sas: driver version update Update megaraid_sas driver version. Signed-off-by: Sumit Saxena Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 793b2b3..14e5c7c 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -35,7 +35,7 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "06.805.06.01-rc1" +#define MEGASAS_VERSION "06.806.08.00-rc1" /* * Device IDs -- cgit v0.10.2 From c4eaa62fdac3cdbf358e19625477ffc9a15d4c7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:40:23 +0100 Subject: ALSA: ali5451: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index af89e42..4cd2210 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1873,7 +1873,6 @@ static int snd_ali_mixer(struct snd_ali *codec) #ifdef CONFIG_PM_SLEEP static int ali_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ali *chip = card->private_data; struct snd_ali_image *im; @@ -1914,16 +1913,11 @@ static int ali_suspend(struct device *dev) outl(0xffffffff, ALI_REG(chip, ALI_STOP)); spin_unlock_irq(&chip->reg_lock); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int ali_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ali *chip = card->private_data; struct snd_ali_image *im; @@ -1933,15 +1927,6 @@ static int ali_resume(struct device *dev) if (!im) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - spin_lock_irq(&chip->reg_lock); for (i = 0; i < ALI_CHANNELS; i++) { -- cgit v0.10.2 From 08aa0e34305059a80f38e039f085fe91a7587cca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:43:46 +0100 Subject: ALSA: als300: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 7bb6ac5..bd01113 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -728,35 +728,20 @@ static int snd_als300_create(struct snd_card *card, #ifdef CONFIG_PM_SLEEP static int snd_als300_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_als300 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_als300_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_als300 *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_als300_init(chip); snd_ac97_resume(chip->ac97); -- cgit v0.10.2 From dc3b10eb64edd977fb5173f72fc66cc8687e61be Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:44:01 +0100 Subject: ALSA: als4000: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index d3e6424..9460852 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -988,7 +988,6 @@ static void snd_card_als4000_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_als4000_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_card_als4000 *acard = card->private_data; struct snd_sb *chip = acard->chip; @@ -997,29 +996,15 @@ static int snd_als4000_suspend(struct device *dev) snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_als4000_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_card_als4000 *acard = card->private_data; struct snd_sb *chip = acard->chip; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_als4000_configure(chip); snd_sbdsp_reset(chip); snd_sbmixer_resume(chip); -- cgit v0.10.2 From 94af14691d3783629f5d186acfb1f700fb68ff03 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:44:18 +0100 Subject: ALSA: atiixp: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 9c1c445..f41de00 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1474,7 +1474,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, */ static int snd_atiixp_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp *chip = card->private_data; int i; @@ -1492,29 +1491,15 @@ static int snd_atiixp_suspend(struct device *dev) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); snd_atiixp_chip_stop(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_atiixp_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); -- cgit v0.10.2 From 2b5d0891ba8555c8edc21098715324d90a4d5de0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:44:30 +0100 Subject: ALSA: atiixp-modem: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index b2f63e0..7cf4197 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1120,7 +1120,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) */ static int snd_atiixp_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp_modem *chip = card->private_data; int i; @@ -1132,29 +1131,15 @@ static int snd_atiixp_suspend(struct device *dev) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); snd_atiixp_chip_stop(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_atiixp_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp_modem *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); -- cgit v0.10.2 From 3a7ed36909a6c4aee677100ff1a45869a5873a12 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:44:47 +0100 Subject: ALSA: azt3328: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index fdbb9c0..bbacc75 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2694,7 +2694,6 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip) static int snd_azf3328_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_azf3328 *chip = card->private_data; u16 *saved_regs_ctrl_u16; @@ -2720,29 +2719,15 @@ snd_azf3328_suspend(struct device *dev) ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); snd_azf3328_suspend_regs(chip, chip->opl3_io, ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_azf3328_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); const struct snd_azf3328 *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io, ARRAY_SIZE(chip->saved_regs_game)); snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io, -- cgit v0.10.2 From 11afa6426c4ff69cc58f0b91e85cf17f31c0a442 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:44:59 +0100 Subject: ALSA: ca0106: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 96af339..dd75b75 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1910,7 +1910,6 @@ static void snd_ca0106_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_ca0106_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ca0106 *chip = card->private_data; int i; @@ -1923,30 +1922,15 @@ static int snd_ca0106_suspend(struct device *dev) snd_ca0106_mixer_suspend(chip); ca0106_stop_chip(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_ca0106_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ca0106 *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - snd_card_disconnect(card); - return -EIO; - } - - pci_set_master(pci); - ca0106_init_chip(chip, 1); if (chip->details->ac97) -- cgit v0.10.2 From 5762fdb5f9b18a5bf8cdbdfbc0c735ad1d88a478 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:45:12 +0100 Subject: ALSA: cmipci: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 85ed403..63d2c82 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -3347,7 +3347,6 @@ static unsigned char saved_mixers[] = { static int snd_cmipci_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cmipci *cm = card->private_data; int i; @@ -3366,29 +3365,15 @@ static int snd_cmipci_suspend(struct device *dev) /* disable ints */ snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_cmipci_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cmipci *cm = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - /* reset / initialize to a sane state */ snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); snd_cmipci_ch_reset(cm, CM_CH_PLAY); -- cgit v0.10.2 From faab5223930114b0a33f8c712c14799967342e8c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:45:22 +0100 Subject: ALSA: cs4281: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 4c49b5c..80bb1d1 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -2008,7 +2008,6 @@ static int saved_regs[SUSPEND_REGISTERS] = { static int cs4281_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs4281 *chip = card->private_data; u32 ulCLK; @@ -2047,30 +2046,16 @@ static int cs4281_suspend(struct device *dev) ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1); ulCLK &= ~CLKCR1_CKRA; snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int cs4281_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs4281 *chip = card->private_data; unsigned int i; u32 ulCLK; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1); ulCLK |= CLKCR1_CKRA; snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK); -- cgit v0.10.2 From 319184680d7ecbea5718fa1ab73105ef8abb478f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:45:32 +0100 Subject: ALSA: cs46xx: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 32b44f2..ba97aba 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3804,7 +3804,6 @@ static unsigned int saved_regs[] = { static int snd_cs46xx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_cs46xx *chip = card->private_data; int i, amp_saved; @@ -3829,16 +3828,11 @@ static int snd_cs46xx_suspend(struct device *dev) /* disable CLKRUN */ chip->active_ctrl(chip, -chip->amplifier); chip->amplifier = amp_saved; /* restore the status */ - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_cs46xx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_cs46xx *chip = card->private_data; int amp_saved; @@ -3847,15 +3841,6 @@ static int snd_cs46xx_resume(struct device *dev) #endif unsigned int tmp; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - amp_saved = chip->amplifier; chip->amplifier = 0; chip->active_ctrl(chip, 1); /* force to on */ -- cgit v0.10.2 From b8375122b59b1362e94ccd8502cff3cfef4cf168 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:45:43 +0100 Subject: ALSA: cs5535audio: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 34cc600..06ac5d8 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -57,7 +57,6 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au) static int snd_cs5535audio_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs5535audio *cs5535au = card->private_data; int i; @@ -72,34 +71,17 @@ static int snd_cs5535audio_suspend(struct device *dev) } /* save important regs, then disable aclink in hw */ snd_cs5535audio_stop_hardware(cs5535au); - - if (pci_save_state(pci)) { - dev_err(dev, "pci_save_state failed!\n"); - return -EIO; - } - pci_disable_device(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_cs5535audio_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs5535audio *cs5535au = card->private_data; u32 tmp; int timeout; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - /* set LNK_WRM_RST to reset AC link */ cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST); -- cgit v0.10.2 From 7247aabd5ace16677681f815cc34f84ef0278261 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:45:55 +0100 Subject: ALSA: ctxfi: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index b425aa8..f16bec1 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -2099,20 +2099,11 @@ static int hw_suspend(struct hw *hw) pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0); } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); - return 0; } static int hw_resume(struct hw *hw, struct card_conf *info) { - struct pci_dev *pci = hw->pci; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - /* Re-initialize card hardware. */ return hw_card_init(hw, info); } diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 253899d..613671d 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2209,24 +2209,12 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) #ifdef CONFIG_PM_SLEEP static int hw_suspend(struct hw *hw) { - struct pci_dev *pci = hw->pci; - hw_card_stop(hw); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); - return 0; } static int hw_resume(struct hw *hw, struct card_conf *info) { - struct pci_dev *pci = hw->pci; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - /* Re-initialize card hardware. */ return hw_card_init(hw, info); } -- cgit v0.10.2 From f84edab4b59bd004853224703acb03628af6c2ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:46:07 +0100 Subject: ALSA: echoaudio: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 21228ad..5896084 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2162,7 +2162,6 @@ ctl_error: static int snd_echo_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct echoaudio *chip = dev_get_drvdata(dev); snd_pcm_suspend_all(chip->analog_pcm); @@ -2188,9 +2187,6 @@ static int snd_echo_suspend(struct device *dev) chip->dsp_code = NULL; free_irq(chip->irq, chip); chip->irq = -1; - pci_save_state(pci); - pci_disable_device(pci); - return 0; } @@ -2204,7 +2200,6 @@ static int snd_echo_resume(struct device *dev) u32 pipe_alloc_mask; int err; - pci_restore_state(pci); commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); if (commpage_bak == NULL) return -ENOMEM; -- cgit v0.10.2 From 1aa1813b2c29b25de798dc465dffd56124f94e60 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:46:58 +0100 Subject: ALSA: emu10k1: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4c17163..1d262ba 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -210,7 +210,6 @@ static void snd_card_emu10k1_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_emu10k1_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_emu10k1 *emu = card->private_data; @@ -232,28 +231,14 @@ static int snd_emu10k1_suspend(struct device *dev) snd_p16v_suspend(emu); snd_emu10k1_done(emu); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_emu10k1_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_emu10k1 *emu = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_emu10k1_resume_init(emu); snd_emu10k1_efx_resume(emu); snd_ac97_resume(emu->ac97); -- cgit v0.10.2 From 943cf2839637231bdb2710753b457651ea1b7204 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:47:10 +0100 Subject: ALSA: ens137x: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index d94cb3c..1badd91 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -2049,7 +2049,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) #ifdef CONFIG_PM_SLEEP static int snd_ensoniq_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct ensoniq *ensoniq = card->private_data; @@ -2070,28 +2069,14 @@ static int snd_ensoniq_suspend(struct device *dev) udelay(100); snd_ak4531_suspend(ensoniq->u.es1370.ak4531); #endif - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_ensoniq_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct ensoniq *ensoniq = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_ensoniq_chip_init(ensoniq); #ifdef CHIP1371 -- cgit v0.10.2 From 8c3698219119612c239e387e423aa9d90040bc64 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:47:21 +0100 Subject: ALSA: es1938: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 0fc46eb..a01454b 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1454,7 +1454,6 @@ static unsigned char saved_regs[SAVED_REG_SIZE+1] = { static int es1938_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1938 *chip = card->private_data; unsigned char *s, *d; @@ -1471,9 +1470,6 @@ static int es1938_suspend(struct device *dev) free_irq(chip->irq, chip); chip->irq = -1; } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -1484,14 +1480,6 @@ static int es1938_resume(struct device *dev) struct es1938 *chip = card->private_data; unsigned char *s, *d; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(dev, "unable to grab IRQ %d, disabling device\n", -- cgit v0.10.2 From 8b1db4df201b9ad1f5a329438b823e120d463a96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:47:31 +0100 Subject: ALSA: es1968: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 6039700..631be02 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2383,7 +2383,6 @@ static void snd_es1968_start_irq(struct es1968 *chip) */ static int es1968_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1968 *chip = card->private_data; @@ -2396,16 +2395,11 @@ static int es1968_suspend(struct device *dev) snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_es1968_bob_stop(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int es1968_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1968 *chip = card->private_data; struct esschan *es; @@ -2413,16 +2407,6 @@ static int es1968_resume(struct device *dev) if (! chip->do_pm) return 0; - /* restore all our config */ - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_es1968_chip_init(chip); /* need to restore the base pointers.. */ -- cgit v0.10.2 From e2a711f1b59d59e95f58d1e32e5fbcb7a7a28217 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:47:42 +0100 Subject: ALSA: hda: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d426a0b..99ae4e0 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -795,7 +795,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) */ static int azx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; @@ -824,9 +823,6 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) hda_display_power(false); return 0; @@ -851,15 +847,6 @@ static int azx_resume(struct device *dev) hda_display_power(true); haswell_set_bclk(chip); } - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(chip->card->dev, - "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); if (chip->msi) if (pci_enable_msi(pci) < 0) chip->msi = 0; -- cgit v0.10.2 From b60dc62f5b078222e895aae21b71da968ae101a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:47:55 +0100 Subject: ALSA: ice1712: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index b039b46..e1560bf 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2798,7 +2798,6 @@ static void snd_ice1712_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_ice1712_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; @@ -2820,16 +2819,11 @@ static int snd_ice1712_suspend(struct device *dev) if (ice->pm_suspend) ice->pm_suspend(ice); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_ice1712_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; int rate; @@ -2837,16 +2831,6 @@ static int snd_ice1712_resume(struct device *dev) if (!ice->pm_suspend_enabled) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - snd_card_disconnect(card); - return -EIO; - } - - pci_set_master(pci); - if (ice->cur_rate) rate = ice->cur_rate; else -- cgit v0.10.2 From 88942503538c7ef9636858851abbe50a96db3800 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:48:05 +0100 Subject: ALSA: ice1724: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index d73da15..0b22c00 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2798,7 +2798,6 @@ static void snd_vt1724_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_vt1724_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; @@ -2821,32 +2820,17 @@ static int snd_vt1724_suspend(struct device *dev) if (ice->pm_suspend) ice->pm_suspend(ice); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_vt1724_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; if (!ice->pm_suspend_enabled) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - snd_card_disconnect(card); - return -EIO; - } - - pci_set_master(pci); - snd_vt1724_chip_reset(ice); if (snd_vt1724_chip_init(ice) < 0) { -- cgit v0.10.2 From 3c5a03d490d7b6494f3ec028718770a44520ba29 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:48:15 +0100 Subject: ALSA: intel8x0: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 4a28252..67f9e8b 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2654,7 +2654,6 @@ static int snd_intel8x0_free(struct intel8x0 *chip) */ static int intel8x0_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct intel8x0 *chip = card->private_data; int i; @@ -2682,12 +2681,6 @@ static int intel8x0_suspend(struct device *dev) free_irq(chip->irq, chip); chip->irq = -1; } - pci_disable_device(pci); - pci_save_state(pci); - /* The call below may disable built-in speaker on some laptops - * after S2RAM. So, don't touch it. - */ - /* pci_set_power_state(pci, PCI_D3hot); */ return 0; } @@ -2698,14 +2691,6 @@ static int intel8x0_resume(struct device *dev) struct intel8x0 *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); snd_intel8x0_chip_init(chip, 0); if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { -- cgit v0.10.2 From 65fe5b946e5c0dffb7554cccaff3ab075eec7146 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:48:27 +0100 Subject: ALSA: intel8x0m: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 6b40235..748f6f6 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1023,7 +1023,6 @@ static int snd_intel8x0m_free(struct intel8x0m *chip) */ static int intel8x0m_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct intel8x0m *chip = card->private_data; int i; @@ -1036,9 +1035,6 @@ static int intel8x0m_suspend(struct device *dev) free_irq(chip->irq, chip); chip->irq = -1; } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -1048,14 +1044,6 @@ static int intel8x0m_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct intel8x0m *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(dev, "unable to grab IRQ %d, disabling device\n", -- cgit v0.10.2 From cd86f4593db6ca0256b23a33af5577d5239e78ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:48:50 +0100 Subject: ALSA: maestro3: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 98823d1..18a60be 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2395,7 +2395,6 @@ static int snd_m3_free(struct snd_m3 *chip) #ifdef CONFIG_PM_SLEEP static int m3_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_m3 *chip = card->private_data; int i, dsp_index; @@ -2421,16 +2420,11 @@ static int m3_suspend(struct device *dev) for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) chip->suspend_mem[dsp_index++] = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int m3_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_m3 *chip = card->private_data; int i, dsp_index; @@ -2438,15 +2432,6 @@ static int m3_resume(struct device *dev) if (chip->suspend_mem == NULL) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - /* first lets just bring everything back. .*/ snd_m3_outw(chip, 0, 0x54); snd_m3_outw(chip, 0, 0x56); -- cgit v0.10.2 From fc9b6061cf9c42460e482f7a5947ee8120ff0960 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:49:03 +0100 Subject: ALSA: nm256: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 4e41a4e..8598f2b 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1392,7 +1392,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip) */ static int nm256_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct nm256 *chip = card->private_data; @@ -1400,15 +1399,11 @@ static int nm256_suspend(struct device *dev) snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); chip->coeffs_current = 0; - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int nm256_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct nm256 *chip = card->private_data; int i; @@ -1416,15 +1411,6 @@ static int nm256_resume(struct device *dev) /* Perform a full reset on the hardware */ chip->in_resume = 1; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_nm256_init_chip(chip); /* restore ac97 */ -- cgit v0.10.2 From 2d6b2e59eda2d77c16f9189073adb0484503d168 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:49:13 +0100 Subject: ALSA: oxygen: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b67e306..366723cf 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -728,7 +728,6 @@ EXPORT_SYMBOL(oxygen_pci_remove); #ifdef CONFIG_PM_SLEEP static int oxygen_pci_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct oxygen *chip = card->private_data; unsigned int i, saved_interrupt_mask; @@ -753,10 +752,6 @@ static int oxygen_pci_suspend(struct device *dev) flush_work(&chip->spdif_input_bits_work); flush_work(&chip->gpio_work); chip->interrupt_mask = saved_interrupt_mask; - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -788,20 +783,10 @@ static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec) static int oxygen_pci_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct oxygen *chip = card->private_data; unsigned int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "cannot reenable device"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); for (i = 0; i < OXYGEN_IO_SIZE; ++i) -- cgit v0.10.2 From e066d85cc0f87c6e67bbbb7665de8b30e5ce11e4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:49:42 +0100 Subject: ALSA: riptide: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 6abc2ac..7e922fa 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1153,7 +1153,6 @@ static void riptide_handleirq(unsigned long dev_id) #ifdef CONFIG_PM_SLEEP static int riptide_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_riptide *chip = card->private_data; @@ -1161,27 +1160,14 @@ static int riptide_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int riptide_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_riptide *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "riptide: pci_enable_device failed, " - "disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); snd_riptide_initialize(chip); snd_ac97_resume(chip->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); -- cgit v0.10.2 From a0044463da8a20052b23eb2cd38edbe3e611942e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:49:59 +0100 Subject: ALSA: rme96: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2f1a851..e33e79e 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -2358,7 +2358,6 @@ snd_rme96_create_switches(struct snd_card *card, static int rme96_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct rme96 *rme96 = card->private_data; @@ -2381,26 +2380,14 @@ static int rme96_suspend(struct device *dev) /* disable the DAC */ rme96->areg &= ~RME96_AR_DAC_EN; writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); - - pci_disable_device(pci); - pci_save_state(pci); - return 0; } static int rme96_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct rme96 *rme96 = card->private_data; - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - /* reset playback and record buffer pointers */ writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS + rme96->playback_pointer); -- cgit v0.10.2 From 5b3985ecdc6beab7db96a259fce0d8befd99ff07 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:50:09 +0100 Subject: ALSA: sis7019: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 7f6a0a0..be8952f 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1211,7 +1211,6 @@ static int sis_chip_init(struct sis7019 *sis) #ifdef CONFIG_PM_SLEEP static int sis_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct sis7019 *sis = card->private_data; void __iomem *ioaddr = sis->ioaddr; @@ -1240,9 +1239,6 @@ static int sis_suspend(struct device *dev) ioaddr += 4096; } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -1254,14 +1250,6 @@ static int sis_resume(struct device *dev) void __iomem *ioaddr = sis->ioaddr; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - dev_err(&pci->dev, "unable to re-enable device\n"); - goto error; - } - if (sis_chip_init(sis)) { dev_err(&pci->dev, "unable to re-init controller\n"); goto error; @@ -1284,7 +1272,6 @@ static int sis_resume(struct device *dev) memset(sis->suspend_state[0], 0, 4096); sis->irq = pci->irq; - pci_set_master(pci); if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) snd_ac97_resume(sis->ac97[0]); -- cgit v0.10.2 From 6f9eb021f776e7765a054090932cc9834d99c242 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:50:18 +0100 Subject: ALSA: trident: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 57cd757..0728249 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3926,7 +3926,6 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor #ifdef CONFIG_PM_SLEEP static int snd_trident_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_trident *trident = card->private_data; @@ -3938,28 +3937,14 @@ static int snd_trident_suspend(struct device *dev) snd_ac97_suspend(trident->ac97); snd_ac97_suspend(trident->ac97_sec); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_trident_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_trident *trident = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - switch (trident->device) { case TRIDENT_DEVICE_ID_DX: snd_trident_4d_dx_init(trident); -- cgit v0.10.2 From e909bfdfa9cde50099b5eef5bd4b87d92ddffc86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:50:27 +0100 Subject: ALSA: via82xx: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e088467..120fccb 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2271,7 +2271,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip) */ static int snd_via82xx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx *chip = card->private_data; int i; @@ -2291,28 +2290,15 @@ static int snd_via82xx_suspend(struct device *dev) chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10); } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_via82xx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_via82xx_chip_init(chip); if (chip->chip_type == TYPE_VIA686) { -- cgit v0.10.2 From c11b4c68f4e9b92536fae1f000cb734609633c63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:50:36 +0100 Subject: ALSA: via82xx-modem: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index fd46ffe..884f49e 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1031,7 +1031,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) */ static int snd_via82xx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx_modem *chip = card->private_data; int i; @@ -1043,29 +1042,15 @@ static int snd_via82xx_suspend(struct device *dev) snd_via82xx_channel_reset(chip, &chip->devs[i]); synchronize_irq(chip->irq); snd_ac97_suspend(chip->ac97); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_via82xx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx_modem *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_via82xx_chip_init(chip); snd_ac97_resume(chip->ac97); -- cgit v0.10.2 From de0c869c8369db671d165d89d56ea561bea48bd9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:50:48 +0100 Subject: ALSA: vx222: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index c5a25e3..ecbaf47 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -259,32 +259,17 @@ static void snd_vx222_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_vx222_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_vx222 *vx = card->private_data; - int err; - err = snd_vx_suspend(&vx->core); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); - return err; + return snd_vx_suspend(&vx->core); } static int snd_vx222_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_vx222 *vx = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); return snd_vx_resume(&vx->core); } -- cgit v0.10.2 From 3e41c9b5a1ca2acfd9306a918fe3903f02eb89ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2015 12:50:57 +0100 Subject: ALSA: ymfpci: Simplify PM callbacks This is a similar cleanup like the commit [3db084fd0af5: ALSA: fm801: PCI core handles power state for us]. Since pci_set_power_state(), pci_save_state() and pci_restore_state() are already done in the PCI core side, so we don't need to it doubly. Also, pci_enable_device(), pci_disable_device() and pci_set_master() calls in PM callbacks are superfluous nowadays, too, so get rid of them as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 81c916a..2b0b8f55 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2326,7 +2326,6 @@ static int saved_regs_index[] = { static int snd_ymfpci_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ymfpci *chip = card->private_data; unsigned int i; @@ -2347,9 +2346,6 @@ static int snd_ymfpci_suspend(struct device *dev) snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_disable_dsp(chip); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -2360,14 +2356,6 @@ static int snd_ymfpci_resume(struct device *dev) struct snd_ymfpci *chip = card->private_data; unsigned int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); snd_ymfpci_aclink_reset(pci); snd_ymfpci_codec_ready(chip, 0); snd_ymfpci_download_image(chip); -- cgit v0.10.2 From 880fe82dc555c514b5b4b14642f397afddd82860 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 10 Jan 2015 00:23:43 +0800 Subject: regulator: axp20x: Fill regulators_node and of_match descriptor fields This patch fills the DT related fields in the regulator descriptors, which can then be used by the regulator core's simplified DT code. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index f23d7e1..441ae01 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -32,11 +32,13 @@ #define AXP20X_FREQ_DCDC_MASK 0x0f -#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \ - _emask, _enable_val, _disable_val) \ +#define AXP20X_DESC_IO(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \ + _ereg, _emask, _enable_val, _disable_val) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = (((_max) - (_min)) / (_step) + 1), \ @@ -52,11 +54,13 @@ .ops = &axp20x_ops, \ } -#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \ - _emask) \ +#define AXP20X_DESC(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \ + _ereg, _emask) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = (((_max) - (_min)) / (_step) + 1), \ @@ -70,10 +74,12 @@ .ops = &axp20x_ops, \ } -#define AXP20X_DESC_FIXED(_id, _supply, _volt) \ +#define AXP20X_DESC_FIXED(_id, _match, _supply, _volt) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = 1, \ @@ -82,10 +88,13 @@ .ops = &axp20x_ops_fixed \ } -#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask) \ +#define AXP20X_DESC_TABLE(_id, _match, _supply, _table, _vreg, _vmask, _ereg, \ + _emask) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = ARRAY_SIZE(_table), \ @@ -127,20 +136,20 @@ static struct regulator_ops axp20x_ops = { }; static const struct regulator_desc axp20x_regulators[] = { - AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f, - AXP20X_PWR_OUT_CTRL, 0x10), - AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f, - AXP20X_PWR_OUT_CTRL, 0x02), - AXP20X_DESC_FIXED(LDO1, "acin", 1300), - AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0, - AXP20X_PWR_OUT_CTRL, 0x04), - AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f, - AXP20X_PWR_OUT_CTRL, 0x40), - AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f, - AXP20X_PWR_OUT_CTRL, 0x08), - AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0, - AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED, - AXP20X_IO_DISABLED), + AXP20X_DESC(DCDC2, "dcdc2", "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, + 0x3f, AXP20X_PWR_OUT_CTRL, 0x10), + AXP20X_DESC(DCDC3, "dcdc3", "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, + 0x7f, AXP20X_PWR_OUT_CTRL, 0x02), + AXP20X_DESC_FIXED(LDO1, "ldo1", "acin", 1300), + AXP20X_DESC(LDO2, "ldo2", "ldo24in", 1800, 3300, 100, + AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04), + AXP20X_DESC(LDO3, "ldo3", "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, + 0x7f, AXP20X_PWR_OUT_CTRL, 0x40), + AXP20X_DESC_TABLE(LDO4, "ldo4", "ldo24in", axp20x_ldo4_data, + AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08), + AXP20X_DESC_IO(LDO5, "ldo5", "ldo5in", 1800, 3300, 100, + AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07, + AXP20X_IO_ENABLED, AXP20X_IO_DISABLED), }; #define AXP_MATCH(_name, _id) \ -- cgit v0.10.2 From 765e8023251d3366b959f2e77e5ed48c597d57a0 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 10 Jan 2015 00:23:44 +0800 Subject: regulator: axp20x: Migrate to regulator core's simplified DT parsing code A common simplified DT parsing code for regulators was introduced in commit a0c7b164ad11 ("regulator: of: Provide simplified DT parsing method"). This is very similar to our own code, so get rid of ours and use the common code. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 441ae01..e4331f5 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -152,22 +152,6 @@ static const struct regulator_desc axp20x_regulators[] = { AXP20X_IO_ENABLED, AXP20X_IO_DISABLED), }; -#define AXP_MATCH(_name, _id) \ - [AXP20X_##_id] = { \ - .name = #_name, \ - .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \ - } - -static struct of_regulator_match axp20x_matches[] = { - AXP_MATCH(dcdc2, DCDC2), - AXP_MATCH(dcdc3, DCDC3), - AXP_MATCH(ldo1, LDO1), - AXP_MATCH(ldo2, LDO2), - AXP_MATCH(ldo3, LDO3), - AXP_MATCH(ldo4, LDO4), - AXP_MATCH(ldo5, LDO5), -}; - static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); @@ -202,13 +186,6 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) if (!regulators) { dev_warn(&pdev->dev, "regulators node not found\n"); } else { - ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches, - ARRAY_SIZE(axp20x_matches)); - if (ret < 0) { - dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); - return ret; - } - dcdcfreq = 1500; of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq); ret = axp20x_set_dcdc_freq(pdev, dcdcfreq); @@ -242,23 +219,17 @@ static int axp20x_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct regulator_config config = { }; - struct regulator_init_data *init_data; + struct regulator_config config = { + .dev = pdev->dev.parent, + .regmap = axp20x->regmap, + }; int ret, i; u32 workmode; - ret = axp20x_regulator_parse_dt(pdev); - if (ret) - return ret; + /* This only sets the dcdc freq. Ignore any errors */ + axp20x_regulator_parse_dt(pdev); for (i = 0; i < AXP20X_REG_ID_MAX; i++) { - init_data = axp20x_matches[i].init_data; - - config.dev = pdev->dev.parent; - config.init_data = init_data; - config.regmap = axp20x->regmap; - config.of_node = axp20x_matches[i].of_node; - rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i], &config); if (IS_ERR(rdev)) { @@ -268,7 +239,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } - ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode", + ret = of_property_read_u32(rdev->dev.of_node, + "x-powers,dcdc-workmode", &workmode); if (!ret) { if (axp20x_set_dcdc_workmode(rdev, i, workmode)) -- cgit v0.10.2 From 7ff9d6714a5c97fb448c53aae801af3d529ecb56 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Fri, 9 Jan 2015 14:36:36 +0800 Subject: ASoC: Intel: Split hsw_pcm_data for playback and capture There may be 2 pcm streams for a same DAI at most, and these 2 streams should have different hsw_pcm_data, e.g. they have different persistent data, so here we need split hsw_pcm_data for playback and capture, to make sure they won't be mixed and keep cleaned. Signed-off-by: Jie Yang Reviewed-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 5448f79..ad7f4a5 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -135,7 +135,17 @@ struct hsw_priv_data { struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; /* DAI data */ - struct hsw_pcm_data pcm[HSW_PCM_COUNT]; + struct hsw_pcm_data pcm[HSW_PCM_COUNT][2]; +}; + + +/* static mappings between PCMs and modules - may be dynamic in future */ +static struct hsw_pcm_module_map mod_map[] = { + {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, + {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, + {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, }; static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); @@ -168,9 +178,14 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); - struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; u32 volume; + int dai, stream; + + dai = mod_map[mc->reg].dai_id; + stream = mod_map[mc->reg].stream; + pcm_data = &pdata->pcm[dai][stream]; mutex_lock(&pcm_data->mutex); pm_runtime_get_sync(pdata->dev); @@ -212,9 +227,14 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); - struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; u32 volume; + int dai, stream; + + dai = mod_map[mc->reg].dai_id; + stream = mod_map[mc->reg].stream; + pcm_data = &pdata->pcm[dai][stream]; mutex_lock(&pcm_data->mutex); pm_runtime_get_sync(pdata->dev); @@ -309,7 +329,7 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { ARRAY_SIZE(volume_map) - 1, 0, hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), /* Mic Capture volume */ - SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8, + SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, ARRAY_SIZE(volume_map) - 1, 0, hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), }; @@ -353,7 +373,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; struct sst_module *module_data; struct sst_dsp *dsp; @@ -362,7 +382,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, enum sst_hsw_stream_path_id path_id; u32 rate, bits, map, pages, module_id; u8 channels; - int ret; + int ret, dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; /* check if we are being called a subsequent time */ if (pcm_data->allocated) { @@ -552,8 +575,12 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; + int dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -597,11 +624,16 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; snd_pcm_uframes_t offset; uint64_t ppos; - u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); + u32 position; + int dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; + position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); offset = bytes_to_frames(runtime, position); ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); @@ -618,8 +650,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) snd_soc_platform_get_drvdata(rtd->platform); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; + int dai; - pcm_data = &pdata->pcm[rtd->cpu_dai->id]; + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; mutex_lock(&pcm_data->mutex); pm_runtime_get_sync(pdata->dev); @@ -648,9 +682,12 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; - int ret; + int ret, dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; mutex_lock(&pcm_data->mutex); ret = sst_hsw_stream_reset(hsw, pcm_data->stream); @@ -685,15 +722,6 @@ static struct snd_pcm_ops hsw_pcm_ops = { .page = snd_pcm_sgbuf_ops_page, }; -/* static mappings between PCMs and modules - may be dynamic in future */ -static struct hsw_pcm_module_map mod_map[] = { - {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, - {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, - {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, -}; - static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) { struct sst_hsw *hsw = pdata->hsw; @@ -701,7 +729,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) int i; for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; /* create new runtime module, use same offset if recreated */ pcm_data->runtime = sst_hsw_runtime_module_create(hsw, @@ -716,7 +744,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) err: for (--i; i >= 0; i--) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; sst_hsw_runtime_module_free(pcm_data->runtime); } @@ -729,7 +757,7 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) int i; for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; sst_hsw_runtime_module_free(pcm_data->runtime); } @@ -757,7 +785,10 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) return ret; } } - priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm; + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) + priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm; + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) + priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm; return ret; } @@ -866,10 +897,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) /* allocate DSP buffer page tables */ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { - mutex_init(&priv_data->pcm[i].mutex); - /* playback */ if (hsw_dais[i].playback.channels_min) { + mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, PAGE_SIZE, &priv_data->dmab[i][0]); if (ret < 0) @@ -878,6 +908,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) /* capture */ if (hsw_dais[i].capture.channels_min) { + mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, PAGE_SIZE, &priv_data->dmab[i][1]); if (ret < 0) @@ -1076,7 +1107,7 @@ static void hsw_pcm_complete(struct device *dev) } for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; if (!pcm_data->substream) continue; @@ -1110,7 +1141,7 @@ static int hsw_pcm_prepare(struct device *dev) return 0; /* suspend all active streams */ for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; if (!pcm_data->substream) continue; @@ -1129,7 +1160,7 @@ static int hsw_pcm_prepare(struct device *dev) /* preserve persistent memory */ for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; if (!pcm_data->substream) continue; -- cgit v0.10.2 From 145b3fe579db66fbe999a2bc3fd5b63dffe9636d Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 2 Dec 2014 17:35:04 +0100 Subject: PCI: Generate uppercase hex for modalias var in uevent Some implementations of modprobe fail to load the driver for a PCI device automatically because the "interface" part of the modalias from the kernel is lowercase, and the modalias from file2alias is uppercase. The "interface" is the low-order byte of the Class Code, defined in PCI r3.0, Appendix D. Most interface types defined in the spec do not use alpha characters, so they won't be affected. For example, 00h, 01h, 10h, 20h, etc. are unaffected. Print the "interface" byte of the Class Code in uppercase hex, as we already do for the Vendor ID, Device ID, Class, etc. Commit 89ec3dcf17fd ("PCI: Generate uppercase hex for modalias interface class") fixed only half of the problem. Some udev implementations rely on the uevent file and not the modalias file. Fixes: d1ded203adf1 ("PCI: add MODALIAS to hotplug event for pci devices") Fixes: 89ec3dcf17fd ("PCI: Generate uppercase hex for modalias interface class") Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman CC: stable@vger.kernel.org diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 887e6bd..09a66ba 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1383,7 +1383,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), -- cgit v0.10.2 From 94a90312e4ef1b03469086d41fedfa55e67a1532 Mon Sep 17 00:00:00 2001 From: Chris J Arges Date: Fri, 5 Dec 2014 17:02:42 -0600 Subject: PCI/ASPM: Use standard parsing functions for sysfs setters The functions link_state_store() and clk_ctl_store() had just subtracted ASCII '0' from input which could lead to undesired results. Instead, use Linux string functions to safely parse input. [bhelgaas: check kstrtouint() return value] Signed-off-by: Chris J Arges Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index e1e7026..820740a 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -859,7 +859,10 @@ static ssize_t link_state_store(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); struct pcie_link_state *link, *root = pdev->link_state->root; - u32 val = buf[0] - '0', state = 0; + u32 val, state = 0; + + if (kstrtouint(buf, 10, &val)) + return -EINVAL; if (aspm_disabled) return -EPERM; @@ -900,15 +903,14 @@ static ssize_t clk_ctl_store(struct device *dev, size_t n) { struct pci_dev *pdev = to_pci_dev(dev); - int state; + bool state; - if (n < 1) + if (strtobool(buf, &state)) return -EINVAL; - state = buf[0]-'0'; down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clkpm_nocheck(pdev->link_state, !!state); + pcie_set_clkpm_nocheck(pdev->link_state, state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); -- cgit v0.10.2 From 4808c35e22a81beec8f36b1a22793e5b153d7a11 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 9 Jan 2015 11:30:32 -0700 Subject: PCI: keystone: Fix misspelling of current function in debug output Replace a misspelled function name by %s and then __func__. The function name contains pcie, not pci as in the string. This was done using Coccinelle, including the use of Levenshtein distance, as proposed by Rasmus Villemoes. Signed-off-by: Julia Lawall Signed-off-by: Bjorn Helgaas Acked-by: Murali Karicheri diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 23a1d97..75333b0 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -119,7 +119,7 @@ static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) struct pcie_port *pp = &ks_pcie->pp; struct irq_chip *chip = irq_desc_get_chip(desc); - dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq); + dev_dbg(pp->dev, "%s, irq %d\n", __func__, irq); /* * The chained irq handler installation would have replaced normal -- cgit v0.10.2 From 3c066c642aba407819cf83413025705c6e2a68f9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 21:28:21 +0100 Subject: ASoC: ttc-dkb: Remove unnecessary snd_soc_dapm_disable_pin() calls The "Headset Mic 2" and the "Headset Stereophone" widget are managed by the jack detection logic. Their will be set depending on whether something is connected to the jack or not. There is no need to manually change the state beforehand as it will be overwritten anyway. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index e3d7257a..5001dbb 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -76,10 +76,6 @@ static const struct snd_soc_dapm_route ttc_audio_map[] = { static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); - snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); /* Headset jack detection */ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE -- cgit v0.10.2 From 46d0d8df157b4d9bdf7849ce4ae795d399018669 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:26 +0100 Subject: ASoC: corgi: Automatically disconnect non-connected pins All DAPM input and output pins of the wm8994 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index b7cd0a7..3580d10 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -259,20 +259,6 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = { corgi_set_spk), }; -/* - * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device - */ -static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_nc_pin(dapm, "LLINEIN"); - snd_soc_dapm_nc_pin(dapm, "RLINEIN"); - - return 0; -} - /* corgi digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link corgi_dai = { .name = "WM8731", @@ -281,7 +267,6 @@ static struct snd_soc_dai_link corgi_dai = { .codec_dai_name = "wm8731-hifi", .platform_name = "pxa-pcm-audio", .codec_name = "wm8731.0-001b", - .init = corgi_wm8731_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &corgi_ops, @@ -300,6 +285,7 @@ static struct snd_soc_card corgi = { .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), .dapm_routes = corgi_audio_map, .num_dapm_routes = ARRAY_SIZE(corgi_audio_map), + .fully_routed = true, }; static int corgi_probe(struct platform_device *pdev) -- cgit v0.10.2 From dff6c9642369e7cb0f5bf8b280a270c4a4bf797d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:27 +0100 Subject: ASoC: e740: Automatically disconnect non-connected pins All DAPM input and output pins of the wm9705 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 7c691aa..d72e124 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -88,24 +88,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Mic Amp", NULL, "Mic (Internal)"}, }; -static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_nc_pin(dapm, "HPOUTL"); - snd_soc_dapm_nc_pin(dapm, "HPOUTR"); - snd_soc_dapm_nc_pin(dapm, "PHONE"); - snd_soc_dapm_nc_pin(dapm, "LINEINL"); - snd_soc_dapm_nc_pin(dapm, "LINEINR"); - snd_soc_dapm_nc_pin(dapm, "CDINL"); - snd_soc_dapm_nc_pin(dapm, "CDINR"); - snd_soc_dapm_nc_pin(dapm, "PCBEEP"); - snd_soc_dapm_nc_pin(dapm, "MIC2"); - - return 0; -} - static struct snd_soc_dai_link e740_dai[] = { { .name = "AC97", @@ -114,7 +96,6 @@ static struct snd_soc_dai_link e740_dai[] = { .codec_dai_name = "wm9705-hifi", .platform_name = "pxa-pcm-audio", .codec_name = "wm9705-codec", - .init = e740_ac97_init, }, { .name = "AC97 Aux", @@ -136,6 +117,7 @@ static struct snd_soc_card e740 = { .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, }; static struct gpio e740_audio_gpios[] = { -- cgit v0.10.2 From 7523f69e584cba16775cbc70a4f0adcb84625894 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:28 +0100 Subject: ASoC: e750: Automatically disconnect non-connected pins All DAPM input and output pins of the wm9705 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index 30544b6..48f2d7c 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -70,24 +70,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"MIC1", NULL, "Mic (Internal)"}, }; -static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_nc_pin(dapm, "LOUT"); - snd_soc_dapm_nc_pin(dapm, "ROUT"); - snd_soc_dapm_nc_pin(dapm, "PHONE"); - snd_soc_dapm_nc_pin(dapm, "LINEINL"); - snd_soc_dapm_nc_pin(dapm, "LINEINR"); - snd_soc_dapm_nc_pin(dapm, "CDINL"); - snd_soc_dapm_nc_pin(dapm, "CDINR"); - snd_soc_dapm_nc_pin(dapm, "PCBEEP"); - snd_soc_dapm_nc_pin(dapm, "MIC2"); - - return 0; -} - static struct snd_soc_dai_link e750_dai[] = { { .name = "AC97", @@ -96,7 +78,6 @@ static struct snd_soc_dai_link e750_dai[] = { .codec_dai_name = "wm9705-hifi", .platform_name = "pxa-pcm-audio", .codec_name = "wm9705-codec", - .init = e750_ac97_init, /* use ops to check startup state */ }, { @@ -119,6 +100,7 @@ static struct snd_soc_card e750 = { .num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, }; static struct gpio e750_audio_gpios[] = { -- cgit v0.10.2 From c529d0a420ba4ba2031f61a4b86f59e31ddc964e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:29 +0100 Subject: ASoC: hx4700: Automatically disconnect non-connected pins All DAPM input and output pins of the ak4641 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index ce26551..73eb5dd 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -127,15 +127,8 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = { static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; int err; - /* NC codec pins */ - /* FIXME: is anything connected here? */ - snd_soc_dapm_nc_pin(dapm, "MOUT1"); - snd_soc_dapm_nc_pin(dapm, "MICEXT"); - snd_soc_dapm_nc_pin(dapm, "AUX"); - /* Jack detection API stuff */ err = snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hs_jack); @@ -184,6 +177,7 @@ static struct snd_soc_card snd_soc_card_hx4700 = { .num_dapm_widgets = ARRAY_SIZE(hx4700_dapm_widgets), .dapm_routes = hx4700_audio_map, .num_dapm_routes = ARRAY_SIZE(hx4700_audio_map), + .fully_routed = true, }; static struct gpio hx4700_audio_gpios[] = { -- cgit v0.10.2 From 3cfaaaa0e729aa10a5e2dfe1efb1c05a6f5a89d1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:30 +0100 Subject: ASoC: magician: Automatically disconnect non-connected pins All DAPM input and output pins of the uda1380 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 259e048..241d0be 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -391,25 +391,6 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = { magician_get_input, magician_set_input), }; -/* - * Logic for a uda1380 as connected on a HTC Magician - */ -static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - /* NC codec pins */ - snd_soc_dapm_nc_pin(dapm, "VOUTLHP"); - snd_soc_dapm_nc_pin(dapm, "VOUTRHP"); - - /* FIXME: is anything connected here? */ - snd_soc_dapm_nc_pin(dapm, "VINL"); - snd_soc_dapm_nc_pin(dapm, "VINR"); - - return 0; -} - /* magician digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link magician_dai[] = { { @@ -419,7 +400,6 @@ static struct snd_soc_dai_link magician_dai[] = { .codec_dai_name = "uda1380-hifi-playback", .platform_name = "pxa-pcm-audio", .codec_name = "uda1380-codec.0-0018", - .init = magician_uda1380_init, .ops = &magician_playback_ops, }, { @@ -446,6 +426,7 @@ static struct snd_soc_card snd_soc_card_magician = { .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, }; static struct platform_device *magician_snd_device; -- cgit v0.10.2 From b68ef0e0368cda4e17541ae87bbb5b40dc15cbc1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:31 +0100 Subject: ASoC: palm27x: Fix microphone route The microphone route has sink and source swapped. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 1eebca2..5a0b82f 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -68,7 +68,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Ext. Speaker", NULL, "ROUT2"}, /* mic connected to MIC1 */ - {"Ext. Microphone", NULL, "MIC1"}, + {"MIC1", NULL, "Ext. Microphone"}, }; static struct snd_soc_card palm27x_asoc; -- cgit v0.10.2 From 19a3477ec0eb635bdebd1dd905b1cee9a3c06c96 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:32 +0100 Subject: ASoC: palm27x: Automatically disconnect non-connected pins All DAPM input and output pins of the wm9712 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 5a0b82f..910336c 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -76,18 +76,8 @@ static struct snd_soc_card palm27x_asoc; static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; int err; - /* not connected pins */ - snd_soc_dapm_nc_pin(dapm, "OUT3"); - snd_soc_dapm_nc_pin(dapm, "MONOOUT"); - snd_soc_dapm_nc_pin(dapm, "LINEINL"); - snd_soc_dapm_nc_pin(dapm, "LINEINR"); - snd_soc_dapm_nc_pin(dapm, "PCBEEP"); - snd_soc_dapm_nc_pin(dapm, "PHONE"); - snd_soc_dapm_nc_pin(dapm, "MIC2"); - /* Jack detection API stuff */ err = snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hs_jack); @@ -133,7 +123,8 @@ static struct snd_soc_card palm27x_asoc = { .dapm_widgets = palm27x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets), .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map) + .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, }; static int palm27x_asoc_probe(struct platform_device *pdev) -- cgit v0.10.2 From c4b7586cc972ec8cca77d2f6faed1f19a11d6445 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 9 Jan 2015 22:03:33 +0100 Subject: ASoC: spitz: Automatically disconnect non-connected pins All DAPM input and output pins of the wm8750 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index a6d680a..461123a 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -256,26 +256,6 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = { spitz_set_spk), }; -/* - * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device - */ -static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - /* NC codec pins */ - snd_soc_dapm_nc_pin(dapm, "RINPUT1"); - snd_soc_dapm_nc_pin(dapm, "LINPUT2"); - snd_soc_dapm_nc_pin(dapm, "RINPUT2"); - snd_soc_dapm_nc_pin(dapm, "LINPUT3"); - snd_soc_dapm_nc_pin(dapm, "RINPUT3"); - snd_soc_dapm_nc_pin(dapm, "OUT3"); - snd_soc_dapm_nc_pin(dapm, "MONO1"); - - return 0; -} - /* spitz digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link spitz_dai = { .name = "wm8750", @@ -284,7 +264,6 @@ static struct snd_soc_dai_link spitz_dai = { .codec_dai_name = "wm8750-hifi", .platform_name = "pxa-pcm-audio", .codec_name = "wm8750.0-001b", - .init = spitz_wm8750_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &spitz_ops, @@ -303,6 +282,7 @@ static struct snd_soc_card snd_soc_spitz = { .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), .dapm_routes = spitz_audio_map, .num_dapm_routes = ARRAY_SIZE(spitz_audio_map), + .fully_routed = true, }; static int spitz_probe(struct platform_device *pdev) -- cgit v0.10.2 From 99590ba565a22c9f58f7528a94881d0455eef018 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 9 Jan 2015 14:03:04 -0600 Subject: livepatch: fix deferred module patching order When applying multiple patches to a module, if the module is loaded after the patches are loaded, the patches are applied in reverse order: $ insmod patch1.ko [ 43.172992] livepatch: enabling patch 'patch1' $ insmod patch2.ko [ 46.571563] livepatch: enabling patch 'patch2' $ modprobe nfsd [ 52.888922] livepatch: applying patch 'patch2' to loading module 'nfsd' [ 52.899847] livepatch: applying patch 'patch1' to loading module 'nfsd' Fix the loading order by storing the klp_patches list in queue order. Signed-off-by: Josh Poimboeuf Signed-off-by: Jiri Kosina diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index ce42d3b..3d9c00b 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -739,7 +739,7 @@ static int klp_init_patch(struct klp_patch *patch) goto free; } - list_add(&patch->list, &klp_patches); + list_add_tail(&patch->list, &klp_patches); mutex_unlock(&klp_mutex); -- cgit v0.10.2 From 9eb457b547cc731bc2fc251bd79891a60c64fc3e Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 4 Dec 2014 12:32:50 +0200 Subject: pinctrl: cherryview: Save and restore pin configs over system sleep Before resuming from system sleep BIOS restores its view of pin configuration. If we have configured some pins differently from that, for instance some driver requested a pin as a GPIO but it was not in GPIO mode originally, our view of the pin configuration will not match the hardware state anymore. This patch saves the pin configuration and interrupt mask registers on suspend and restores them on exit. This should make sure that the previously configured state is still in effect. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index e9f8b39..dde67d4 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -148,6 +148,11 @@ struct chv_community { size_t ngpios; }; +struct chv_pin_context { + u32 padctrl0; + u32 padctrl1; +}; + /** * struct chv_pinctrl - CHV pinctrl private structure * @dev: Pointer to the parent device @@ -172,6 +177,8 @@ struct chv_pinctrl { spinlock_t lock; unsigned intr_lines[16]; const struct chv_community *community; + u32 saved_intmask; + struct chv_pin_context *saved_pin_context; }; #define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip) @@ -1443,6 +1450,14 @@ static int chv_pinctrl_probe(struct platform_device *pdev) spin_lock_init(&pctrl->lock); pctrl->dev = &pdev->dev; +#ifdef CONFIG_PM_SLEEP + pctrl->saved_pin_context = devm_kcalloc(pctrl->dev, + pctrl->community->npins, sizeof(*pctrl->saved_pin_context), + GFP_KERNEL); + if (!pctrl->saved_pin_context) + return -ENOMEM; +#endif + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pctrl->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pctrl->regs)) @@ -1486,6 +1501,94 @@ static int chv_pinctrl_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int chv_pinctrl_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + int i; + + pctrl->saved_intmask = readl(pctrl->regs + CHV_INTMASK); + + for (i = 0; i < pctrl->community->npins; i++) { + const struct pinctrl_pin_desc *desc; + struct chv_pin_context *ctx; + void __iomem *reg; + + desc = &pctrl->community->pins[i]; + if (chv_pad_locked(pctrl, desc->number)) + continue; + + ctx = &pctrl->saved_pin_context[i]; + + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL0); + ctx->padctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIORXSTATE; + + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL1); + ctx->padctrl1 = readl(reg); + } + + return 0; +} + +static int chv_pinctrl_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + int i; + + /* + * Mask all interrupts before restoring per-pin configuration + * registers because we don't know in which state BIOS left them + * upon exiting suspend. + */ + chv_writel(0, pctrl->regs + CHV_INTMASK); + + for (i = 0; i < pctrl->community->npins; i++) { + const struct pinctrl_pin_desc *desc; + const struct chv_pin_context *ctx; + void __iomem *reg; + u32 val; + + desc = &pctrl->community->pins[i]; + if (chv_pad_locked(pctrl, desc->number)) + continue; + + ctx = &pctrl->saved_pin_context[i]; + + /* Only restore if our saved state differs from the current */ + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL0); + val = readl(reg) & ~CHV_PADCTRL0_GPIORXSTATE; + if (ctx->padctrl0 != val) { + chv_writel(ctx->padctrl0, reg); + dev_dbg(pctrl->dev, "restored pin %2u ctrl0 0x%08x\n", + desc->number, readl(reg)); + } + + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL1); + val = readl(reg); + if (ctx->padctrl1 != val) { + chv_writel(ctx->padctrl1, reg); + dev_dbg(pctrl->dev, "restored pin %2u ctrl1 0x%08x\n", + desc->number, readl(reg)); + } + } + + /* + * Now that all pins are restored to known state, we can restore + * the interrupt mask register as well. + */ + chv_writel(0xffff, pctrl->regs + CHV_INTSTAT); + chv_writel(pctrl->saved_intmask, pctrl->regs + CHV_INTMASK); + + return 0; +} +#endif + +static const struct dev_pm_ops chv_pinctrl_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend, chv_pinctrl_resume) +}; + static const struct acpi_device_id chv_pinctrl_acpi_match[] = { { "INT33FF" }, { } @@ -1498,6 +1601,7 @@ static struct platform_driver chv_pinctrl_driver = { .driver = { .name = "cherryview-pinctrl", .owner = THIS_MODULE, + .pm = &chv_pinctrl_pm_ops, .acpi_match_table = chv_pinctrl_acpi_match, }, }; -- cgit v0.10.2 From 1ee68af8a5003bdda32ca02f93afc9701d50e871 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:36 +0100 Subject: pinctrl: intel: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Acked-by: Mika Westerberg Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index dde67d4..a2f23c3 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1600,7 +1600,6 @@ static struct platform_driver chv_pinctrl_driver = { .remove = chv_pinctrl_remove, .driver = { .name = "cherryview-pinctrl", - .owner = THIS_MODULE, .pm = &chv_pinctrl_pm_ops, .acpi_match_table = chv_pinctrl_acpi_match, }, -- cgit v0.10.2 From a95308d88c07e0093aedae7e64f92cb1e165f592 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 5 Dec 2014 15:44:57 +0100 Subject: pinctrl: mvebu: a38x: Add UART1 muxing options The MPP19 and MMP20 pins also have the ability to be muxed to the uart1 function. Add this case to the pinctrl driver. Signed-off-by: Maxime Ripard Acked-by: Jason Cooper Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c index 224c6cf..7302f66 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c @@ -145,14 +145,16 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = { MPP_VAR_FUNCTION(2, "ptp", "event_req", V_88F6810_PLUS), MPP_VAR_FUNCTION(3, "pcie0", "clkreq", V_88F6810_PLUS), MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS), - MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS)), + MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)), MPP_MODE(20, MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS), MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS), MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS), MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS), - MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS)), + MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)), MPP_MODE(21, MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6810_PLUS), -- cgit v0.10.2 From 2ef2a489256b135429a652060416714172c23603 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 10 Jan 2015 22:13:02 +0100 Subject: pinctrl: nomadik:fix up device tree bindings After the Nomadik pin controller was force migrated to generic pin control bindings, some leftovers in the documentation need to be cleaned up. The code and device trees are already migrated. Signed-off-by: Linus Walleij diff --git a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt index 6b33b9f..f63fcb3 100644 --- a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt +++ b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt @@ -16,17 +16,22 @@ mux function to select on those pin(s)/group(s), and various pin configuration parameters, such as input, output, pull up, pull down... The name of each subnode is not important; all subnodes should be enumerated -and processed purely based on their content. +and processed purely based on their content. The subnodes use the generic +pin multiplexing node layout from the standard pin control bindings +(see pinctrl-bindings.txt): -Required subnode-properties: -- ste,pins : An array of strings. Each string contains the name of a pin or - group. - -Optional subnode-properties: -- ste,function: A string containing the name of the function to mux to the +Required pin multiplexing subnode properties: +- function: A string containing the name of the function to mux to the pin or group. +- groups : An array of strings. Each string contains the name of a pin + group that will be combined with the function to form a multiplexing + set-up. -- ste,config: Handle of pin configuration node (e.g. ste,config = <&slpm_in_wkup_pdis>) +Required pin configuration subnode properties: +- pins: A string array describing the pins affected by the configuration + in the node. +- ste,config: Handle of pin configuration node + (e.g. ste,config = <&slpm_in_wkup_pdis>) - ste,input : <0/1/2> 0: input with no pull @@ -97,32 +102,32 @@ Example board file extract: uart0 { uart0_default_mux: uart0_mux { u0_default_mux { - ste,function = "u0"; - ste,pins = "u0_a_1"; + function = "u0"; + pins = "u0_a_1"; }; }; uart0_default_mode: uart0_default { uart0_default_cfg1 { - ste,pins = "GPIO0", "GPIO2"; + pins = "GPIO0", "GPIO2"; ste,input = <1>; }; uart0_default_cfg2 { - ste,pins = "GPIO1", "GPIO3"; + pins = "GPIO1", "GPIO3"; ste,output = <1>; }; }; uart0_sleep_mode: uart0_sleep { uart0_sleep_cfg1 { - ste,pins = "GPIO0", "GPIO2"; + pins = "GPIO0", "GPIO2"; ste,config = <&slpm_in_wkup_pdis>; }; uart0_sleep_cfg2 { - ste,pins = "GPIO1"; + pins = "GPIO1"; ste,config = <&slpm_out_hi_wkup_pdis>; }; uart0_sleep_cfg3 { - ste,pins = "GPIO3"; + pins = "GPIO3"; ste,config = <&slpm_out_wkup_pdis>; }; }; -- cgit v0.10.2 From e2821bee40bec00aed5abffa446a5ac3738b041e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 10 Jan 2015 22:47:56 +0100 Subject: pinctrl: pass -DDEBUG in subdirs When drivers are compiled in subdirectories the -DDEBUG flag need to be passed in the individual Makefiles. Reported-by: Mika Westerberg Suggested-by: Yingjoe Chen Cc: Mika Westerberg Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index c030b3d..c7139ba 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,6 +1,6 @@ # generic pinmux support -ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG +subdir-ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o -- cgit v0.10.2 From 846a7fc8f4bc8f0d04be8d953ecba28152b14de4 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Sat, 10 Jan 2015 14:04:14 -0800 Subject: Input: add support for NI Ettus Research USRP E3x0 button Signed-off-by: Moritz Fischer Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/e3x0-button.txt b/Documentation/devicetree/bindings/input/e3x0-button.txt new file mode 100644 index 0000000..751665e --- /dev/null +++ b/Documentation/devicetree/bindings/input/e3x0-button.txt @@ -0,0 +1,25 @@ +National Instruments Ettus Research USRP E3x0 button driver + +This module is part of the NI Ettus Research USRP E3x0 SDR. + +This module provides a simple power button event via two interrupts. + +Required properties: +- compatible: should be one of the following + - "ettus,e3x0-button": For devices such as the NI Ettus Research USRP E3x0 +- interrupt-parent: + - a phandle to the interrupt controller that it is attached to. +- interrupts: should be one of the following + - <0 30 1>, <0 31 1>: For devices such as the NI Ettus Research USRP E3x0 +- interrupt-names: should be one of the following + - "press", "release": For devices such as the NI Ettus Research USRP E3x0 + +Note: Interrupt numbers might vary depending on the FPGA configuration. + +Example: + button { + compatible = "ettus,e3x0-button"; + interrupt-parent = <&intc>; + interrupts = <0 30 1>, <0 31 1>; + interrupt-names = "press", "release"; + } diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index e6469ec..9f18b4f 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -48,6 +48,7 @@ epcos EPCOS AG epfl Ecole Polytechnique Fédérale de Lausanne epson Seiko Epson Corp. est ESTeem Wireless Modems +ettus NI Ettus Research eukrea Eukréa Electromatique excito Excito fsl Freescale Semiconductor diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 9e610c4..6deb8da 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -93,6 +93,16 @@ config INPUT_BMA150 To compile this driver as a module, choose M here: the module will be called bma150. +config INPUT_E3X0_BUTTON + tristate "NI Ettus Research USRP E3x0 Button support." + default n + help + Say Y here to enable support for the NI Ettus Research + USRP E3x0 Button. + + To compile this driver as a module, choose M here: the + module will be called e3x0_button. + config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index f8d9ea7..403a1a5 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o +obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c new file mode 100644 index 0000000..13bfca8 --- /dev/null +++ b/drivers/input/misc/e3x0-button.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2014, National Instruments Corp. All rights reserved. + * + * Driver for NI Ettus Research USRP E3x0 Button Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static irqreturn_t e3x0_button_release_handler(int irq, void *data) +{ + struct input_dev *idev = data; + + input_report_key(idev, KEY_POWER, 0); + input_sync(idev); + + return IRQ_HANDLED; +} + +static irqreturn_t e3x0_button_press_handler(int irq, void *data) +{ + struct input_dev *idev = data; + + input_report_key(idev, KEY_POWER, 1); + pm_wakeup_event(idev->dev.parent, 0); + input_sync(idev); + + return IRQ_HANDLED; +} + +static int __maybe_unused e3x0_button_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(platform_get_irq_byname(pdev, "press")); + + return 0; +} + +static int __maybe_unused e3x0_button_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(platform_get_irq_byname(pdev, "press")); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops, + e3x0_button_suspend, e3x0_button_resume); + +static int e3x0_button_probe(struct platform_device *pdev) +{ + struct input_dev *input; + int irq_press, irq_release; + int error; + + irq_press = platform_get_irq_byname(pdev, "press"); + if (irq_press < 0) { + dev_err(&pdev->dev, "No IRQ for 'press', error=%d\n", + irq_press); + return irq_press; + } + + irq_release = platform_get_irq_byname(pdev, "release"); + if (irq_release < 0) { + dev_err(&pdev->dev, "No IRQ for 'release', error=%d\n", + irq_release); + return irq_release; + } + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; + + input->name = "NI Ettus Research USRP E3x0 Button Driver"; + input->phys = "e3x0_button/input0"; + input->dev.parent = &pdev->dev; + + input_set_capability(input, EV_KEY, KEY_POWER); + + error = devm_request_irq(&pdev->dev, irq_press, + e3x0_button_press_handler, 0, + "e3x0-button", input); + if (error) { + dev_err(&pdev->dev, "Failed to request 'press' IRQ#%d: %d\n", + irq_press, error); + return error; + } + + error = devm_request_irq(&pdev->dev, irq_release, + e3x0_button_release_handler, 0, + "e3x0-button", input); + if (error) { + dev_err(&pdev->dev, "Failed to request 'release' IRQ#%d: %d\n", + irq_release, error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "Can't register input device: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, input); + device_init_wakeup(&pdev->dev, 1); + return 0; +} + +static int e3x0_button_remove(struct platform_device *pdev) +{ + device_init_wakeup(&pdev->dev, 0); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id e3x0_button_match[] = { + { .compatible = "ettus,e3x0-button", }, + { } +}; +MODULE_DEVICE_TABLE(of, e3x0_button_match); +#endif + +static struct platform_driver e3x0_button_driver = { + .driver = { + .name = "e3x0-button", + .of_match_table = of_match_ptr(e3x0_button_match), + .pm = &e3x0_button_pm_ops, + }, + .probe = e3x0_button_probe, + .remove = e3x0_button_remove, +}; + +module_platform_driver(e3x0_button_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Moritz Fischer "); +MODULE_DESCRIPTION("NI Ettus Research USRP E3x0 Button driver"); +MODULE_ALIAS("platform:e3x0-button"); -- cgit v0.10.2 From f17effbe891624fe1ec2dcfa68625ed1c98ebe3a Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Sat, 10 Jan 2015 14:10:59 -0800 Subject: MAINTAINERS: add info for e3x0-button driver Signed-off-by: Moritz Fischer Signed-off-by: Dmitry Torokhov diff --git a/MAINTAINERS b/MAINTAINERS index 21b834b..d726917 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3277,6 +3277,14 @@ M: "Maciej W. Rozycki" S: Maintained F: drivers/tty/serial/dz.* +E3X0 POWER BUTTON DRIVER +M: Moritz Fischer +L: usrp-users@lists.ettus.com +W: http://www.ettus.com +S: Supported +F: drivers/input/misc/e3x0-button.c +F: Documentation/devicetree/bindings/input/e3x0-button.txt + E4000 MEDIA DRIVER M: Antti Palosaari L: linux-media@vger.kernel.org -- cgit v0.10.2 From f94fe119f2e53362a3038ee856fa58412f728bc9 Mon Sep 17 00:00:00 2001 From: Steven Honeyman Date: Wed, 5 Nov 2014 22:52:18 +0000 Subject: x86, CPU: Fix trivial printk formatting issues with dmesg dmesg (from util-linux) currently has two methods for reading the kernel message ring buffer: /dev/kmsg and syslog(2). Since kernel 3.5.0 kmsg has been the default, which escapes control characters (e.g. new lines) before they are shown. This change means that when dmesg is using /dev/kmsg, a 2 line printk makes the output messy, because the second line does not get a timestamp. For example: [ 0.012863] CPU0: Thermal monitoring enabled (TM1) [ 0.012869] Last level iTLB entries: 4KB 1024, 2MB 1024, 4MB 1024 Last level dTLB entries: 4KB 1024, 2MB 1024, 4MB 1024, 1GB 4 [ 0.012958] Freeing SMP alternatives memory: 28K (ffffffff81d86000 - ffffffff81d8d000) [ 0.014961] dmar: Host address width 39 Because printk.c intentionally escapes control characters, they should not be there in the first place. This patch fixes two occurrences of this. Signed-off-by: Steven Honeyman Link: https://lkml.kernel.org/r/1414856696-8094-1-git-send-email-stevenhoneyman@gmail.com [ Boris: make cpu_detect_tlb() static, while at it. ] Signed-off-by: Borislav Petkov diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c604965..4973d63 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -491,17 +491,18 @@ u16 __read_mostly tlb_lld_2m[NR_INFO]; u16 __read_mostly tlb_lld_4m[NR_INFO]; u16 __read_mostly tlb_lld_1g[NR_INFO]; -void cpu_detect_tlb(struct cpuinfo_x86 *c) +static void cpu_detect_tlb(struct cpuinfo_x86 *c) { if (this_cpu->c_detect_tlb) this_cpu->c_detect_tlb(c); - printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" - "Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d, 1GB %d\n", + pr_info("Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n", tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES], - tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES], - tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES], - tlb_lld_1g[ENTRIES]); + tlb_lli_4m[ENTRIES]); + + pr_info("Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d, 1GB %d\n", + tlb_lld_4k[ENTRIES], tlb_lld_2m[ENTRIES], + tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]); } void detect_ht(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 9cc6b6f..94d7dcb 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -487,10 +487,8 @@ static void init_intel(struct cpuinfo_x86 *c) rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) { - printk_once(KERN_WARNING "ENERGY_PERF_BIAS:" - " Set to 'normal', was 'performance'\n" - "ENERGY_PERF_BIAS: View and update with" - " x86_energy_perf_policy(8)\n"); + pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n"); + pr_warn_once("ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)\n"); epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL; wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); } -- cgit v0.10.2 From 79619cf5151257f82a4c016b02283e2ceb4b63ce Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 17 Nov 2014 10:12:27 -0800 Subject: rcutorture: Issue warnings on close calls due to Reader Batch blows Normal rcutorture checking overestimates grace periods somewhat due to the fact that there is a delay from a grace-period request until the start of the corresponding grace period and another delay from the end of that grace period to notification of the requestor. This means that rcutorture's detection of RCU bugs is less sensitive than it might be. It turns out that rcutorture also checks the underlying grace-period "completed" counter (displayed in Reader Batch output), which in theory allows rcutorture to do exact checks. In practice, memory misordering (by both compiler and CPU) can result in false positives. However, experience on x86 shows that these false positives are quite rare, occurring less than one time per 1,000 hours of testing. This commit therefore does the exact checking, giving a warning if any Reader Batch blows happen, and flagging an error if they happen more often than once every three hours in long tests. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh index d6cc07f..559e01a 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh @@ -30,6 +30,7 @@ else echo Unreadable results directory: $i exit 1 fi +. tools/testing/selftests/rcutorture/bin/functions.sh configfile=`echo $i | sed -e 's/^.*\///'` ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` @@ -48,4 +49,21 @@ else title="$title ($ngpsps per second)" fi echo $title + nclosecalls=`grep --binary-files=text 'torture: Reader Batch' $i/console.log | tail -1 | awk '{for (i=NF-8;i<=NF;i++) sum+=$i; } END {print sum}'` + if test -z "$nclosecalls" + then + exit 0 + fi + if test "$nclosecalls" -eq 0 + then + exit 0 + fi + # Compute number of close calls per tenth of an hour + nclosecalls10=`awk -v nclosecalls=$nclosecalls -v dur=$dur 'BEGIN { print int(nclosecalls * 36000 / dur) }' < /dev/null` + if test $nclosecalls10 -gt 5 -a $nclosecalls -gt 1 + then + print_bug $nclosecalls "Reader Batch close calls in" $(($dur/60)) minute run: $i + else + print_warning $nclosecalls "Reader Batch close calls in" $(($dur/60)) minute run: $i + fi fi -- cgit v0.10.2 From 9733e4f0a973a354034f5dd603b4142a3095c85f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 12:49:13 -0800 Subject: rcu: Make _batches_completed() functions return unsigned long Long ago, the various ->completed fields were of type long, but now are unsigned long due to signed-integer-overflow concerns. However, the various _batches_completed() functions remained of type long, even though their only purpose in life is to return the corresponding ->completed field. This patch cleans this up by changing these functions' return types to unsigned long. Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 0e53662..91f7e4c 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -94,7 +94,7 @@ static inline void rcu_virt_note_context_switch(int cpu) /* * Return the number of grace periods. */ -static inline long rcu_batches_completed(void) +static inline unsigned long rcu_batches_completed(void) { return 0; } @@ -102,7 +102,7 @@ static inline long rcu_batches_completed(void) /* * Return the number of bottom-half grace periods. */ -static inline long rcu_batches_completed_bh(void) +static inline unsigned long rcu_batches_completed_bh(void) { return 0; } diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 5295379..9885bfb 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -81,9 +81,9 @@ void cond_synchronize_rcu(unsigned long oldstate); extern unsigned long rcutorture_testseq; extern unsigned long rcutorture_vernum; -long rcu_batches_completed(void); -long rcu_batches_completed_bh(void); -long rcu_batches_completed_sched(void); +unsigned long rcu_batches_completed(void); +unsigned long rcu_batches_completed_bh(void); +unsigned long rcu_batches_completed_sched(void); void show_rcu_gp_kthreads(void); void rcu_force_quiescent_state(void); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 4c106fc..e26d787 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -317,7 +317,7 @@ static int rcu_pending(void); /* * Return the number of RCU-sched batches processed thus far for debug & stats. */ -long rcu_batches_completed_sched(void) +unsigned long rcu_batches_completed_sched(void) { return rcu_sched_state.completed; } @@ -326,7 +326,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed_sched); /* * Return the number of RCU BH batches processed thus far for debug & stats. */ -long rcu_batches_completed_bh(void) +unsigned long rcu_batches_completed_bh(void) { return rcu_bh_state.completed; } diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 8e7b184..1a07d73 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -546,7 +546,7 @@ DECLARE_PER_CPU(char, rcu_cpu_has_work); /* Forward declarations for rcutree_plugin.h */ static void rcu_bootup_announce(void); -long rcu_batches_completed(void); +unsigned long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(void); static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 3ec85cb..f69300d 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -117,7 +117,7 @@ static void __init rcu_bootup_announce(void) * Return the number of RCU-preempt batches processed thus far * for debug and statistics. */ -static long rcu_batches_completed_preempt(void) +static unsigned long rcu_batches_completed_preempt(void) { return rcu_preempt_state.completed; } @@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed_preempt); /* * Return the number of RCU batches processed thus far for debug & stats. */ -long rcu_batches_completed(void) +unsigned long rcu_batches_completed(void) { return rcu_batches_completed_preempt(); } @@ -935,7 +935,7 @@ static void __init rcu_bootup_announce(void) /* * Return the number of RCU batches processed thus far for debug & stats. */ -long rcu_batches_completed(void) +unsigned long rcu_batches_completed(void) { return rcu_batches_completed_sched(); } -- cgit v0.10.2 From 3b009c0ebe02a06d2d5bd667da0eb9cefa79321d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 13:54:57 -0800 Subject: rcutorture: Make build-output parsing correctly flag RCU's warnings Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/parse-build.sh b/tools/testing/selftests/rcutorture/bin/parse-build.sh index 499d1e5..a6b5762 100755 --- a/tools/testing/selftests/rcutorture/bin/parse-build.sh +++ b/tools/testing/selftests/rcutorture/bin/parse-build.sh @@ -26,12 +26,15 @@ # # Authors: Paul E. McKenney -T=$1 +F=$1 title=$2 +T=/tmp/parse-build.sh.$$ +trap 'rm -rf $T' 0 +mkdir $T . functions.sh -if grep -q CC < $T +if grep -q CC < $F then : else @@ -39,18 +42,21 @@ else exit 1 fi -if grep -q "error:" < $T +if grep -q "error:" < $F then print_bug $title build errors: - grep "error:" < $T + grep "error:" < $F exit 2 fi -exit 0 -if egrep -q "rcu[^/]*\.c.*warning:|rcu.*\.h.*warning:" < $T +grep warning: < $F > $T/warnings +grep "include/linux/*rcu*\.h:" $T/warnings > $T/hwarnings +grep "kernel/rcu/[^/]*:" $T/warnings > $T/cwarnings +cat $T/hwarnings $T/cwarnings > $T/rcuwarnings +if test -s $T/rcuwarnings then print_warning $title build errors: - egrep "rcu[^/]*\.c.*warning:|rcu.*\.h.*warning:" < $T + cat $T/rcuwarnings exit 2 fi exit 0 -- cgit v0.10.2 From 6b80da42c02bc731ab38b6a37da5366abe26717f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 14:19:26 -0800 Subject: rcutorture: Use unsigned for Reader Batch computations The counter returned by the various ->completed functions is subject to overflow, which means that subtracting two such counters might result in overflow, which invokes undefined behavior in the C standard. This commit therefore changes these functions and variables to unsigned to avoid this undefined behavior. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 4d559ba..f43e351 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -244,7 +244,7 @@ struct rcu_torture_ops { int (*readlock)(void); void (*read_delay)(struct torture_random_state *rrsp); void (*readunlock)(int idx); - int (*completed)(void); + unsigned long (*completed)(void); void (*deferred_free)(struct rcu_torture *p); void (*sync)(void); void (*exp_sync)(void); @@ -296,7 +296,7 @@ static void rcu_torture_read_unlock(int idx) __releases(RCU) rcu_read_unlock(); } -static int rcu_torture_completed(void) +static unsigned long rcu_torture_completed(void) { return rcu_batches_completed(); } @@ -356,7 +356,7 @@ rcu_torture_cb(struct rcu_head *p) cur_ops->deferred_free(rp); } -static int rcu_no_completed(void) +static unsigned long rcu_no_completed(void) { return 0; } @@ -407,7 +407,7 @@ static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH) rcu_read_unlock_bh(); } -static int rcu_bh_torture_completed(void) +static unsigned long rcu_bh_torture_completed(void) { return rcu_batches_completed_bh(); } @@ -510,7 +510,7 @@ static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl) srcu_read_unlock(&srcu_ctl, idx); } -static int srcu_torture_completed(void) +static unsigned long srcu_torture_completed(void) { return srcu_batches_completed(&srcu_ctl); } @@ -1015,8 +1015,8 @@ static void rcutorture_trace_dump(void) static void rcu_torture_timer(unsigned long unused) { int idx; - int completed; - int completed_end; + unsigned long completed; + unsigned long completed_end; static DEFINE_TORTURE_RANDOM(rand); static DEFINE_SPINLOCK(rand_lock); struct rcu_torture *p; @@ -1073,8 +1073,8 @@ static void rcu_torture_timer(unsigned long unused) static int rcu_torture_reader(void *arg) { - int completed; - int completed_end; + unsigned long completed; + unsigned long completed_end; int idx; DEFINE_TORTURE_RANDOM(rand); struct rcu_torture *p; -- cgit v0.10.2 From c1fe9cde4ae904fffb5b4d975d0a37e99136ff50 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 15:45:27 -0800 Subject: rcu: Provide rcu_batches_completed_sched() for TINY_RCU A bug in rcutorture has caused it to ignore completed batches. In preparation for fixing that bug, this commit provides TINY_RCU with the required rcu_batches_completed_sched(). Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 91f7e4c..1ce2d6b 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -107,6 +107,14 @@ static inline unsigned long rcu_batches_completed_bh(void) return 0; } +/* + * Return the number of sched grace periods. + */ +static inline unsigned long rcu_batches_completed_sched(void) +{ + return 0; +} + static inline void rcu_force_quiescent_state(void) { } -- cgit v0.10.2 From 1e32eaee4c370afca20324f634bf47ae991cd240 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 16:04:34 -0800 Subject: rcutorture: Drop rcu_torture_completed() and friends Now that the return type of rcu_batches_completed() and friends matches that of the rcu_torture_ops structure's ->completed field, the wrapper functions can be deleted. This commit carries out that deletion, while also wiring "sched"'s ->completed field to rcu_batches_completed_sched(). Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index f43e351..aadbc07 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -296,11 +296,6 @@ static void rcu_torture_read_unlock(int idx) __releases(RCU) rcu_read_unlock(); } -static unsigned long rcu_torture_completed(void) -{ - return rcu_batches_completed(); -} - /* * Update callback in the pipe. This should be invoked after a grace period. */ @@ -377,7 +372,7 @@ static struct rcu_torture_ops rcu_ops = { .readlock = rcu_torture_read_lock, .read_delay = rcu_read_delay, .readunlock = rcu_torture_read_unlock, - .completed = rcu_torture_completed, + .completed = rcu_batches_completed, .deferred_free = rcu_torture_deferred_free, .sync = synchronize_rcu, .exp_sync = synchronize_rcu_expedited, @@ -407,11 +402,6 @@ static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH) rcu_read_unlock_bh(); } -static unsigned long rcu_bh_torture_completed(void) -{ - return rcu_batches_completed_bh(); -} - static void rcu_bh_torture_deferred_free(struct rcu_torture *p) { call_rcu_bh(&p->rtort_rcu, rcu_torture_cb); @@ -423,7 +413,7 @@ static struct rcu_torture_ops rcu_bh_ops = { .readlock = rcu_bh_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = rcu_bh_torture_read_unlock, - .completed = rcu_bh_torture_completed, + .completed = rcu_batches_completed_bh, .deferred_free = rcu_bh_torture_deferred_free, .sync = synchronize_rcu_bh, .exp_sync = synchronize_rcu_bh_expedited, @@ -600,7 +590,7 @@ static struct rcu_torture_ops sched_ops = { .readlock = sched_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = sched_torture_read_unlock, - .completed = rcu_no_completed, + .completed = rcu_batches_completed_sched, .deferred_free = rcu_sched_torture_deferred_free, .sync = synchronize_sched, .exp_sync = synchronize_sched_expedited, -- cgit v0.10.2 From f9103c390257d06c162d9e3c2a90d2bdedadfe17 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 16:48:20 -0800 Subject: rcu: Remove redundant rcu_batches_completed() declaration Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 1a07d73..69eb422 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -546,7 +546,6 @@ DECLARE_PER_CPU(char, rcu_cpu_has_work); /* Forward declarations for rcutree_plugin.h */ static void rcu_bootup_announce(void); -unsigned long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(void); static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU -- cgit v0.10.2 From 917963d0b30f9c4153c372c165178501d97b6b55 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Nov 2014 17:10:16 -0800 Subject: rcutorture: Check from beginning to end of grace period Currently, rcutorture's Reader Batch checks measure from the end of the previous grace period to the end of the current one. This commit tightens up these checks by measuring from the start and end of the same grace period. This involves adding rcu_batches_started() and friends corresponding to the existing rcu_batches_completed() and friends. We leave SRCU alone for the moment, as it does not yet have a way of tracking both ends of its grace periods. Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 1ce2d6b..9841921 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -92,7 +92,31 @@ static inline void rcu_virt_note_context_switch(int cpu) } /* - * Return the number of grace periods. + * Return the number of grace periods started. + */ +static inline unsigned long rcu_batches_started(void) +{ + return 0; +} + +/* + * Return the number of bottom-half grace periods started. + */ +static inline unsigned long rcu_batches_started_bh(void) +{ + return 0; +} + +/* + * Return the number of sched grace periods started. + */ +static inline unsigned long rcu_batches_started_sched(void) +{ + return 0; +} + +/* + * Return the number of grace periods completed. */ static inline unsigned long rcu_batches_completed(void) { @@ -100,7 +124,7 @@ static inline unsigned long rcu_batches_completed(void) } /* - * Return the number of bottom-half grace periods. + * Return the number of bottom-half grace periods completed. */ static inline unsigned long rcu_batches_completed_bh(void) { @@ -108,7 +132,7 @@ static inline unsigned long rcu_batches_completed_bh(void) } /* - * Return the number of sched grace periods. + * Return the number of sched grace periods completed. */ static inline unsigned long rcu_batches_completed_sched(void) { diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 9885bfb..c0dd124 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -81,6 +81,9 @@ void cond_synchronize_rcu(unsigned long oldstate); extern unsigned long rcutorture_testseq; extern unsigned long rcutorture_vernum; +unsigned long rcu_batches_started(void); +unsigned long rcu_batches_started_bh(void); +unsigned long rcu_batches_started_sched(void); unsigned long rcu_batches_completed(void); unsigned long rcu_batches_completed_bh(void); unsigned long rcu_batches_completed_sched(void); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index aadbc07..24142c2 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -244,6 +244,7 @@ struct rcu_torture_ops { int (*readlock)(void); void (*read_delay)(struct torture_random_state *rrsp); void (*readunlock)(int idx); + unsigned long (*started)(void); unsigned long (*completed)(void); void (*deferred_free)(struct rcu_torture *p); void (*sync)(void); @@ -372,6 +373,7 @@ static struct rcu_torture_ops rcu_ops = { .readlock = rcu_torture_read_lock, .read_delay = rcu_read_delay, .readunlock = rcu_torture_read_unlock, + .started = rcu_batches_started, .completed = rcu_batches_completed, .deferred_free = rcu_torture_deferred_free, .sync = synchronize_rcu, @@ -413,6 +415,7 @@ static struct rcu_torture_ops rcu_bh_ops = { .readlock = rcu_bh_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = rcu_bh_torture_read_unlock, + .started = rcu_batches_started_bh, .completed = rcu_batches_completed_bh, .deferred_free = rcu_bh_torture_deferred_free, .sync = synchronize_rcu_bh, @@ -456,6 +459,7 @@ static struct rcu_torture_ops rcu_busted_ops = { .readlock = rcu_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = rcu_torture_read_unlock, + .started = rcu_no_completed, .completed = rcu_no_completed, .deferred_free = rcu_busted_torture_deferred_free, .sync = synchronize_rcu_busted, @@ -554,6 +558,7 @@ static struct rcu_torture_ops srcu_ops = { .readlock = srcu_torture_read_lock, .read_delay = srcu_read_delay, .readunlock = srcu_torture_read_unlock, + .started = NULL, .completed = srcu_torture_completed, .deferred_free = srcu_torture_deferred_free, .sync = srcu_torture_synchronize, @@ -590,6 +595,7 @@ static struct rcu_torture_ops sched_ops = { .readlock = sched_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = sched_torture_read_unlock, + .started = rcu_batches_started_sched, .completed = rcu_batches_completed_sched, .deferred_free = rcu_sched_torture_deferred_free, .sync = synchronize_sched, @@ -628,6 +634,7 @@ static struct rcu_torture_ops tasks_ops = { .readlock = tasks_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = tasks_torture_read_unlock, + .started = rcu_no_completed, .completed = rcu_no_completed, .deferred_free = rcu_tasks_torture_deferred_free, .sync = synchronize_rcu_tasks, @@ -1005,8 +1012,8 @@ static void rcutorture_trace_dump(void) static void rcu_torture_timer(unsigned long unused) { int idx; + unsigned long started; unsigned long completed; - unsigned long completed_end; static DEFINE_TORTURE_RANDOM(rand); static DEFINE_SPINLOCK(rand_lock); struct rcu_torture *p; @@ -1014,7 +1021,10 @@ static void rcu_torture_timer(unsigned long unused) unsigned long long ts; idx = cur_ops->readlock(); - completed = cur_ops->completed(); + if (cur_ops->started) + started = cur_ops->started(); + else + started = cur_ops->completed(); ts = rcu_trace_clock_local(); p = rcu_dereference_check(rcu_torture_current, rcu_read_lock_bh_held() || @@ -1037,14 +1047,16 @@ static void rcu_torture_timer(unsigned long unused) /* Should not happen, but... */ pipe_count = RCU_TORTURE_PIPE_LEN; } - completed_end = cur_ops->completed(); + completed = cur_ops->completed(); if (pipe_count > 1) { do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts, - completed, completed_end); + started, completed); rcutorture_trace_dump(); } __this_cpu_inc(rcu_torture_count[pipe_count]); - completed = completed_end - completed; + completed = completed - started; + if (cur_ops->started) + completed++; if (completed > RCU_TORTURE_PIPE_LEN) { /* Should not happen, but... */ completed = RCU_TORTURE_PIPE_LEN; @@ -1063,8 +1075,8 @@ static void rcu_torture_timer(unsigned long unused) static int rcu_torture_reader(void *arg) { + unsigned long started; unsigned long completed; - unsigned long completed_end; int idx; DEFINE_TORTURE_RANDOM(rand); struct rcu_torture *p; @@ -1083,7 +1095,10 @@ rcu_torture_reader(void *arg) mod_timer(&t, jiffies + 1); } idx = cur_ops->readlock(); - completed = cur_ops->completed(); + if (cur_ops->started) + started = cur_ops->started(); + else + started = cur_ops->completed(); ts = rcu_trace_clock_local(); p = rcu_dereference_check(rcu_torture_current, rcu_read_lock_bh_held() || @@ -1104,14 +1119,16 @@ rcu_torture_reader(void *arg) /* Should not happen, but... */ pipe_count = RCU_TORTURE_PIPE_LEN; } - completed_end = cur_ops->completed(); + completed = cur_ops->completed(); if (pipe_count > 1) { do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, - ts, completed, completed_end); + ts, started, completed); rcutorture_trace_dump(); } __this_cpu_inc(rcu_torture_count[pipe_count]); - completed = completed_end - completed; + completed = completed - started; + if (cur_ops->started) + completed++; if (completed > RCU_TORTURE_PIPE_LEN) { /* Should not happen, but... */ completed = RCU_TORTURE_PIPE_LEN; diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index e26d787..c0faad5 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -315,7 +315,43 @@ static void force_quiescent_state(struct rcu_state *rsp); static int rcu_pending(void); /* - * Return the number of RCU-sched batches processed thus far for debug & stats. + * Return the number of RCU batches started thus far for debug & stats. + */ +unsigned long rcu_batches_started(void) +{ + return rcu_state_p->gpnum; +} +EXPORT_SYMBOL_GPL(rcu_batches_started); + +/* + * Return the number of RCU-sched batches started thus far for debug & stats. + */ +unsigned long rcu_batches_started_sched(void) +{ + return rcu_sched_state.gpnum; +} +EXPORT_SYMBOL_GPL(rcu_batches_started_sched); + +/* + * Return the number of RCU BH batches started thus far for debug & stats. + */ +unsigned long rcu_batches_started_bh(void) +{ + return rcu_bh_state.gpnum; +} +EXPORT_SYMBOL_GPL(rcu_batches_started_bh); + +/* + * Return the number of RCU batches completed thus far for debug & stats. + */ +unsigned long rcu_batches_completed(void) +{ + return rcu_state_p->completed; +} +EXPORT_SYMBOL_GPL(rcu_batches_completed); + +/* + * Return the number of RCU-sched batches completed thus far for debug & stats. */ unsigned long rcu_batches_completed_sched(void) { @@ -324,7 +360,7 @@ unsigned long rcu_batches_completed_sched(void) EXPORT_SYMBOL_GPL(rcu_batches_completed_sched); /* - * Return the number of RCU BH batches processed thus far for debug & stats. + * Return the number of RCU BH batches completed thus far for debug & stats. */ unsigned long rcu_batches_completed_bh(void) { diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index f69300d..07e61a0 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -114,25 +114,6 @@ static void __init rcu_bootup_announce(void) } /* - * Return the number of RCU-preempt batches processed thus far - * for debug and statistics. - */ -static unsigned long rcu_batches_completed_preempt(void) -{ - return rcu_preempt_state.completed; -} -EXPORT_SYMBOL_GPL(rcu_batches_completed_preempt); - -/* - * Return the number of RCU batches processed thus far for debug & stats. - */ -unsigned long rcu_batches_completed(void) -{ - return rcu_batches_completed_preempt(); -} -EXPORT_SYMBOL_GPL(rcu_batches_completed); - -/* * Record a preemptible-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is * not in a quiescent state. There might be any number of tasks blocked @@ -933,15 +914,6 @@ static void __init rcu_bootup_announce(void) } /* - * Return the number of RCU batches processed thus far for debug & stats. - */ -unsigned long rcu_batches_completed(void) -{ - return rcu_batches_completed_sched(); -} -EXPORT_SYMBOL_GPL(rcu_batches_completed); - -/* * Because preemptible RCU does not exist, we never have to check for * CPUs being in quiescent states. */ -- cgit v0.10.2 From 94162c8daa839bd0de791f66d754a880e2787c82 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 10 Dec 2014 17:42:16 -0800 Subject: rcutorture: Handle different mpstat versions The mpstat command recently added the %gnice column, which messes up the cpu2use.sh script's idle-CPU calculations. This commit therefore uses $NF instead of $12 to select the last (%idle) column. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/cpus2use.sh b/tools/testing/selftests/rcutorture/bin/cpus2use.sh index abe14b7..bb99cde 100755 --- a/tools/testing/selftests/rcutorture/bin/cpus2use.sh +++ b/tools/testing/selftests/rcutorture/bin/cpus2use.sh @@ -24,7 +24,7 @@ ncpus=`grep '^processor' /proc/cpuinfo | wc -l` idlecpus=`mpstat | tail -1 | \ - awk -v ncpus=$ncpus '{ print ncpus * ($7 + $12) / 100 }'` + awk -v ncpus=$ncpus '{ print ncpus * ($7 + $NF) / 100 }'` awk -v ncpus=$ncpus -v idlecpus=$idlecpus < /dev/null ' BEGIN { cpus2use = idlecpus; -- cgit v0.10.2 From 16c77ea7d0f4a74e49009aa2d26c275f7f93de7c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 10 Dec 2014 17:43:58 -0800 Subject: torture: Add "-enable-kvm -soundhw pcspk" to qemu command line More recent qemu implementations really want "-enable-kvm", and the "-soundhw pcspk" makes the script a bit less dependent on odd audio libraries being installed. This commit therefore adds both to the default qemu command line. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 8ca9f21..35b8532 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -8,9 +8,9 @@ # # Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args # -# qemu-args defaults to "-nographic", along with arguments specifying the -# number of CPUs and other options generated from -# the underlying CPU architecture. +# qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with +# arguments specifying the number of CPUs and other +# options generated from the underlying CPU architecture. # boot_args defaults to value returned by the per_version_boot_params # shell function. # @@ -138,7 +138,7 @@ then fi # Generate -smp qemu argument. -qemu_args="-nographic $qemu_args" +qemu_args="-enable-kvm -soundhw pcspk -nographic $qemu_args" cpu_count=`configNR_CPUS.sh $config_template` cpu_count=`configfrag_boot_cpus "$boot_args" "$config_template" "$cpu_count"` vcpus=`identify_qemu_vcpus` -- cgit v0.10.2 From d2f74b5b488dd2b283977f64844fee3ba91676db Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 11 Dec 2014 10:50:22 -0800 Subject: torture: Flag console.log file to prevent holdovers from earlier runs A system misconfiguration that prevents qemu from running at all (for example, a missing dynamically linked library) will keep the console.log file from the previous run. This can fool the developer into thinking that this failed run actually completed correctly. This commit therefore overwrites the console.log file just before launching qemu. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 35b8532..5236e07 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -168,6 +168,7 @@ then touch $resdir/buildonly exit 0 fi +echo "NOTE: $QEMU either did not run or was interactive" > $builddir/console.log echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd ( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & qemu_pid=$! -- cgit v0.10.2 From 7602de4af192b1527767538454557cb7564bae60 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 17 Dec 2014 18:39:54 -0800 Subject: rcutorture: Add more diagnostics in rcu_barrier() test failure case Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 24142c2..30d42aa 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1427,6 +1427,9 @@ static int rcu_torture_barrier(void *arg) cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */ if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) { n_rcu_torture_barrier_error++; + pr_err("barrier_cbs_invoked = %d, n_barrier_cbs = %d\n", + atomic_read(&barrier_cbs_invoked), + n_barrier_cbs); WARN_ON_ONCE(1); } n_barrier_successes++; -- cgit v0.10.2 From 624afe4dc9a08992b200046dfe8a61f19bab74ab Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Sat, 10 Jan 2015 13:02:22 +0100 Subject: ALSA: hda - fixup input_free_device called after input_unregister_device Input_unregister_device will internally free the device, so input_free_device should not be called. Reported-by: Dan Carpenter Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 09d2131..a50e15e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3548,7 +3548,6 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, break; case HDA_FIXUP_ACT_FREE: input_unregister_device(spec->kb_dev); - input_free_device(spec->kb_dev); spec->kb_dev = NULL; } #endif -- cgit v0.10.2 From 12c243b833c2c441f46dc592ab410fdccb5e056b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 10 Jan 2015 16:57:45 +0200 Subject: ALSA: fm801: remove FSF address The FSF address is subject to change. So, we remove it from the header. While here, remove a line with my old and non-functional email from the header. Moreover, nowadays we have a Git VCS that contains a history of changes. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 52555bda..1fdd92b6 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -2,8 +2,6 @@ * The driver for the ForteMedia FM801 based soundcards * Copyright (c) by Jaroslav Kysela * - * Support FM only card by Andy Shevchenko - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include -- cgit v0.10.2 From 51ad77ada1edc2c4096730820c45756cd8f112ad Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 16 Jan 2014 17:15:14 -0500 Subject: m68k/mvme16x: rtc - Don't use module_init in non-modular code The rtc.o is built for obj-y, i.e. always built in. It will never be modular, so using module_init as an alias for __initcall can be somewhat misleading. Fix this up now, so that we can relocate module_init from init.h into module.h in the future. If we don't do this, we'd have to add module.h to obviously non-modular code, and that would be a worse thing. Note that direct use of __initcall is discouraged, vs. one of the priority categorized subgroups. As __initcall gets mapped onto device_initcall, our use of device_initcall directly in this change means that the runtime impact is zero -- it will remain at level 6 in initcall ordering. Signed-off-by: Paul Gortmaker Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c index 6ef7a81..1755e2f 100644 --- a/arch/m68k/mvme16x/rtc.c +++ b/arch/m68k/mvme16x/rtc.c @@ -161,4 +161,4 @@ static int __init rtc_MK48T08_init(void) printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION); return misc_register(&rtc_dev); } -module_init(rtc_MK48T08_init); +device_initcall(rtc_MK48T08_init); -- cgit v0.10.2 From 23b94210267185db51f0be8d7115eb49b63b064b Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Thu, 1 Jan 2015 16:37:57 +0100 Subject: m68k/atari: atakeyb.c - Remove some unused functions Remove some functions that are not used anywhere: atari_kbd_leds() ikbd_exec() ikbd_mem_read() ikbd_mem_write() ikbd_clock_get() ikbd_clock_set() ikbd_pause() ikbd_resume() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 95022b0..ad91969 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -430,14 +430,6 @@ void ikbd_mouse_y0_top(void) } EXPORT_SYMBOL(ikbd_mouse_y0_top); -/* Resume */ -void ikbd_resume(void) -{ - static const char cmd[1] = { 0x11 }; - - ikbd_write(cmd, 1); -} - /* Disable mouse */ void ikbd_mouse_disable(void) { @@ -447,14 +439,6 @@ void ikbd_mouse_disable(void) } EXPORT_SYMBOL(ikbd_mouse_disable); -/* Pause output */ -void ikbd_pause(void) -{ - static const char cmd[1] = { 0x13 }; - - ikbd_write(cmd, 1); -} - /* Set joystick event reporting */ void ikbd_joystick_event_on(void) { @@ -502,56 +486,6 @@ void ikbd_joystick_disable(void) ikbd_write(cmd, 1); } -/* Time-of-day clock set */ -void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) -{ - char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; - - ikbd_write(cmd, 7); -} - -/* Interrogate time-of-day clock */ -void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) -{ - static const char cmd[1] = { 0x1C }; - - ikbd_write(cmd, 1); -} - -/* Memory load */ -void ikbd_mem_write(int address, int size, char *data) -{ - panic("Attempt to write data into keyboard memory"); -} - -/* Memory read */ -void ikbd_mem_read(int address, char data[6]) -{ - char cmd[3] = { 0x21, address>>8, address&0xFF }; - - ikbd_write(cmd, 3); - - /* receive data and put it in data */ -} - -/* Controller execute */ -void ikbd_exec(int address) -{ - char cmd[3] = { 0x22, address>>8, address&0xFF }; - - ikbd_write(cmd, 3); -} - -/* Status inquiries (0x87-0x9A) not yet implemented */ - -/* Set the state of the caps lock led. */ -void atari_kbd_leds(unsigned int leds) -{ - char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; - - ikbd_write(cmd, 6); -} - /* * The original code sometimes left the interrupt line of * the ACIAs low forever. I hope, it is fixed now. -- cgit v0.10.2 From a38eaa07a0ce4bdb5f79637fedefae276a567e72 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Thu, 1 Jan 2015 17:49:11 +0100 Subject: m68k/mvme147: config.c - Remove unused functions Remove the function mvme147_init_console_port() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist [geert: Also remove now unused m147_scc_write(), scc_write(), scc_delay()] Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 1bb3ce6..e6a3b56 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -168,49 +168,3 @@ int mvme147_set_clock_mmss (unsigned long nowtime) { return 0; } - -/*------------------- Serial console stuff ------------------------*/ - -static void scc_delay (void) -{ - int n; - volatile int trash; - - for (n = 0; n < 20; n++) - trash = n; -} - -static void scc_write (char ch) -{ - volatile char *p = (volatile char *)M147_SCC_A_ADDR; - - do { - scc_delay(); - } - while (!(*p & 4)); - scc_delay(); - *p = 8; - scc_delay(); - *p = ch; -} - - -void m147_scc_write (struct console *co, const char *str, unsigned count) -{ - unsigned long flags; - - local_irq_save(flags); - - while (count--) - { - if (*str == '\n') - scc_write ('\r'); - scc_write (*str++); - } - local_irq_restore(flags); -} - -void mvme147_init_console_port (struct console *co, int cflag) -{ - co->write = m147_scc_write; -} -- cgit v0.10.2 From 8c0ce284b320d2e6ef1a7c9a590d4fa44299c695 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 6 Jan 2015 08:49:52 +0100 Subject: m68k: Switch to asm-generic/futex.h As of commit 00f634bc522dedc8 ("asm-generic: add generic futex for !CONFIG_SMP") asm-generic follows the m68k futex implementation. Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index 9b6c691..1517ed1 100644 --- a/arch/m68k/include/asm/Kbuild +++ b/arch/m68k/include/asm/Kbuild @@ -6,6 +6,7 @@ generic-y += device.h generic-y += emergency-restart.h generic-y += errno.h generic-y += exec.h +generic-y += futex.h generic-y += hw_irq.h generic-y += ioctl.h generic-y += ipcbuf.h diff --git a/arch/m68k/include/asm/futex.h b/arch/m68k/include/asm/futex.h deleted file mode 100644 index bc868af..0000000 --- a/arch/m68k/include/asm/futex.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _ASM_M68K_FUTEX_H -#define _ASM_M68K_FUTEX_H - -#ifdef __KERNEL__ -#if !defined(CONFIG_MMU) -#include -#else /* CONFIG_MMU */ - -#include -#include -#include - -static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, - u32 oldval, u32 newval) -{ - u32 val; - - if (unlikely(get_user(val, uaddr) != 0)) - return -EFAULT; - - if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) - return -EFAULT; - - *uval = val; - - return 0; -} - -static inline int -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval, ret; - u32 tmp; - - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - pagefault_disable(); /* implies preempt_disable() */ - - ret = -EFAULT; - if (unlikely(get_user(oldval, uaddr) != 0)) - goto out_pagefault_enable; - - ret = 0; - tmp = oldval; - - switch (op) { - case FUTEX_OP_SET: - tmp = oparg; - break; - case FUTEX_OP_ADD: - tmp += oparg; - break; - case FUTEX_OP_OR: - tmp |= oparg; - break; - case FUTEX_OP_ANDN: - tmp &= ~oparg; - break; - case FUTEX_OP_XOR: - tmp ^= oparg; - break; - default: - ret = -ENOSYS; - } - - if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) - ret = -EFAULT; - -out_pagefault_enable: - pagefault_enable(); /* subsumes preempt_enable() */ - - if (ret == 0) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif /* CONFIG_MMU */ -#endif /* __KERNEL__ */ -#endif /* _ASM_M68K_FUTEX_H */ -- cgit v0.10.2 From 2e874d178c9e8cb048bfc1075ec0e93582c0e124 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 7 Jan 2015 11:17:35 +1100 Subject: m68k/mac: Fix scsi_type for Mac LC and similar models Designing Cards and Drivers for the Macintosh Family, 3rd ed. on page 310 says that the I/O address space for the Mac LC is $50F0 0000 - $50FF FFFF. The developer notes for the Classic II, LC III and IIvx/IIvi give the same I/O address space. That means I've assigned the wrong platform resources to those Mac models. Fix the scsi_type initialization for the affected models, to restore the SCSI base address to its value prior to Linux 3.18. Also rename MAC_SCSI_CCL as MAC_SCSI_LC for the sake of correct chronology. Signed-off-by: Finn Thain Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/include/asm/macintosh.h b/arch/m68k/include/asm/macintosh.h index 29c7c6c..42235e7 100644 --- a/arch/m68k/include/asm/macintosh.h +++ b/arch/m68k/include/asm/macintosh.h @@ -55,7 +55,7 @@ struct mac_model #define MAC_SCSI_QUADRA3 4 #define MAC_SCSI_IIFX 5 #define MAC_SCSI_DUO 6 -#define MAC_SCSI_CCL 7 +#define MAC_SCSI_LC 7 #define MAC_SCSI_LATE 8 #define MAC_IDE_NONE 0 diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index e9c3756..689b47d 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -296,7 +296,7 @@ static struct mac_model mac_data_table[] = { .name = "IIvi", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -305,7 +305,7 @@ static struct mac_model mac_data_table[] = { .name = "IIvx", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -320,7 +320,7 @@ static struct mac_model mac_data_table[] = { .name = "Classic II", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -329,7 +329,7 @@ static struct mac_model mac_data_table[] = { .name = "Color Classic", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -338,7 +338,7 @@ static struct mac_model mac_data_table[] = { .name = "Color Classic II", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -353,7 +353,7 @@ static struct mac_model mac_data_table[] = { .name = "LC", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -362,7 +362,7 @@ static struct mac_model mac_data_table[] = { .name = "LC II", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -371,7 +371,7 @@ static struct mac_model mac_data_table[] = { .name = "LC III", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -499,7 +499,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 460", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -526,7 +526,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 520", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -535,7 +535,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 550", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -567,7 +567,7 @@ static struct mac_model mac_data_table[] = { .name = "TV", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -576,7 +576,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 600", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -1109,8 +1109,10 @@ int __init mac_platform_init(void) platform_device_register_simple("mac_scsi", 0, mac_scsi_late_rsrc, ARRAY_SIZE(mac_scsi_late_rsrc)); break; - case MAC_SCSI_CCL: - /* Addresses from the Color Classic Developer Note. + case MAC_SCSI_LC: + /* Addresses from Mac LC data in Designing Cards & Drivers 3ed. + * Also from the Developer Notes for Classic II, LC III, + * Color Classic and IIvx. * $50F0 6000 - $50F0 7FFF: SCSI handshake * $50F1 0000 - $50F1 1FFF: SCSI * $50F1 2000 - $50F1 3FFF: SCSI DMA -- cgit v0.10.2 From ace79a3592bee97406c88c3d856e16b7f5720a39 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 11 Jan 2015 16:31:40 +0100 Subject: ALSA: ice1712: wm8766: Remove some unused functions Removes some functions that are not used anywhere: snd_wm8766_set_power() snd_wm8766_set_master_mode() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c index 21b373b..f7ac8d5 100644 --- a/sound/pci/ice1712/wm8766.c +++ b/sound/pci/ice1712/wm8766.c @@ -183,22 +183,6 @@ void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac) snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac); } -void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode) -{ - u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK; - - mode &= WM8766_DAC3_MSTR_MASK; - snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode); -} - -void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power) -{ - u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK; - - power &= WM8766_DAC3_POWER_MASK; - snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power); -} - void snd_wm8766_volume_restore(struct snd_wm8766 *wm) { u16 val = wm->regs[WM8766_REG_DACR1]; diff --git a/sound/pci/ice1712/wm8766.h b/sound/pci/ice1712/wm8766.h index c119f84..18c8d9d 100644 --- a/sound/pci/ice1712/wm8766.h +++ b/sound/pci/ice1712/wm8766.h @@ -155,8 +155,6 @@ struct snd_wm8766 { void snd_wm8766_init(struct snd_wm8766 *wm); void snd_wm8766_resume(struct snd_wm8766 *wm); void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac); -void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode); -void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power); void snd_wm8766_volume_restore(struct snd_wm8766 *wm); int snd_wm8766_build_controls(struct snd_wm8766 *wm); -- cgit v0.10.2 From e88af2f8de7914d311e66854eba2889710ee364e Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 11 Jan 2015 15:27:01 +0100 Subject: ata: libata-core: Remove unused function Remove the function ata_do_simple_cmd() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Tejun Heo diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5c84fb5..7cbcafa 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1752,33 +1752,6 @@ unsigned ata_exec_internal(struct ata_device *dev, } /** - * ata_do_simple_cmd - execute simple internal command - * @dev: Device to which the command is sent - * @cmd: Opcode to execute - * - * Execute a 'simple' command, that only consists of the opcode - * 'cmd' itself, without filling any other registers - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * Zero on success, AC_ERR_* mask on failure - */ -unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) -{ - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = cmd; - tf.flags |= ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - - return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); -} - -/** * ata_pio_need_iordy - check if iordy needed * @adev: ATA device * diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 5f4e0cc..82ebe26 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -76,7 +76,6 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, unsigned int n_elem, unsigned long timeout); -extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_wait_ready(struct ata_link *link, unsigned long deadline, int (*check_ready)(struct ata_link *link)); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, -- cgit v0.10.2 From 31c89c959667194350f496947b576c149503ce98 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 9 Jan 2015 07:43:45 -0800 Subject: pinctrl: pinconf-generic: Infer map type from DT property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the new 'groups' property, the DT parser can infer the map type from the fact whether 'pins' or 'groups' is used to specify the pin group to work on. To maintain backwards compatibitliy with current usage of the DT binding, this is only done when PIN_MAP_TYPE_INVALID is passed to the parsing function as type. Also, a new helper 'pinconf_generic_dt_node_to_map_all()' is introduced, which can be used by drivers as generic callback for dt_node_to_map() to leverage the new feature. Changes since v2: - rename dt_pin_specifier to subnode_target_type - add additional comment in header file explaining passing an invalid map type - mention map_all() helper in commit message Changes since RFC v2: - none Signed-off-by: Soren Brinkmann Tested-by: Andreas Färber Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index f78b416..21b3d90 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -264,6 +264,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned reserve; struct property *prop; const char *group; + const char *subnode_target_type = "pins"; ret = of_property_read_string(np, "function", &function); if (ret < 0) { @@ -284,10 +285,20 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, reserve++; if (num_configs) reserve++; + ret = of_property_count_strings(np, "pins"); if (ret < 0) { - dev_err(dev, "could not parse property pins\n"); - goto exit; + ret = of_property_count_strings(np, "groups"); + if (ret < 0) { + dev_err(dev, "could not parse property pins/groups\n"); + goto exit; + } + if (type == PIN_MAP_TYPE_INVALID) + type = PIN_MAP_TYPE_CONFIGS_GROUP; + subnode_target_type = "groups"; + } else { + if (type == PIN_MAP_TYPE_INVALID) + type = PIN_MAP_TYPE_CONFIGS_PIN; } reserve *= ret; @@ -296,7 +307,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "pins", prop, group) { + of_property_for_each_string(np, subnode_target_type, prop, group) { if (function) { ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, group, diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index d578a60..83c89f5 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -174,6 +174,17 @@ static inline int pinconf_generic_dt_node_to_map_pin( PIN_MAP_TYPE_CONFIGS_PIN); } +static inline int pinconf_generic_dt_node_to_map_all( + struct pinctrl_dev *pctldev, struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + /* + * passing the type as PIN_MAP_TYPE_INVALID causes the underlying parser + * to infer the map type from the DT properties used. + */ + return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps, + PIN_MAP_TYPE_INVALID); +} #endif #endif /* CONFIG_GENERIC_PINCONF */ -- cgit v0.10.2 From dd4d01f7bad886c22687224bc7070b87de8deb51 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 9 Jan 2015 07:43:46 -0800 Subject: pinctrl: pinconf-generic: Allow driver to specify DT params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Additionally to the generic DT parameters, allow drivers to provide driver-specific DT parameters to be used with the generic parser infrastructure. To achieve this 'struct pinctrl_desc' is extended to pass custom pinconf option to the core. In order to pass this kind of information, the related data structures - 'struct pinconf_generic_dt_params', 'pin_config_item' - are moved from pinconf internals to the pinconf-generic header. Additionally pinconfg-generic is refactored to not only iterate over the generic pinconf parameters but also take the parameters into account that are provided through the driver's 'struct pinctrl_desc'. In particular 'pinconf_generic_parse_dt_config()' and 'pinconf_generic_dump' helpers are split into two parts each. In order to have a more generic helper that can be used to process the generic parameters as well as the driver-specific ones. v2: - fix typo - add missing documentation for @conf_items member in struct - rebase to pinctrl/devel: conflict in abx500 - rename _pinconf_generic_dump() to pinconf_generic_dump_one() - removed '_' from _parse_dt_cfg() - removed BUG_ONs, error condition is handled in if statements - removed pinconf_generic_dump_group() & pinconf_generic_dump_pin helpers - fixed up corresponding call sites - renamed pinconf_generic_dump() to pinconf_generic_dump_pins() - added kernel-doc to pinconf_generic_dump_pins() - add kernel-doc - more verbose commit message Signed-off-by: Soren Brinkmann Tested-by: Andreas Färber Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 3d6d972..1806b24 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -914,7 +914,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, } } - ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs); + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &nconfigs); if (nconfigs) { const char *gpio_name; const char *pin; diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 21b3d90..e088666 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -27,17 +27,6 @@ #include "pinctrl-utils.h" #ifdef CONFIG_DEBUG_FS - -struct pin_config_item { - const enum pin_config_param param; - const char * const display; - const char * const format; - bool has_arg; -}; - -#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \ - .has_arg = d } - static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), @@ -60,22 +49,25 @@ static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true), }; -void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, - struct seq_file *s, unsigned pin) +static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, + struct seq_file *s, const char *gname, + unsigned pin, + const struct pin_config_item *items, + int nitems) { - const struct pinconf_ops *ops = pctldev->desc->confops; int i; - if (!ops->is_generic) - return; - - for (i = 0; i < ARRAY_SIZE(conf_items); i++) { + for (i = 0; i < nitems; i++) { unsigned long config; int ret; /* We want to check out this parameter */ - config = pinconf_to_config_packed(conf_items[i].param, 0); - ret = pin_config_get_for_pin(pctldev, pin, &config); + config = pinconf_to_config_packed(items[i].param, 0); + if (gname) + ret = pin_config_group_get(dev_name(pctldev->dev), + gname, &config); + else + ret = pin_config_get_for_pin(pctldev, pin, &config); /* These are legal errors */ if (ret == -EINVAL || ret == -ENOTSUPP) continue; @@ -85,56 +77,46 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, } /* Space between multiple configs */ seq_puts(s, " "); - seq_puts(s, conf_items[i].display); + seq_puts(s, items[i].display); /* Print unit if available */ - if (conf_items[i].has_arg) { + if (items[i].has_arg) { seq_printf(s, " (%u", pinconf_to_config_argument(config)); - if (conf_items[i].format) - seq_printf(s, " %s)", conf_items[i].format); + if (items[i].format) + seq_printf(s, " %s)", items[i].format); else seq_puts(s, ")"); } } } -void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, - struct seq_file *s, const char *gname) +/** + * pinconf_generic_dump_pins - Print information about pin or group of pins + * @pctldev: Pincontrol device + * @s: File to print to + * @gname: Group name specifying pins + * @pin: Pin number specyfying pin + * + * Print the pinconf configuration for the requested pin(s) to @s. Pins can be + * specified either by pin using @pin or by group using @gname. Only one needs + * to be specified the other can be NULL/0. + */ +void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s, + const char *gname, unsigned pin) { const struct pinconf_ops *ops = pctldev->desc->confops; - int i; if (!ops->is_generic) return; - for (i = 0; i < ARRAY_SIZE(conf_items); i++) { - unsigned long config; - int ret; - - /* We want to check out this parameter */ - config = pinconf_to_config_packed(conf_items[i].param, 0); - ret = pin_config_group_get(dev_name(pctldev->dev), gname, - &config); - /* These are legal errors */ - if (ret == -EINVAL || ret == -ENOTSUPP) - continue; - if (ret) { - seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); - continue; - } - /* Space between multiple configs */ - seq_puts(s, " "); - seq_puts(s, conf_items[i].display); - /* Print unit if available */ - if (conf_items[i].has_arg) { - seq_printf(s, " (%u", - pinconf_to_config_argument(config)); - if (conf_items[i].format) - seq_printf(s, " %s)", conf_items[i].format); - else - seq_puts(s, ")"); - } - } + /* generic parameters */ + pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items, + ARRAY_SIZE(conf_items)); + /* driver-specific parameters */ + if (pctldev->desc->num_dt_params && pctldev->desc->conf_items) + pinconf_generic_dump_one(pctldev, s, gname, pin, + pctldev->desc->conf_items, + pctldev->desc->num_dt_params); } void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, @@ -148,17 +130,21 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, seq_printf(s, "%s: 0x%x", conf_items[i].display, pinconf_to_config_argument(config)); } + + if (!pctldev->desc->num_dt_params || !pctldev->desc->conf_items) + return; + + for (i = 0; i < pctldev->desc->num_dt_params; i++) { + if (pinconf_to_config_param(config) != pctldev->desc->conf_items[i].param) + continue; + seq_printf(s, "%s: 0x%x", pctldev->desc->conf_items[i].display, + pinconf_to_config_argument(config)); + } } EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); #endif #ifdef CONFIG_OF -struct pinconf_generic_dt_params { - const char * const property; - enum pin_config_param param; - u32 default_value; -}; - static const struct pinconf_generic_dt_params dt_params[] = { { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, @@ -184,6 +170,47 @@ static const struct pinconf_generic_dt_params dt_params[] = { }; /** + * parse_dt_cfg - Parse DT pinconf parameters + * @np: DT node + * @params: Array of describing DT parameters + * @count: Number of entries in @params + * @cfg: Array of parsed config options + * @ncfg: Number of entries in @cfg + * + * Parse the config options described in @params from @np and puts the result + * in @cfg. @cfg does not need to be empty, entries are added beggining at + * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg + * needs to have enough memory allocated to hold all possible entries. + */ +static void parse_dt_cfg(struct device_node *np, + const struct pinconf_generic_dt_params *params, + unsigned int count, unsigned long *cfg, + unsigned int *ncfg) +{ + int i; + + for (i = 0; i < count; i++) { + u32 val; + int ret; + const struct pinconf_generic_dt_params *par = ¶ms[i]; + + ret = of_property_read_u32(np, par->property, &val); + + /* property not found */ + if (ret == -EINVAL) + continue; + + /* use default value, when no value is specified */ + if (ret) + val = par->default_value; + + pr_debug("found %s with value %u\n", par->property, val); + cfg[*ncfg] = pinconf_to_config_packed(par->param, val); + (*ncfg)++; + } +} + +/** * pinconf_generic_parse_dt_config() * parse the config properties into generic pinconfig values. * @np: node containing the pinconfig properties @@ -191,39 +218,29 @@ static const struct pinconf_generic_dt_params dt_params[] = { * @nconfigs: umber of configurations */ int pinconf_generic_parse_dt_config(struct device_node *np, + struct pinctrl_dev *pctldev, unsigned long **configs, unsigned int *nconfigs) { unsigned long *cfg; - unsigned int ncfg = 0; + unsigned int max_cfg, ncfg = 0; int ret; - int i; - u32 val; if (!np) return -EINVAL; /* allocate a temporary array big enough to hold one of each option */ - cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL); + max_cfg = ARRAY_SIZE(dt_params); + if (pctldev) + max_cfg += pctldev->desc->num_dt_params; + cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dt_params); i++) { - const struct pinconf_generic_dt_params *par = &dt_params[i]; - ret = of_property_read_u32(np, par->property, &val); - - /* property not found */ - if (ret == -EINVAL) - continue; - - /* use default value, when no value is specified */ - if (ret) - val = par->default_value; - - pr_debug("found %s with value %u\n", par->property, val); - cfg[ncfg] = pinconf_to_config_packed(par->param, val); - ncfg++; - } + parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg); + if (pctldev && pctldev->desc->num_dt_params && pctldev->desc->params) + parse_dt_cfg(np, pctldev->desc->params, + pctldev->desc->num_dt_params, cfg, &ncfg); ret = 0; @@ -274,7 +291,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, function = NULL; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); if (ret < 0) { dev_err(dev, "could not parse node property\n"); return ret; diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 8bfa064..1fc09dc 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -288,7 +288,7 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev, const struct pinconf_ops *ops = pctldev->desc->confops; /* no-op when not using generic pin config */ - pinconf_generic_dump_pin(pctldev, s, pin); + pinconf_generic_dump_pins(pctldev, s, NULL, pin); if (ops && ops->pin_config_dbg_show) ops->pin_config_dbg_show(pctldev, s, pin); } @@ -333,7 +333,7 @@ static void pinconf_dump_group(struct pinctrl_dev *pctldev, const struct pinconf_ops *ops = pctldev->desc->confops; /* no-op when not using generic pin config */ - pinconf_generic_dump_group(pctldev, s, gname); + pinconf_generic_dump_pins(pctldev, s, gname, 0); if (ops && ops->pin_config_group_dbg_show) ops->pin_config_group_dbg_show(pctldev, s, selector); } diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index a4a5417..55c7578 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -92,26 +92,17 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot, #if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS) -void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, - struct seq_file *s, unsigned pin); - -void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, - struct seq_file *s, const char *gname); +void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, + struct seq_file *s, const char *gname, + unsigned pin); void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned long config); #else -static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, - struct seq_file *s, - unsigned pin) -{ - return; -} - -static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, - struct seq_file *s, - const char *gname) +static inline void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, + struct seq_file *s, + const char *gname, unsigned pin) { return; } @@ -126,6 +117,7 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, #if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF) int pinconf_generic_parse_dt_config(struct device_node *np, + struct pinctrl_dev *pctldev, unsigned long **configs, unsigned int *nconfigs); #endif diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index ba74f0a..7625f33 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1140,7 +1140,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, return -EINVAL; np_config = of_find_node_by_phandle(be32_to_cpup(phandle)); - ret = pinconf_generic_parse_dt_config(np_config, + ret = pinconf_generic_parse_dt_config(np_config, NULL, &grp->data[j].configs, &grp->data[j].nconfigs); if (ret) return ret; diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c index 146e48a..fab6aaf 100644 --- a/drivers/pinctrl/pinctrl-tz1090-pdc.c +++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c @@ -415,7 +415,7 @@ static int tz1090_pdc_pinctrl_dt_subnode_to_map(struct device *dev, function = NULL; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); if (ret) return ret; diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c index df8cb1e..8bd73075 100644 --- a/drivers/pinctrl/pinctrl-tz1090.c +++ b/drivers/pinctrl/pinctrl-tz1090.c @@ -1131,7 +1131,7 @@ static int tz1090_pinctrl_dt_subnode_to_map(struct device *dev, function = NULL; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); if (ret) return ret; diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 910deae..072e7c6 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -122,7 +122,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, return ret; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); if (ret < 0) return ret; diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 83c89f5..342409f 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -115,6 +115,18 @@ enum pin_config_param { PIN_CONFIG_END = 0x7FFF, }; +#ifdef CONFIG_DEBUG_FS +#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \ + .has_arg = d } + +struct pin_config_item { + const enum pin_config_param param; + const char * const display; + const char * const format; + bool has_arg; +}; +#endif /* CONFIG_DEBUG_FS */ + /* * Helpful configuration macro to be used in tables etc. */ @@ -150,6 +162,12 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param struct pinctrl_dev; struct pinctrl_map; +struct pinconf_generic_dt_params { + const char * const property; + enum pin_config_param param; + u32 default_value; +}; + int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned *reserved_maps, unsigned *num_maps, diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index cc8e1af..c58b3e1 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -24,6 +24,7 @@ struct pinctrl_dev; struct pinctrl_map; struct pinmux_ops; struct pinconf_ops; +struct pin_config_item; struct gpio_chip; struct device_node; @@ -117,6 +118,9 @@ struct pinctrl_ops { * @confops: pin config operations vtable, if you support pin configuration in * your driver * @owner: module providing the pin controller, used for refcounting + * @num_dt_params: Number of driver-specific DT parameters + * @params: List of DT parameters + * @conf_items: Information how to print @params in debugfs */ struct pinctrl_desc { const char *name; @@ -126,6 +130,11 @@ struct pinctrl_desc { const struct pinmux_ops *pmxops; const struct pinconf_ops *confops; struct module *owner; +#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF) + unsigned int num_dt_params; + const struct pinconf_generic_dt_params *params; + const struct pin_config_item *conf_items; +#endif }; /* External interface to pin controller */ -- cgit v0.10.2 From da085a86732e351503ca8264b146343faaf20660 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 9 Jan 2015 07:43:47 -0800 Subject: pinctrl: zynq: Document DT binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation for the devicetree binding for the Zynq pincontroller. Changes since v1: - fix typo - add USB related documentation - remove 'pinctrl-' prefix for pinctrl sub-nodes - update documentation to enforce strict separation of pinmux and pinconf nodes - update example accordingly Signed-off-by: Soren Brinkmann Tested-by: Andreas Färber Signed-off-by: Linus Walleij diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt new file mode 100644 index 0000000..b7b55a9 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt @@ -0,0 +1,104 @@ + Binding for Xilinx Zynq Pinctrl + +Required properties: +- compatible: "xlnx,zynq-pinctrl" +- syscon: phandle to SLCR +- reg: Offset and length of pinctrl space in SLCR + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Zynq's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, slew rate, etc. + +Each configuration node can consist of multiple nodes describing the pinmux and +pinconf options. Those nodes can be pinmux nodes or pinconf nodes. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Required properties for pinmux nodes are: + - groups: A list of pinmux groups. + - function: The name of a pinmux function to activate for the specified set + of groups. + +Required properties for configuration nodes: +One of: + - pins: a list of pin names + - groups: A list of pinmux groups. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinmux subnode: + groups, function + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinconf subnode: + groups, pins, bias-disable, bias-high-impedance, bias-pull-up, slew-rate, + low-power-disable, low-power-enable + + Valid arguments for 'slew-rate' are '0' and '1' to select between slow and fast + respectively. + + Valid values for groups are: + ethernet0_0_grp, ethernet1_0_grp, mdio0_0_grp, mdio1_0_grp, + qspi0_0_grp, qspi1_0_grp, qspi_fbclk, qspi_cs1_grp, spi0_0_grp, + spi0_1_grp - spi0_2_grp, spi1_0_grp - spi1_3_grp, sdio0_0_grp - sdio0_2_grp, + sdio1_0_grp - sdio1_3_grp, sdio0_emio_wp, sdio0_emio_cd, sdio1_emio_wp, + sdio1_emio_cd, smc0_nor, smc0_nor_cs1_grp, smc0_nor_addr25_grp, smc0_nand, + can0_0_grp - can0_10_grp, can1_0_grp - can1_11_grp, uart0_0_grp - uart0_10_grp, + uart1_0_grp - uart1_11_grp, i2c0_0_grp - i2c0_10_grp, i2c1_0_grp - i2c1_10_grp, + ttc0_0_grp - ttc0_2_grp, ttc1_0_grp - ttc1_2_grp, swdt0_0_grp - swdt0_4_grp, + gpio0_0_grp - gpio0_53_grp, usb0_0_grp, usb1_0_grp + + Valid values for pins are: + MIO0 - MIO53 + + Valid values for function are: + ethernet0, ethernet1, mdio0, mdio1, qspi0, qspi1, qspi_fbclk, qspi_cs1, + spi0, spi1, sdio0, sdio0_pc, sdio0_cd, sdio0_wp, + sdio1, sdio1_pc, sdio1_cd, sdio1_wp, + smc0_nor, smc0_nor_cs1, smc0_nor_addr25, smc0_nand, can0, can1, uart0, uart1, + i2c0, i2c1, ttc0, ttc1, swdt0, gpio0, usb0, usb1 + +The following driver-specific properties as defined here are valid to specify in +a pin configuration subnode: + - io-standard: Configure the pin to use the selected IO standard according to + this mapping: + 1: LVCMOS18 + 2: LVCMOS25 + 3: LVCMOS33 + 4: HSTL + +Example: + pinctrl0: pinctrl@700 { + compatible = "xlnx,pinctrl-zynq"; + reg = <0x700 0x200>; + syscon = <&slcr>; + + pinctrl_uart1_default: uart1-default { + mux { + groups = "uart1_10_grp"; + function = "uart1"; + }; + + conf { + groups = "uart1_10_grp"; + slew-rate = <0>; + io-standard = <1>; + }; + + conf-rx { + pins = "MIO49"; + bias-high-impedance; + }; + + conf-tx { + pins = "MIO48"; + bias-disable; + }; + }; + }; -- cgit v0.10.2 From add958cee967df0a6d003e59b104ba9a6f263e00 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Fri, 9 Jan 2015 07:43:48 -0800 Subject: pinctrl: Add driver for Zynq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a pin-control driver for Zynq. Changes since v2: - driver-specific DT properties are passed to the core in two arrays, one for the actual DT parsing one for the debugfs representation. Issue a compiler warning when the number of entries is not the same for both arrays. Changes since v1: - fix EMIO_SD1_CD pin name - add USB to pinmux options changes since RFCv2: - let Zynq select PINCTRL_ZYNQ. Boot hangs when pinctrl information is present in DT but no driver available. - add #defines to get rid of magical constants - add commas at end of initializers - separate changes in mach-zynq in separate patch - add driver specific io-standard DT property - refactored pinconf set function to not require arguments for argument-less properties - squash other patches in - support for IO-standard property - support for low-power mode property - migration to pinconf_generic_dt_node_to_map_all() - use newly created infrastructure to add pass driver-specific DT params to pinconf-generic changes since RFC: - use syscon/regmap to access registers in SLCR space - rebase to 3.18: rename enable -> set_mux - add kernel-doc - support pinconf - supported attributes - pin-bias: pull up, tristate, disable - slew-rate: 0 == slow, 1 == fast; generic pinconf does not display argument Signed-off-by: Soren Brinkmann Tested-by: Andreas Färber Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d014f22..67c8db9 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -191,6 +191,14 @@ config PINCTRL_PALMAS open drain configuration for the Palmas series devices like TPS65913, TPS80036 etc. +config PINCTRL_ZYNQ + bool "Pinctrl driver for Xilinx Zynq" + depends on ARCH_ZYNQ + select PINMUX + select GENERIC_PINCONF + help + This selectes the pinctrl driver for Xilinx Zynq. + source "drivers/pinctrl/berlin/Kconfig" source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index c7139ba..6c28bd6 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o +obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c new file mode 100644 index 0000000..6253423 --- /dev/null +++ b/drivers/pinctrl/pinctrl-zynq.c @@ -0,0 +1,1176 @@ +/* + * Zynq pin controller + * + * Copyright (C) 2014 Xilinx + * + * Sören Brinkmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-utils.h" +#include "core.h" + +#define ZYNQ_NUM_MIOS 54 + +#define ZYNQ_PCTRL_MIO_MST_TRI0 0x10c +#define ZYNQ_PCTRL_MIO_MST_TRI1 0x110 + +#define ZYNQ_PINMUX_MUX_SHIFT 1 +#define ZYNQ_PINMUX_MUX_MASK (0x7f << ZYNQ_PINMUX_MUX_SHIFT) + +/** + * struct zynq_pinctrl - driver data + * @pctrl: Pinctrl device + * @syscon: Syscon regmap + * @pctrl_offset: Offset for pinctrl into the @syscon space + * @groups: Pingroups + * @ngroupos: Number of @groups + * @funcs: Pinmux functions + * @nfuncs: Number of @funcs + */ +struct zynq_pinctrl { + struct pinctrl_dev *pctrl; + struct regmap *syscon; + u32 pctrl_offset; + const struct zynq_pctrl_group *groups; + unsigned int ngroups; + const struct zynq_pinmux_function *funcs; + unsigned int nfuncs; +}; + +struct zynq_pctrl_group { + const char *name; + const unsigned int *pins; + const unsigned npins; +}; + +/** + * struct zynq_pinmux_function - a pinmux function + * @name: Name of the pinmux function. + * @groups: List of pingroups for this function. + * @ngroups: Number of entries in @groups. + * @mux_val: Selector for this function + * @mux: Offset of function specific mux + * @mux_mask: Mask for function specific selector + * @mux_shift: Shift for function specific selector + */ +struct zynq_pinmux_function { + const char *name; + const char * const *groups; + unsigned int ngroups; + unsigned int mux_val; + u32 mux; + u32 mux_mask; + u8 mux_shift; +}; + +enum zynq_pinmux_functions { + ZYNQ_PMUX_can0, + ZYNQ_PMUX_can1, + ZYNQ_PMUX_ethernet0, + ZYNQ_PMUX_ethernet1, + ZYNQ_PMUX_gpio0, + ZYNQ_PMUX_i2c0, + ZYNQ_PMUX_i2c1, + ZYNQ_PMUX_mdio0, + ZYNQ_PMUX_mdio1, + ZYNQ_PMUX_qspi0, + ZYNQ_PMUX_qspi1, + ZYNQ_PMUX_qspi_fbclk, + ZYNQ_PMUX_qspi_cs1, + ZYNQ_PMUX_spi0, + ZYNQ_PMUX_spi1, + ZYNQ_PMUX_sdio0, + ZYNQ_PMUX_sdio0_pc, + ZYNQ_PMUX_sdio0_cd, + ZYNQ_PMUX_sdio0_wp, + ZYNQ_PMUX_sdio1, + ZYNQ_PMUX_sdio1_pc, + ZYNQ_PMUX_sdio1_cd, + ZYNQ_PMUX_sdio1_wp, + ZYNQ_PMUX_smc0_nor, + ZYNQ_PMUX_smc0_nor_cs1, + ZYNQ_PMUX_smc0_nor_addr25, + ZYNQ_PMUX_smc0_nand, + ZYNQ_PMUX_ttc0, + ZYNQ_PMUX_ttc1, + ZYNQ_PMUX_uart0, + ZYNQ_PMUX_uart1, + ZYNQ_PMUX_usb0, + ZYNQ_PMUX_usb1, + ZYNQ_PMUX_swdt0, + ZYNQ_PMUX_MAX_FUNC +}; + +const struct pinctrl_pin_desc zynq_pins[] = { + PINCTRL_PIN(0, "MIO0"), + PINCTRL_PIN(1, "MIO1"), + PINCTRL_PIN(2, "MIO2"), + PINCTRL_PIN(3, "MIO3"), + PINCTRL_PIN(4, "MIO4"), + PINCTRL_PIN(5, "MIO5"), + PINCTRL_PIN(6, "MIO6"), + PINCTRL_PIN(7, "MIO7"), + PINCTRL_PIN(8, "MIO8"), + PINCTRL_PIN(9, "MIO9"), + PINCTRL_PIN(10, "MIO10"), + PINCTRL_PIN(11, "MIO11"), + PINCTRL_PIN(12, "MIO12"), + PINCTRL_PIN(13, "MIO13"), + PINCTRL_PIN(14, "MIO14"), + PINCTRL_PIN(15, "MIO15"), + PINCTRL_PIN(16, "MIO16"), + PINCTRL_PIN(17, "MIO17"), + PINCTRL_PIN(18, "MIO18"), + PINCTRL_PIN(19, "MIO19"), + PINCTRL_PIN(20, "MIO20"), + PINCTRL_PIN(21, "MIO21"), + PINCTRL_PIN(22, "MIO22"), + PINCTRL_PIN(23, "MIO23"), + PINCTRL_PIN(24, "MIO24"), + PINCTRL_PIN(25, "MIO25"), + PINCTRL_PIN(26, "MIO26"), + PINCTRL_PIN(27, "MIO27"), + PINCTRL_PIN(28, "MIO28"), + PINCTRL_PIN(29, "MIO29"), + PINCTRL_PIN(30, "MIO30"), + PINCTRL_PIN(31, "MIO31"), + PINCTRL_PIN(32, "MIO32"), + PINCTRL_PIN(33, "MIO33"), + PINCTRL_PIN(34, "MIO34"), + PINCTRL_PIN(35, "MIO35"), + PINCTRL_PIN(36, "MIO36"), + PINCTRL_PIN(37, "MIO37"), + PINCTRL_PIN(38, "MIO38"), + PINCTRL_PIN(39, "MIO39"), + PINCTRL_PIN(40, "MIO40"), + PINCTRL_PIN(41, "MIO41"), + PINCTRL_PIN(42, "MIO42"), + PINCTRL_PIN(43, "MIO43"), + PINCTRL_PIN(44, "MIO44"), + PINCTRL_PIN(45, "MIO45"), + PINCTRL_PIN(46, "MIO46"), + PINCTRL_PIN(47, "MIO47"), + PINCTRL_PIN(48, "MIO48"), + PINCTRL_PIN(49, "MIO49"), + PINCTRL_PIN(50, "MIO50"), + PINCTRL_PIN(51, "MIO51"), + PINCTRL_PIN(52, "MIO52"), + PINCTRL_PIN(53, "MIO53"), + PINCTRL_PIN(54, "EMIO_SD0_WP"), + PINCTRL_PIN(55, "EMIO_SD0_CD"), + PINCTRL_PIN(56, "EMIO_SD1_WP"), + PINCTRL_PIN(57, "EMIO_SD1_CD"), +}; + +/* pin groups */ +static const unsigned int ethernet0_0_pins[] = {16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27}; +static const unsigned int ethernet1_0_pins[] = {28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39}; +static const unsigned int mdio0_0_pins[] = {52, 53}; +static const unsigned int mdio1_0_pins[] = {52, 53}; +static const unsigned int qspi0_0_pins[] = {1, 2, 3, 4, 5, 6}; + +static const unsigned int qspi1_0_pins[] = {9, 10, 11, 12, 13}; +static const unsigned int qspi_cs1_pins[] = {0}; +static const unsigned int qspi_fbclk_pins[] = {8}; +static const unsigned int spi0_0_pins[] = {16, 17, 18, 19, 20, 21}; +static const unsigned int spi0_1_pins[] = {28, 29, 30, 31, 32, 33}; +static const unsigned int spi0_2_pins[] = {40, 41, 42, 43, 44, 45}; +static const unsigned int spi1_0_pins[] = {10, 11, 12, 13, 14, 15}; +static const unsigned int spi1_1_pins[] = {22, 23, 24, 25, 26, 27}; +static const unsigned int spi1_2_pins[] = {34, 35, 36, 37, 38, 39}; +static const unsigned int spi1_3_pins[] = {46, 47, 48, 49, 40, 51}; +static const unsigned int sdio0_0_pins[] = {16, 17, 18, 19, 20, 21}; +static const unsigned int sdio0_1_pins[] = {28, 29, 30, 31, 32, 33}; +static const unsigned int sdio0_2_pins[] = {40, 41, 42, 43, 44, 45}; +static const unsigned int sdio1_0_pins[] = {10, 11, 12, 13, 14, 15}; +static const unsigned int sdio1_1_pins[] = {22, 23, 24, 25, 26, 27}; +static const unsigned int sdio1_2_pins[] = {34, 35, 36, 37, 38, 39}; +static const unsigned int sdio1_3_pins[] = {46, 47, 48, 49, 40, 51}; +static const unsigned int sdio0_emio_wp_pins[] = {54}; +static const unsigned int sdio0_emio_cd_pins[] = {55}; +static const unsigned int sdio1_emio_wp_pins[] = {56}; +static const unsigned int sdio1_emio_cd_pins[] = {57}; +static const unsigned int smc0_nor_pins[] = {0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39}; +static const unsigned int smc0_nor_cs1_pins[] = {1}; +static const unsigned int smc0_nor_addr25_pins[] = {1}; +static const unsigned int smc0_nand_pins[] = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 16, 17, 18, 19, 20, + 21, 22, 23}; +/* Note: CAN MIO clock inputs are modeled in the clock framework */ +static const unsigned int can0_0_pins[] = {10, 11}; +static const unsigned int can0_1_pins[] = {14, 15}; +static const unsigned int can0_2_pins[] = {18, 19}; +static const unsigned int can0_3_pins[] = {22, 23}; +static const unsigned int can0_4_pins[] = {26, 27}; +static const unsigned int can0_5_pins[] = {30, 31}; +static const unsigned int can0_6_pins[] = {34, 35}; +static const unsigned int can0_7_pins[] = {38, 39}; +static const unsigned int can0_8_pins[] = {42, 43}; +static const unsigned int can0_9_pins[] = {46, 47}; +static const unsigned int can0_10_pins[] = {50, 51}; +static const unsigned int can1_0_pins[] = {8, 9}; +static const unsigned int can1_1_pins[] = {12, 13}; +static const unsigned int can1_2_pins[] = {16, 17}; +static const unsigned int can1_3_pins[] = {20, 21}; +static const unsigned int can1_4_pins[] = {24, 25}; +static const unsigned int can1_5_pins[] = {28, 29}; +static const unsigned int can1_6_pins[] = {32, 33}; +static const unsigned int can1_7_pins[] = {36, 37}; +static const unsigned int can1_8_pins[] = {40, 41}; +static const unsigned int can1_9_pins[] = {44, 45}; +static const unsigned int can1_10_pins[] = {48, 49}; +static const unsigned int can1_11_pins[] = {52, 53}; +static const unsigned int uart0_0_pins[] = {10, 11}; +static const unsigned int uart0_1_pins[] = {14, 15}; +static const unsigned int uart0_2_pins[] = {18, 19}; +static const unsigned int uart0_3_pins[] = {22, 23}; +static const unsigned int uart0_4_pins[] = {26, 27}; +static const unsigned int uart0_5_pins[] = {30, 31}; +static const unsigned int uart0_6_pins[] = {34, 35}; +static const unsigned int uart0_7_pins[] = {38, 39}; +static const unsigned int uart0_8_pins[] = {42, 43}; +static const unsigned int uart0_9_pins[] = {46, 47}; +static const unsigned int uart0_10_pins[] = {50, 51}; +static const unsigned int uart1_0_pins[] = {8, 9}; +static const unsigned int uart1_1_pins[] = {12, 13}; +static const unsigned int uart1_2_pins[] = {16, 17}; +static const unsigned int uart1_3_pins[] = {20, 21}; +static const unsigned int uart1_4_pins[] = {24, 25}; +static const unsigned int uart1_5_pins[] = {28, 29}; +static const unsigned int uart1_6_pins[] = {32, 33}; +static const unsigned int uart1_7_pins[] = {36, 37}; +static const unsigned int uart1_8_pins[] = {40, 41}; +static const unsigned int uart1_9_pins[] = {44, 45}; +static const unsigned int uart1_10_pins[] = {48, 49}; +static const unsigned int uart1_11_pins[] = {52, 53}; +static const unsigned int i2c0_0_pins[] = {10, 11}; +static const unsigned int i2c0_1_pins[] = {14, 15}; +static const unsigned int i2c0_2_pins[] = {18, 19}; +static const unsigned int i2c0_3_pins[] = {22, 23}; +static const unsigned int i2c0_4_pins[] = {26, 27}; +static const unsigned int i2c0_5_pins[] = {30, 31}; +static const unsigned int i2c0_6_pins[] = {34, 35}; +static const unsigned int i2c0_7_pins[] = {38, 39}; +static const unsigned int i2c0_8_pins[] = {42, 43}; +static const unsigned int i2c0_9_pins[] = {46, 47}; +static const unsigned int i2c0_10_pins[] = {50, 51}; +static const unsigned int i2c1_0_pins[] = {12, 13}; +static const unsigned int i2c1_1_pins[] = {16, 17}; +static const unsigned int i2c1_2_pins[] = {20, 21}; +static const unsigned int i2c1_3_pins[] = {24, 25}; +static const unsigned int i2c1_4_pins[] = {28, 29}; +static const unsigned int i2c1_5_pins[] = {32, 33}; +static const unsigned int i2c1_6_pins[] = {36, 37}; +static const unsigned int i2c1_7_pins[] = {40, 41}; +static const unsigned int i2c1_8_pins[] = {44, 45}; +static const unsigned int i2c1_9_pins[] = {48, 49}; +static const unsigned int i2c1_10_pins[] = {52, 53}; +static const unsigned int ttc0_0_pins[] = {18, 19}; +static const unsigned int ttc0_1_pins[] = {30, 31}; +static const unsigned int ttc0_2_pins[] = {42, 43}; +static const unsigned int ttc1_0_pins[] = {16, 17}; +static const unsigned int ttc1_1_pins[] = {28, 29}; +static const unsigned int ttc1_2_pins[] = {40, 41}; +static const unsigned int swdt0_0_pins[] = {14, 15}; +static const unsigned int swdt0_1_pins[] = {26, 27}; +static const unsigned int swdt0_2_pins[] = {38, 39}; +static const unsigned int swdt0_3_pins[] = {50, 51}; +static const unsigned int swdt0_4_pins[] = {52, 53}; +static const unsigned int gpio0_0_pins[] = {0}; +static const unsigned int gpio0_1_pins[] = {1}; +static const unsigned int gpio0_2_pins[] = {2}; +static const unsigned int gpio0_3_pins[] = {3}; +static const unsigned int gpio0_4_pins[] = {4}; +static const unsigned int gpio0_5_pins[] = {5}; +static const unsigned int gpio0_6_pins[] = {6}; +static const unsigned int gpio0_7_pins[] = {7}; +static const unsigned int gpio0_8_pins[] = {8}; +static const unsigned int gpio0_9_pins[] = {9}; +static const unsigned int gpio0_10_pins[] = {10}; +static const unsigned int gpio0_11_pins[] = {11}; +static const unsigned int gpio0_12_pins[] = {12}; +static const unsigned int gpio0_13_pins[] = {13}; +static const unsigned int gpio0_14_pins[] = {14}; +static const unsigned int gpio0_15_pins[] = {15}; +static const unsigned int gpio0_16_pins[] = {16}; +static const unsigned int gpio0_17_pins[] = {17}; +static const unsigned int gpio0_18_pins[] = {18}; +static const unsigned int gpio0_19_pins[] = {19}; +static const unsigned int gpio0_20_pins[] = {20}; +static const unsigned int gpio0_21_pins[] = {21}; +static const unsigned int gpio0_22_pins[] = {22}; +static const unsigned int gpio0_23_pins[] = {23}; +static const unsigned int gpio0_24_pins[] = {24}; +static const unsigned int gpio0_25_pins[] = {25}; +static const unsigned int gpio0_26_pins[] = {26}; +static const unsigned int gpio0_27_pins[] = {27}; +static const unsigned int gpio0_28_pins[] = {28}; +static const unsigned int gpio0_29_pins[] = {29}; +static const unsigned int gpio0_30_pins[] = {30}; +static const unsigned int gpio0_31_pins[] = {31}; +static const unsigned int gpio0_32_pins[] = {32}; +static const unsigned int gpio0_33_pins[] = {33}; +static const unsigned int gpio0_34_pins[] = {34}; +static const unsigned int gpio0_35_pins[] = {35}; +static const unsigned int gpio0_36_pins[] = {36}; +static const unsigned int gpio0_37_pins[] = {37}; +static const unsigned int gpio0_38_pins[] = {38}; +static const unsigned int gpio0_39_pins[] = {39}; +static const unsigned int gpio0_40_pins[] = {40}; +static const unsigned int gpio0_41_pins[] = {41}; +static const unsigned int gpio0_42_pins[] = {42}; +static const unsigned int gpio0_43_pins[] = {43}; +static const unsigned int gpio0_44_pins[] = {44}; +static const unsigned int gpio0_45_pins[] = {45}; +static const unsigned int gpio0_46_pins[] = {46}; +static const unsigned int gpio0_47_pins[] = {47}; +static const unsigned int gpio0_48_pins[] = {48}; +static const unsigned int gpio0_49_pins[] = {49}; +static const unsigned int gpio0_50_pins[] = {50}; +static const unsigned int gpio0_51_pins[] = {51}; +static const unsigned int gpio0_52_pins[] = {52}; +static const unsigned int gpio0_53_pins[] = {53}; +static const unsigned int usb0_0_pins[] = {28, 19, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39}; +static const unsigned int usb1_0_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51}; + +#define DEFINE_ZYNQ_PINCTRL_GRP(nm) \ + { \ + .name = #nm "_grp", \ + .pins = nm ## _pins, \ + .npins = ARRAY_SIZE(nm ## _pins), \ + } + +struct zynq_pctrl_group zynq_pctrl_groups[] = { + DEFINE_ZYNQ_PINCTRL_GRP(ethernet0_0), + DEFINE_ZYNQ_PINCTRL_GRP(ethernet1_0), + DEFINE_ZYNQ_PINCTRL_GRP(mdio0_0), + DEFINE_ZYNQ_PINCTRL_GRP(mdio1_0), + DEFINE_ZYNQ_PINCTRL_GRP(qspi0_0), + DEFINE_ZYNQ_PINCTRL_GRP(qspi1_0), + DEFINE_ZYNQ_PINCTRL_GRP(qspi_fbclk), + DEFINE_ZYNQ_PINCTRL_GRP(qspi_cs1), + DEFINE_ZYNQ_PINCTRL_GRP(spi0_0), + DEFINE_ZYNQ_PINCTRL_GRP(spi0_1), + DEFINE_ZYNQ_PINCTRL_GRP(spi0_2), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_0), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_1), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_2), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_3), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_0), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_1), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_2), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_0), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_1), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_2), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_3), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_emio_wp), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_emio_cd), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_emio_wp), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_emio_cd), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor_cs1), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor_addr25), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nand), + DEFINE_ZYNQ_PINCTRL_GRP(can0_0), + DEFINE_ZYNQ_PINCTRL_GRP(can0_1), + DEFINE_ZYNQ_PINCTRL_GRP(can0_2), + DEFINE_ZYNQ_PINCTRL_GRP(can0_3), + DEFINE_ZYNQ_PINCTRL_GRP(can0_4), + DEFINE_ZYNQ_PINCTRL_GRP(can0_5), + DEFINE_ZYNQ_PINCTRL_GRP(can0_6), + DEFINE_ZYNQ_PINCTRL_GRP(can0_7), + DEFINE_ZYNQ_PINCTRL_GRP(can0_8), + DEFINE_ZYNQ_PINCTRL_GRP(can0_9), + DEFINE_ZYNQ_PINCTRL_GRP(can0_10), + DEFINE_ZYNQ_PINCTRL_GRP(can1_0), + DEFINE_ZYNQ_PINCTRL_GRP(can1_1), + DEFINE_ZYNQ_PINCTRL_GRP(can1_2), + DEFINE_ZYNQ_PINCTRL_GRP(can1_3), + DEFINE_ZYNQ_PINCTRL_GRP(can1_4), + DEFINE_ZYNQ_PINCTRL_GRP(can1_5), + DEFINE_ZYNQ_PINCTRL_GRP(can1_6), + DEFINE_ZYNQ_PINCTRL_GRP(can1_7), + DEFINE_ZYNQ_PINCTRL_GRP(can1_8), + DEFINE_ZYNQ_PINCTRL_GRP(can1_9), + DEFINE_ZYNQ_PINCTRL_GRP(can1_10), + DEFINE_ZYNQ_PINCTRL_GRP(can1_11), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_0), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_1), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_2), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_3), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_4), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_5), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_6), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_7), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_8), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_9), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_10), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_0), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_1), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_2), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_3), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_4), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_5), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_6), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_7), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_8), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_9), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_10), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_11), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_0), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_1), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_2), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_3), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_4), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_5), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_6), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_7), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_8), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_9), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_10), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_0), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_1), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_2), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_3), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_4), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_5), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_6), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_7), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_8), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_9), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_10), + DEFINE_ZYNQ_PINCTRL_GRP(ttc0_0), + DEFINE_ZYNQ_PINCTRL_GRP(ttc0_1), + DEFINE_ZYNQ_PINCTRL_GRP(ttc0_2), + DEFINE_ZYNQ_PINCTRL_GRP(ttc1_0), + DEFINE_ZYNQ_PINCTRL_GRP(ttc1_1), + DEFINE_ZYNQ_PINCTRL_GRP(ttc1_2), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_0), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_1), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_2), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_3), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_4), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_0), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_1), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_2), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_3), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_4), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_5), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_6), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_7), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_8), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_9), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_10), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_11), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_12), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_13), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_14), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_15), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_16), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_17), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_18), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_19), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_20), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_21), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_22), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_23), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_24), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_25), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_26), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_27), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_28), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_29), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_30), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_31), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_32), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_33), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_34), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_35), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_36), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_37), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_38), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_39), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_40), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_41), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_42), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_43), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_44), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_45), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_46), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_47), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_48), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_49), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_50), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_51), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_52), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_53), + DEFINE_ZYNQ_PINCTRL_GRP(usb0_0), + DEFINE_ZYNQ_PINCTRL_GRP(usb1_0), +}; + +/* function groups */ +static const char * const ethernet0_groups[] = {"ethernet0_0_grp"}; +static const char * const ethernet1_groups[] = {"ethernet1_0_grp"}; +static const char * const usb0_groups[] = {"usb0_0_grp"}; +static const char * const usb1_groups[] = {"usb1_0_grp"}; +static const char * const mdio0_groups[] = {"mdio0_0_grp"}; +static const char * const mdio1_groups[] = {"mdio1_0_grp"}; +static const char * const qspi0_groups[] = {"qspi0_0_grp"}; +static const char * const qspi1_groups[] = {"qspi0_1_grp"}; +static const char * const qspi_fbclk_groups[] = {"qspi_fbclk_grp"}; +static const char * const qspi_cs1_groups[] = {"qspi_cs1_grp"}; +static const char * const spi0_groups[] = {"spi0_0_grp", "spi0_1_grp", + "spi0_2_grp"}; +static const char * const spi1_groups[] = {"spi1_0_grp", "spi1_1_grp", + "spi1_2_grp", "spi1_3_grp"}; +static const char * const sdio0_groups[] = {"sdio0_0_grp", "sdio0_1_grp", + "sdio0_2_grp"}; +static const char * const sdio1_groups[] = {"sdio1_0_grp", "sdio1_1_grp", + "sdio1_2_grp", "sdio1_3_grp"}; +static const char * const sdio0_pc_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_8_grp", "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp"}; +static const char * const sdio1_pc_groups[] = {"gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", "gpio0_7_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp"}; +static const char * const sdio0_cd_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio0_emio_cd_grp"}; +static const char * const sdio0_wp_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio0_emio_wp_grp"}; +static const char * const sdio1_cd_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_cd_grp"}; +static const char * const sdio1_wp_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_wp_grp"}; +static const char * const smc0_nor_groups[] = {"smc0_nor"}; +static const char * const smc0_nor_cs1_groups[] = {"smc0_nor_cs1_grp"}; +static const char * const smc0_nor_addr25_groups[] = {"smc0_nor_addr25_grp"}; +static const char * const smc0_nand_groups[] = {"smc0_nand"}; +static const char * const can0_groups[] = {"can0_0_grp", "can0_1_grp", + "can0_2_grp", "can0_3_grp", "can0_4_grp", "can0_5_grp", + "can0_6_grp", "can0_7_grp", "can0_8_grp", "can0_9_grp", + "can0_10_grp"}; +static const char * const can1_groups[] = {"can1_0_grp", "can1_1_grp", + "can1_2_grp", "can1_3_grp", "can1_4_grp", "can1_5_grp", + "can1_6_grp", "can1_7_grp", "can1_8_grp", "can1_9_grp", + "can1_10_grp", "can1_11_grp"}; +static const char * const uart0_groups[] = {"uart0_0_grp", "uart0_1_grp", + "uart0_2_grp", "uart0_3_grp", "uart0_4_grp", "uart0_5_grp", + "uart0_6_grp", "uart0_7_grp", "uart0_8_grp", "uart0_9_grp", + "uart0_10_grp"}; +static const char * const uart1_groups[] = {"uart1_0_grp", "uart1_1_grp", + "uart1_2_grp", "uart1_3_grp", "uart1_4_grp", "uart1_5_grp", + "uart1_6_grp", "uart1_7_grp", "uart1_8_grp", "uart1_9_grp", + "uart1_10_grp", "uart1_11_grp"}; +static const char * const i2c0_groups[] = {"i2c0_0_grp", "i2c0_1_grp", + "i2c0_2_grp", "i2c0_3_grp", "i2c0_4_grp", "i2c0_5_grp", + "i2c0_6_grp", "i2c0_7_grp", "i2c0_8_grp", "i2c0_9_grp", + "i2c0_10_grp"}; +static const char * const i2c1_groups[] = {"i2c1_0_grp", "i2c1_1_grp", + "i2c1_2_grp", "i2c1_3_grp", "i2c1_4_grp", "i2c1_5_grp", + "i2c1_6_grp", "i2c1_7_grp", "i2c1_8_grp", "i2c1_9_grp", + "i2c1_10_grp"}; +static const char * const ttc0_groups[] = {"ttc0_0_grp", "ttc0_1_grp", + "ttc0_2_grp"}; +static const char * const ttc1_groups[] = {"ttc1_0_grp", "ttc1_1_grp", + "ttc1_2_grp"}; +static const char * const swdt0_groups[] = {"swdt0_0_grp", "swdt0_1_grp", + "swdt0_2_grp", "swdt0_3_grp", "swdt0_4_grp"}; +static const char * const gpio0_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_8_grp", "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", "gpio0_7_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp"}; + +#define DEFINE_ZYNQ_PINMUX_FUNCTION(fname, mval) \ + [ZYNQ_PMUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + .mux_val = mval, \ + } + +#define DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(fname, mval, mux, mask, shift) \ + [ZYNQ_PMUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + .mux_val = mval, \ + .mux_mask = mask, \ + .mux_shift = shift, \ + } + +#define ZYNQ_SDIO_WP_SHIFT 0 +#define ZYNQ_SDIO_WP_MASK (0x3f << ZYNQ_SDIO_WP_SHIFT) +#define ZYNQ_SDIO_CD_SHIFT 16 +#define ZYNQ_SDIO_CD_MASK (0x3f << ZYNQ_SDIO_CD_SHIFT) + +static const struct zynq_pinmux_function zynq_pmux_functions[] = { + DEFINE_ZYNQ_PINMUX_FUNCTION(ethernet0, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(ethernet1, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(usb0, 2), + DEFINE_ZYNQ_PINMUX_FUNCTION(usb1, 2), + DEFINE_ZYNQ_PINMUX_FUNCTION(mdio0, 0x40), + DEFINE_ZYNQ_PINMUX_FUNCTION(mdio1, 0x50), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi0, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi1, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_fbclk, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_cs1, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(spi0, 0x50), + DEFINE_ZYNQ_PINMUX_FUNCTION(spi1, 0x50), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0, 0x40), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0_pc, 0xc), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_wp, 0, 130, ZYNQ_SDIO_WP_MASK, + ZYNQ_SDIO_WP_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_cd, 0, 130, ZYNQ_SDIO_CD_MASK, + ZYNQ_SDIO_CD_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1, 0x40), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1_pc, 0xc), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_wp, 0, 134, ZYNQ_SDIO_WP_MASK, + ZYNQ_SDIO_WP_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_cd, 0, 134, ZYNQ_SDIO_CD_MASK, + ZYNQ_SDIO_CD_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor, 4), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_cs1, 8), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_addr25, 4), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nand, 8), + DEFINE_ZYNQ_PINMUX_FUNCTION(can0, 0x10), + DEFINE_ZYNQ_PINMUX_FUNCTION(can1, 0x10), + DEFINE_ZYNQ_PINMUX_FUNCTION(uart0, 0x70), + DEFINE_ZYNQ_PINMUX_FUNCTION(uart1, 0x70), + DEFINE_ZYNQ_PINMUX_FUNCTION(i2c0, 0x20), + DEFINE_ZYNQ_PINMUX_FUNCTION(i2c1, 0x20), + DEFINE_ZYNQ_PINMUX_FUNCTION(ttc0, 0x60), + DEFINE_ZYNQ_PINMUX_FUNCTION(ttc1, 0x60), + DEFINE_ZYNQ_PINMUX_FUNCTION(swdt0, 0x30), + DEFINE_ZYNQ_PINMUX_FUNCTION(gpio0, 0), +}; + + +/* pinctrl */ +static int zynq_pctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->ngroups; +} + +static const char *zynq_pctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->groups[selector].name; +} + +static int zynq_pctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->groups[selector].pins; + *num_pins = pctrl->groups[selector].npins; + + return 0; +} + +static const struct pinctrl_ops zynq_pctrl_ops = { + .get_groups_count = zynq_pctrl_get_groups_count, + .get_group_name = zynq_pctrl_get_group_name, + .get_group_pins = zynq_pctrl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +/* pinmux */ +static int zynq_pmux_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->nfuncs; +} + +static const char *zynq_pmux_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->funcs[selector].name; +} + +static int zynq_pmux_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctrl->funcs[selector].groups; + *num_groups = pctrl->funcs[selector].ngroups; + return 0; +} + +static int zynq_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + int i, ret; + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct zynq_pctrl_group *pgrp = &pctrl->groups[group]; + const struct zynq_pinmux_function *func = &pctrl->funcs[function]; + + /* + * SD WP & CD are special. They have dedicated registers + * to mux them in + */ + if (function == ZYNQ_PMUX_sdio0_cd || function == ZYNQ_PMUX_sdio0_wp || + function == ZYNQ_PMUX_sdio1_cd || + function == ZYNQ_PMUX_sdio1_wp) { + u32 reg; + + ret = regmap_read(pctrl->syscon, + pctrl->pctrl_offset + func->mux, ®); + if (ret) + return ret; + + reg &= ~func->mux_mask; + reg |= pgrp->pins[0] << func->mux_shift; + ret = regmap_write(pctrl->syscon, + pctrl->pctrl_offset + func->mux, reg); + if (ret) + return ret; + } else { + for (i = 0; i < pgrp->npins; i++) { + unsigned int pin = pgrp->pins[i]; + u32 reg, addr = pctrl->pctrl_offset + (4 * pin); + + ret = regmap_read(pctrl->syscon, addr, ®); + if (ret) + return ret; + + reg &= ~ZYNQ_PINMUX_MUX_MASK; + reg |= func->mux_val << ZYNQ_PINMUX_MUX_SHIFT; + ret = regmap_write(pctrl->syscon, addr, reg); + if (ret) + return ret; + } + } + + return 0; +} + +static const struct pinmux_ops zynq_pinmux_ops = { + .get_functions_count = zynq_pmux_get_functions_count, + .get_function_name = zynq_pmux_get_function_name, + .get_function_groups = zynq_pmux_get_function_groups, + .set_mux = zynq_pinmux_set_mux, +}; + +/* pinconfig */ +#define ZYNQ_PINCONF_TRISTATE BIT(0) +#define ZYNQ_PINCONF_SPEED BIT(8) +#define ZYNQ_PINCONF_PULLUP BIT(12) +#define ZYNQ_PINCONF_DISABLE_RECVR BIT(13) + +#define ZYNQ_PINCONF_IOTYPE_SHIFT 9 +#define ZYNQ_PINCONF_IOTYPE_MASK (7 << ZYNQ_PINCONF_IOTYPE_SHIFT) + +enum zynq_io_standards { + zynq_iostd_min, + zynq_iostd_lvcmos18, + zynq_iostd_lvcmos25, + zynq_iostd_lvcmos33, + zynq_iostd_hstl, + zynq_iostd_max +}; + +/** + * enum zynq_pin_config_param - possible pin configuration parameters + * @PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to + * this parameter (on a custom format) tells the driver which alternative + * IO standard to use. + */ +enum zynq_pin_config_param { + PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1, +}; + +static const struct pinconf_generic_dt_params zynq_dt_params[] = { + {"io-standard", PIN_CONFIG_IOSTANDARD, zynq_iostd_lvcmos18}, +}; + +static const struct pin_config_item zynq_conf_items[ARRAY_SIZE(zynq_dt_params)] = { + PCONFDUMP(PIN_CONFIG_IOSTANDARD, "IO-standard", NULL, true), +}; + +static unsigned int zynq_pinconf_iostd_get(u32 reg) +{ + return (reg & ZYNQ_PINCONF_IOTYPE_MASK) >> ZYNQ_PINCONF_IOTYPE_SHIFT; +} + +static int zynq_pinconf_cfg_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + u32 reg; + int ret; + unsigned int arg = 0; + unsigned int param = pinconf_to_config_param(*config); + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + if (pin >= ZYNQ_NUM_MIOS) + return -ENOTSUPP; + + ret = regmap_read(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), ®); + if (ret) + return -EIO; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + if (!(reg & ZYNQ_PINCONF_PULLUP)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + if (!(reg & ZYNQ_PINCONF_TRISTATE)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_DISABLE: + if (reg & ZYNQ_PINCONF_PULLUP || reg & ZYNQ_PINCONF_TRISTATE) + return -EINVAL; + break; + case PIN_CONFIG_SLEW_RATE: + arg = !!(reg & ZYNQ_PINCONF_SPEED); + break; + case PIN_CONFIG_LOW_POWER_MODE: + { + enum zynq_io_standards iostd = zynq_pinconf_iostd_get(reg); + + if (iostd != zynq_iostd_hstl) + return -EINVAL; + if (!(reg & ZYNQ_PINCONF_DISABLE_RECVR)) + return -EINVAL; + arg = !!(reg & ZYNQ_PINCONF_DISABLE_RECVR); + break; + } + case PIN_CONFIG_IOSTANDARD: + arg = zynq_pinconf_iostd_get(reg); + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int zynq_pinconf_cfg_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + int i, ret; + u32 reg; + u32 pullup = 0; + u32 tristate = 0; + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + if (pin >= ZYNQ_NUM_MIOS) + return -ENOTSUPP; + + ret = regmap_read(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), ®); + if (ret) + return -EIO; + + for (i = 0; i < num_configs; i++) { + unsigned int param = pinconf_to_config_param(configs[i]); + unsigned int arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + pullup = ZYNQ_PINCONF_PULLUP; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + tristate = ZYNQ_PINCONF_TRISTATE; + break; + case PIN_CONFIG_BIAS_DISABLE: + reg &= ~(ZYNQ_PINCONF_PULLUP | ZYNQ_PINCONF_TRISTATE); + break; + case PIN_CONFIG_SLEW_RATE: + if (arg) + reg |= ZYNQ_PINCONF_SPEED; + else + reg &= ~ZYNQ_PINCONF_SPEED; + + break; + case PIN_CONFIG_IOSTANDARD: + if (arg <= zynq_iostd_min || arg >= zynq_iostd_max) { + dev_warn(pctldev->dev, + "unsupported IO standard '%u'\n", + param); + break; + } + reg &= ~ZYNQ_PINCONF_IOTYPE_MASK; + reg |= arg << ZYNQ_PINCONF_IOTYPE_SHIFT; + break; + case PIN_CONFIG_LOW_POWER_MODE: + if (arg) + reg |= ZYNQ_PINCONF_DISABLE_RECVR; + else + reg &= ~ZYNQ_PINCONF_DISABLE_RECVR; + + break; + default: + dev_warn(pctldev->dev, + "unsupported configuration parameter '%u'\n", + param); + continue; + } + } + + if (tristate || pullup) { + reg &= ~(ZYNQ_PINCONF_PULLUP | ZYNQ_PINCONF_TRISTATE); + reg |= tristate | pullup; + } + + ret = regmap_write(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), reg); + if (ret) + return -EIO; + + return 0; +} + +static int zynq_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long *configs, + unsigned num_configs) +{ + int i, ret; + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct zynq_pctrl_group *pgrp = &pctrl->groups[selector]; + + for (i = 0; i < pgrp->npins; i++) { + ret = zynq_pinconf_cfg_set(pctldev, pgrp->pins[i], configs, + num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops zynq_pinconf_ops = { + .is_generic = true, + .pin_config_get = zynq_pinconf_cfg_get, + .pin_config_set = zynq_pinconf_cfg_set, + .pin_config_group_set = zynq_pinconf_group_set, +}; + +static struct pinctrl_desc zynq_desc = { + .name = "zynq_pinctrl", + .pins = zynq_pins, + .npins = ARRAY_SIZE(zynq_pins), + .pctlops = &zynq_pctrl_ops, + .pmxops = &zynq_pinmux_ops, + .confops = &zynq_pinconf_ops, + .num_dt_params = ARRAY_SIZE(zynq_dt_params), + .params = zynq_dt_params, + .conf_items = zynq_conf_items, + .owner = THIS_MODULE, +}; + +static int zynq_pinctrl_probe(struct platform_device *pdev) + +{ + struct resource *res; + struct zynq_pinctrl *pctrl; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(pctrl->syscon)) { + dev_err(&pdev->dev, "unable to get syscon\n"); + return PTR_ERR(pctrl->syscon); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENODEV; + } + pctrl->pctrl_offset = res->start; + + pctrl->groups = zynq_pctrl_groups; + pctrl->ngroups = ARRAY_SIZE(zynq_pctrl_groups); + pctrl->funcs = zynq_pmux_functions; + pctrl->nfuncs = ARRAY_SIZE(zynq_pmux_functions); + + pctrl->pctrl = pinctrl_register(&zynq_desc, &pdev->dev, pctrl); + if (!pctrl->pctrl) + return -ENOMEM; + + platform_set_drvdata(pdev, pctrl); + + dev_info(&pdev->dev, "zynq pinctrl initialized\n"); + + return 0; +} + +int zynq_pinctrl_remove(struct platform_device *pdev) +{ + struct zynq_pinctrl *pctrl = platform_get_drvdata(pdev); + + pinctrl_unregister(pctrl->pctrl); + + return 0; +} + +static const struct of_device_id zynq_pinctrl_of_match[] = { + { .compatible = "xlnx,pinctrl-zynq" }, + { } +}; +MODULE_DEVICE_TABLE(of, zynq_pinctrl_of_match); + +static struct platform_driver zynq_pinctrl_driver = { + .driver = { + .name = "zynq-pinctrl", + .of_match_table = zynq_pinctrl_of_match, + }, + .probe = zynq_pinctrl_probe, + .remove = zynq_pinctrl_remove, +}; + +module_platform_driver(zynq_pinctrl_driver); + +MODULE_AUTHOR("Sören Brinkmann "); +MODULE_DESCRIPTION("Xilinx Zynq pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 3cb6dcfa44e883412f8df2f2b1917b0d359f3ec4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 9 Jan 2015 17:43:06 -0800 Subject: Input: regulator-haptic - simplify code All the use cases in this driver has a regulator_haptic_toggle() call after regulator_haptic_set_voltage(). So make regulator_haptic_set_voltage() call regulator_haptic_toggle() to simplify the code. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c index 9426221..132eb91 100644 --- a/drivers/input/misc/regulator-haptic.c +++ b/drivers/input/misc/regulator-haptic.c @@ -76,6 +76,8 @@ static int regulator_haptic_set_voltage(struct regulator_haptic *haptic, return error; } + regulator_haptic_toggle(haptic, !!magnitude); + return 0; } @@ -83,23 +85,12 @@ static void regulator_haptic_work(struct work_struct *work) { struct regulator_haptic *haptic = container_of(work, struct regulator_haptic, work); - unsigned int magnitude; - int error; mutex_lock(&haptic->mutex); - if (haptic->suspended) - goto out; - - magnitude = ACCESS_ONCE(haptic->magnitude); + if (!haptic->suspended) + regulator_haptic_set_voltage(haptic, haptic->magnitude); - error = regulator_haptic_set_voltage(haptic, magnitude); - if (error) - goto out; - - regulator_haptic_toggle(haptic, magnitude != 0); - -out: mutex_unlock(&haptic->mutex); } @@ -123,7 +114,6 @@ static void regulator_haptic_close(struct input_dev *input) cancel_work_sync(&haptic->work); regulator_haptic_set_voltage(haptic, 0); - regulator_haptic_toggle(haptic, false); } static int __maybe_unused @@ -225,7 +215,6 @@ static int __maybe_unused regulator_haptic_suspend(struct device *dev) return error; regulator_haptic_set_voltage(haptic, 0); - regulator_haptic_toggle(haptic, false); haptic->suspended = true; @@ -245,10 +234,8 @@ static int __maybe_unused regulator_haptic_resume(struct device *dev) haptic->suspended = false; magnitude = ACCESS_ONCE(haptic->magnitude); - if (magnitude) { + if (magnitude) regulator_haptic_set_voltage(haptic, magnitude); - regulator_haptic_toggle(haptic, true); - } mutex_unlock(&haptic->mutex); -- cgit v0.10.2 From dfba8600024abb09dbabfcd9d3c887848f4b154c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 9 Jan 2015 12:48:44 -0800 Subject: Input: alps - fix name, product and version of dev2 input device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change fixes name, product and version of dev2 input device based on format used in function psmouse_switch_protocol() in file psmouse-base.c. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 0faea6d..4d7c4cc 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2422,14 +2422,24 @@ int alps_init(struct psmouse *psmouse) dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); } + if (priv->flags & ALPS_DUALPOINT) { + /* + * format of input device name is: "protocol vendor name" + * see function psmouse_switch_protocol() in psmouse-base.c + */ + dev2->name = "AlpsPS/2 ALPS DualPoint Stick"; + dev2->id.product = PSMOUSE_ALPS; + dev2->id.version = priv->proto_version; + } else { + dev2->name = "PS/2 ALPS Mouse"; + dev2->id.product = PSMOUSE_PS2; + dev2->id.version = 0x0000; + } + snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); dev2->phys = priv->phys; - dev2->name = (priv->flags & ALPS_DUALPOINT) ? - "DualPoint Stick" : "ALPS PS/2 Device"; dev2->id.bustype = BUS_I8042; dev2->id.vendor = 0x0002; - dev2->id.product = PSMOUSE_ALPS; - dev2->id.version = 0x0000; dev2->dev.parent = &psmouse->ps2dev.serio->dev; dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -- cgit v0.10.2 From 34412ba28232e8b3b4955a4bbe53c9df4c7b2d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 9 Jan 2015 12:48:58 -0800 Subject: Input: alps - add sanity checks for non DualPoint devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that driver does not process bogus packets as trackstick data when there is no trackstick present and emit warnings in dmesg so potential issues with trackstick handling will be visible for debugging. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 4d7c4cc..dd2fd39 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -475,6 +475,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) struct input_dev *dev = priv->dev2; int x, y, z, left, right, middle; + /* It should be a DualPoint when received trackstick packet */ + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + return; + } + /* Sanity check packet */ if (!(packet[0] & 0x40)) { psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); @@ -699,7 +706,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) alps_report_semi_mt_data(psmouse, fingers); - if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { + if ((priv->flags & ALPS_DUALPOINT) && + !(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { input_report_key(dev2, BTN_LEFT, f->ts_left); input_report_key(dev2, BTN_RIGHT, f->ts_right); input_report_key(dev2, BTN_MIDDLE, f->ts_middle); @@ -743,8 +751,11 @@ static void alps_process_packet_v6(struct psmouse *psmouse) */ if (packet[5] == 0x7F) { /* It should be a DualPoint when received Trackpoint packet */ - if (!(priv->flags & ALPS_DUALPOINT)) + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); return; + } /* Trackpoint packet */ x = packet[1] | ((packet[3] & 0x20) << 2); @@ -1026,6 +1037,13 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) struct input_dev *dev2 = priv->dev2; int x, y, z, left, right, middle; + /* It should be a DualPoint when received trackstick packet */ + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + return; + } + /* * b7 b6 b5 b4 b3 b2 b1 b0 * Byte0 0 1 0 0 1 0 0 0 -- cgit v0.10.2 From 888d0d421663313739a8bf93459c6ba61fd4b121 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 8 Jan 2015 17:54:13 +0200 Subject: drm/i915: add dev_to_i915 helper This will be needed by later patches, so factor it out. No functional change. v2: - s/dev_to_i915_priv/dev_to_i915/ (Jani) - don't use the helper in i915_pm_suspend (Chris) - simplify the helper (Chris) v3: - remove redundant upcasting in the helper (Daniel) Signed-off-by: Imre Deak Reviewed-by: Takashi Iwai Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 574057c..cbbd23f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -940,8 +940,7 @@ static int i915_pm_suspend(struct device *dev) static int i915_pm_suspend_late(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; /* * We have a suspedn ordering issue with the snd-hda driver also @@ -960,8 +959,7 @@ static int i915_pm_suspend_late(struct device *dev) static int i915_pm_resume_early(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -971,8 +969,7 @@ static int i915_pm_resume_early(struct device *dev) static int i915_pm_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e9f891c..a343f2f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1781,6 +1781,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev) return dev->dev_private; } +static inline struct drm_i915_private *dev_to_i915(struct device *dev) +{ + return to_i915(dev_get_drvdata(dev)); +} + /* Iterate over initialised rings */ #define for_each_ring(ring__, dev_priv__, i__) \ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ -- cgit v0.10.2 From 58fddc288b5cec192ad9eb9221da7ed14d974a27 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 8 Jan 2015 17:54:14 +0200 Subject: drm/i915: add component support Register a component to be used to interface with the snd_hda_intel driver. This is meant to replace the same interface that is currently based on module symbol lookup. v2: - change roles between the hda and i915 components (Daniel) - add the implementation to a new file (Jani) - use better namespacing (Jani) v3: - move the implementation to intel_audio.c (Daniel) - rename display_component to audio_component (Daniel) - add kerneldoc (Daniel) v4: - run forgotten git rm i915_component.c (Jani) Signed-off-by: Imre Deak Reviewed-by: Takashi Iwai Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ecee3bc..26b3199 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_runtime_pm_enable(dev_priv); + i915_audio_component_init(dev_priv); + return 0; out_power_well: @@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + i915_audio_component_cleanup(dev_priv); + ret = i915_gem_suspend(dev); if (ret) { DRM_ERROR("failed to idle hardware: %d\n", ret); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a343f2f..176afc5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1698,6 +1698,9 @@ struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; + /* hda/i915 audio component */ + bool audio_component_registered; + uint32_t hw_context_size; struct list_head context_list; diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 2c7ed5c..ee41b88 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -22,6 +22,9 @@ */ #include +#include +#include +#include "intel_drv.h" #include #include @@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev) dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; } } + +static void i915_audio_component_get_power(struct device *dev) +{ + intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +static void i915_audio_component_put_power(struct device *dev) +{ + intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +/* Get CDCLK in kHz */ +static int i915_audio_component_get_cdclk_freq(struct device *dev) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + int ret; + + if (WARN_ON_ONCE(!HAS_DDI(dev_priv))) + return -ENODEV; + + intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); + ret = intel_ddi_get_cdclk_freq(dev_priv); + intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); + + return ret; +} + +static const struct i915_audio_component_ops i915_audio_component_ops = { + .owner = THIS_MODULE, + .get_power = i915_audio_component_get_power, + .put_power = i915_audio_component_put_power, + .get_cdclk_freq = i915_audio_component_get_cdclk_freq, +}; + +static int i915_audio_component_bind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + if (WARN_ON(acomp->ops || acomp->dev)) + return -EEXIST; + + acomp->ops = &i915_audio_component_ops; + acomp->dev = i915_dev; + + return 0; +} + +static void i915_audio_component_unbind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; +} + +static const struct component_ops i915_audio_component_bind_ops = { + .bind = i915_audio_component_bind, + .unbind = i915_audio_component_unbind, +}; + +/** + * i915_audio_component_init - initialize and register the audio component + * @dev_priv: i915 device instance + * + * This will register with the component framework a child component which + * will bind dynamically to the snd_hda_intel driver's corresponding master + * component when the latter is registered. During binding the child + * initializes an instance of struct i915_audio_component which it receives + * from the master. The master can then start to use the interface defined by + * this struct. Each side can break the binding at any point by deregistering + * its own component after which each side's component unbind callback is + * called. + * + * We ignore any error during registration and continue with reduced + * functionality (i.e. without HDMI audio). + */ +void i915_audio_component_init(struct drm_i915_private *dev_priv) +{ + int ret; + + ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops); + if (ret < 0) { + DRM_ERROR("failed to add audio component (%d)\n", ret); + /* continue with reduced functionality */ + return; + } + + dev_priv->audio_component_registered = true; +} + +/** + * i915_audio_component_cleanup - deregister the audio component + * @dev_priv: i915 device instance + * + * Deregisters the audio component, breaking any existing binding to the + * corresponding snd_hda_intel driver's master component. + */ +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) +{ + if (!dev_priv->audio_component_registered) + return; + + component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops); + dev_priv->audio_component_registered = false; +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 25fdbb1..e88fd5d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -872,6 +872,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); void intel_init_audio(struct drm_device *dev); void intel_audio_codec_enable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder); +void i915_audio_component_init(struct drm_i915_private *dev_priv); +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); /* intel_display.c */ const char *intel_output_name(int output); diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h new file mode 100644 index 0000000..3e2f22e --- /dev/null +++ b/include/drm/i915_component.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _I915_COMPONENT_H_ +#define _I915_COMPONENT_H_ + +struct i915_audio_component { + struct device *dev; + + const struct i915_audio_component_ops { + struct module *owner; + void (*get_power)(struct device *); + void (*put_power)(struct device *); + int (*get_cdclk_freq)(struct device *); + } *ops; +}; + +#endif /* _I915_COMPONENT_H_ */ -- cgit v0.10.2 From 347de1f8625199d177caf7668cfa1c00717faedb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 8 Jan 2015 17:54:15 +0200 Subject: ALSA: hda: export struct hda_intel This struct will be needed by the component code added in an upcoming patch, so export it into a new hda_intel.h file. At the same time also merge hda_i915.h into this new header, there is no reason to keep two separate intel specific header file. Suggested-by: Takashi Iwai Signed-off-by: Imre Deak Reviewed-by: Takashi Iwai Signed-off-by: Daniel Vetter diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index d4d0375..6a7854d 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -21,7 +21,7 @@ #include #include #include "hda_priv.h" -#include "hda_i915.h" +#include "hda_intel.h" /* Intel HSW/BDW display HDA controller Extended Mode registers. * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h deleted file mode 100644 index e6072c6..0000000 --- a/sound/pci/hda/hda_i915.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __SOUND_HDA_I915_H -#define __SOUND_HDA_I915_H - -#ifdef CONFIG_SND_HDA_I915 -int hda_display_power(bool enable); -void haswell_set_bclk(struct azx *chip); -int hda_i915_init(void); -int hda_i915_exit(void); -#else -static inline int hda_display_power(bool enable) { return 0; } -static inline void haswell_set_bclk(struct azx *chip) { return; } -static inline int hda_i915_init(void) -{ - return -ENODEV; -} -static inline int hda_i915_exit(void) -{ - return 0; -} -#endif - -#endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d426a0b..e4bc0dc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include "hda_codec.h" #include "hda_controller.h" #include "hda_priv.h" -#include "hda_i915.h" +#include "hda_intel.h" /* position fix mode */ enum { @@ -354,31 +354,6 @@ static char *driver_short_names[] = { [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; -struct hda_intel { - struct azx chip; - - /* for pending irqs */ - struct work_struct irq_pending_work; - - /* sync probing */ - struct completion probe_wait; - struct work_struct probe_work; - - /* card list (for power_save trigger) */ - struct list_head list; - - /* extra flags */ - unsigned int irq_pending_warned:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ - - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; -}; - #ifdef CONFIG_X86 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) { diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h new file mode 100644 index 0000000..434f254 --- /dev/null +++ b/sound/pci/hda/hda_intel.h @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __SOUND_HDA_INTEL_H +#define __SOUND_HDA_INTEL_H + +#include "hda_priv.h" + +struct hda_intel { + struct azx chip; + + /* for pending irqs */ + struct work_struct irq_pending_work; + + /* sync probing */ + struct completion probe_wait; + struct work_struct probe_work; + + /* card list (for power_save trigger) */ + struct list_head list; + + /* extra flags */ + unsigned int irq_pending_warned:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; +}; + +#ifdef CONFIG_SND_HDA_I915 +int hda_display_power(bool enable); +void haswell_set_bclk(struct azx *chip); +int hda_i915_init(void); +int hda_i915_exit(void); +#else +static inline int hda_display_power(bool enable) { return 0; } +static inline void haswell_set_bclk(struct azx *chip) { return; } +static inline int hda_i915_init(void) +{ + return -ENODEV; +} +static inline int hda_i915_exit(void) +{ + return 0; +} +#endif + +#endif -- cgit v0.10.2 From 926981ae3325257d0bffcf7ff7ba359edb4fd7e8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 8 Jan 2015 17:54:16 +0200 Subject: ALSA: hda: pass intel_hda to all i915 interface functions chip is already passed to most of the i915 interface functions. Unify the interface by passing intel_hda instead of chip and passing it to all functions. Passing intel_hda instead of chip makes more sense since this is an intel specific interface. Also in an upcoming patch we will use intel_hda in all of these functions so by passing intel_hda we can save on some pointer casts from chip to intel_hda. This will be needed by an upcoming patch adding component support. No functional change. v2-3: unchanged v4: - pass intel_hda instead of chip Signed-off-by: Imre Deak Reviewed-by: Takashi Iwai Signed-off-by: Daniel Vetter diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 6a7854d..66acd09 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -35,7 +35,7 @@ static int (*get_power)(void); static int (*put_power)(void); static int (*get_cdclk)(void); -int hda_display_power(bool enable) +int hda_display_power(struct hda_intel *hda, bool enable) { if (!get_power || !put_power) return -ENODEV; @@ -48,7 +48,7 @@ int hda_display_power(bool enable) return put_power(); } -void haswell_set_bclk(struct azx *chip) +void haswell_set_bclk(struct hda_intel *hda) { int cdclk_freq; unsigned int bclk_m, bclk_n; @@ -80,12 +80,12 @@ void haswell_set_bclk(struct azx *chip) break; } - azx_writew(chip, EM4, bclk_m); - azx_writew(chip, EM5, bclk_n); + azx_writew(&hda->chip, EM4, bclk_m); + azx_writew(&hda->chip, EM5, bclk_n); } -int hda_i915_init(void) +int hda_i915_init(struct hda_intel *hda) { int err = 0; @@ -111,7 +111,7 @@ int hda_i915_init(void) return err; } -int hda_i915_exit(void) +int hda_i915_exit(struct hda_intel *hda) { if (get_power) { symbol_put(i915_request_power_well); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e4bc0dc..323abf9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -803,7 +803,7 @@ static int azx_suspend(struct device *dev) pci_save_state(pci); pci_set_power_state(pci, PCI_D3hot); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(false); + hda_display_power(hda, false); return 0; } @@ -823,8 +823,8 @@ static int azx_resume(struct device *dev) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(true); - haswell_set_bclk(chip); + hda_display_power(hda, true); + haswell_set_bclk(hda); } pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -876,7 +876,7 @@ static int azx_runtime_suspend(struct device *dev) azx_enter_link_reset(chip); azx_clear_irq_pending(chip); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(false); + hda_display_power(hda, false); return 0; } @@ -902,8 +902,8 @@ static int azx_runtime_resume(struct device *dev) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(true); - haswell_set_bclk(chip); + hda_display_power(hda, true); + haswell_set_bclk(hda); } /* Read STATESTS before controller reset */ @@ -1125,8 +1125,8 @@ static int azx_free(struct azx *chip) release_firmware(chip->fw); #endif if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(false); - hda_i915_exit(); + hda_display_power(hda, false); + hda_i915_exit(hda); } kfree(hda); @@ -1604,8 +1604,12 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - haswell_set_bclk(chip); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + struct hda_intel *hda; + + hda = container_of(chip, struct hda_intel, chip); + haswell_set_bclk(hda); + } azx_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -1885,13 +1889,13 @@ static int azx_probe_continue(struct azx *chip) /* Request power well for Haswell HDA controller and codec */ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { #ifdef CONFIG_SND_HDA_I915 - err = hda_i915_init(); + err = hda_i915_init(hda); if (err < 0) { dev_err(chip->card->dev, "Error request power-well from i915\n"); goto out_free; } - err = hda_display_power(true); + err = hda_display_power(hda, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 434f254..70b8306 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -44,18 +44,21 @@ struct hda_intel { }; #ifdef CONFIG_SND_HDA_I915 -int hda_display_power(bool enable); -void haswell_set_bclk(struct azx *chip); -int hda_i915_init(void); -int hda_i915_exit(void); +int hda_display_power(struct hda_intel *hda, bool enable); +void haswell_set_bclk(struct hda_intel *hda); +int hda_i915_init(struct hda_intel *hda); +int hda_i915_exit(struct hda_intel *hda); #else -static inline int hda_display_power(bool enable) { return 0; } -static inline void haswell_set_bclk(struct azx *chip) { return; } -static inline int hda_i915_init(void) +static inline int hda_display_power(struct hda_intel *hda, bool enable) +{ + return 0; +} +static inline void haswell_set_bclk(struct hda_intel *hda) { return; } +static inline int hda_i915_init(struct hda_intel *hda) { return -ENODEV; } -static inline int hda_i915_exit(void) +static inline int hda_i915_exit(struct hda_intel *hda) { return 0; } -- cgit v0.10.2 From d7055bd653e00ef40a07065d1c94380240314c48 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 8 Jan 2015 17:54:17 +0200 Subject: ALSA: hda: add component support Register a component master to be used to interface with the i915 driver. This is meant to replace the current interface which is based on module symbol lookups. Note that currently we keep the existing behavior and pin the i915 module while the hda driver is loaded. Using the component interface allows us to remove this dependency once support for dynamically enabling / disabling the HDMI functionality is added to the driver. v2: - change roles between the hda and i915 components (Daniel) v3: - rename display_component to audio_component (Daniel) v4: - move removal of i915_powerwell.h from this patch to the next (Takashi) - request_module fails if module support isn't enabled, so ignore any error it returns and depend on the following NULL check of the component ops (Takashi) - change over to using dev_* instead of pr_* (Takashi) Signed-off-by: Imre Deak Reviewed-by: Takashi Iwai Signed-off-by: Daniel Vetter diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 66acd09..7148945 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -18,8 +18,10 @@ #include #include +#include +#include +#include #include -#include #include "hda_priv.h" #include "hda_intel.h" @@ -31,32 +33,33 @@ #define AZX_REG_EM4 0x100c #define AZX_REG_EM5 0x1010 -static int (*get_power)(void); -static int (*put_power)(void); -static int (*get_cdclk)(void); - int hda_display_power(struct hda_intel *hda, bool enable) { - if (!get_power || !put_power) + struct i915_audio_component *acomp = &hda->audio_component; + + if (!acomp->ops) return -ENODEV; - pr_debug("HDA display power %s \n", - enable ? "Enable" : "Disable"); + dev_dbg(&hda->chip.pci->dev, "display power %s\n", + enable ? "enable" : "disable"); if (enable) - return get_power(); + acomp->ops->get_power(acomp->dev); else - return put_power(); + acomp->ops->put_power(acomp->dev); + + return 0; } void haswell_set_bclk(struct hda_intel *hda) { int cdclk_freq; unsigned int bclk_m, bclk_n; + struct i915_audio_component *acomp = &hda->audio_component; - if (!get_cdclk) + if (!acomp->ops) return; - cdclk_freq = get_cdclk(); + cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); switch (cdclk_freq) { case 337500: bclk_m = 16; @@ -84,47 +87,104 @@ void haswell_set_bclk(struct hda_intel *hda) azx_writew(&hda->chip, EM5, bclk_n); } - -int hda_i915_init(struct hda_intel *hda) +static int hda_component_master_bind(struct device *dev) { - int err = 0; + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct i915_audio_component *acomp = &hda->audio_component; + int ret; + + ret = component_bind_all(dev, acomp); + if (ret < 0) + return ret; + + if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && + acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { + ret = -EINVAL; + goto out_unbind; + } - get_power = symbol_request(i915_request_power_well); - if (!get_power) { - pr_warn("hda-i915: get_power symbol get fail\n"); - return -ENODEV; + /* + * Atm, we don't support dynamic unbinding initiated by the child + * component, so pin its containing module until we unbind. + */ + if (!try_module_get(acomp->ops->owner)) { + ret = -ENODEV; + goto out_unbind; } - put_power = symbol_request(i915_release_power_well); - if (!put_power) { - symbol_put(i915_request_power_well); - get_power = NULL; - return -ENODEV; + return 0; + +out_unbind: + component_unbind_all(dev, acomp); + + return ret; +} + +static void hda_component_master_unbind(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct i915_audio_component *acomp = &hda->audio_component; + + module_put(acomp->ops->owner); + component_unbind_all(dev, acomp); + WARN_ON(acomp->ops || acomp->dev); +} + +static const struct component_master_ops hda_component_master_ops = { + .bind = hda_component_master_bind, + .unbind = hda_component_master_unbind, +}; + +static int hda_component_master_match(struct device *dev, void *data) +{ + /* i915 is the only supported component */ + return !strcmp(dev->driver->name, "i915"); +} + +int hda_i915_init(struct hda_intel *hda) +{ + struct component_match *match = NULL; + struct device *dev = &hda->chip.pci->dev; + struct i915_audio_component *acomp = &hda->audio_component; + int ret; + + component_match_add(dev, &match, hda_component_master_match, hda); + ret = component_master_add_with_match(dev, &hda_component_master_ops, + match); + if (ret < 0) + goto out_err; + + /* + * Atm, we don't support deferring the component binding, so make sure + * i915 is loaded and that the binding successfully completes. + */ + request_module("i915"); + + if (!acomp->ops) { + ret = -ENODEV; + goto out_master_del; } - get_cdclk = symbol_request(i915_get_cdclk_freq); - if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ - pr_warn("hda-i915: get_cdclk symbol get fail\n"); + dev_dbg(dev, "bound to i915 component master\n"); - pr_debug("HDA driver get symbol successfully from i915 module\n"); + return 0; +out_master_del: + component_master_del(dev, &hda_component_master_ops); +out_err: + dev_err(dev, "failed to add i915 component master (%d)\n", ret); - return err; + return ret; } int hda_i915_exit(struct hda_intel *hda) { - if (get_power) { - symbol_put(i915_request_power_well); - get_power = NULL; - } - if (put_power) { - symbol_put(i915_release_power_well); - put_power = NULL; - } - if (get_cdclk) { - symbol_put(i915_get_cdclk_freq); - get_cdclk = NULL; - } + struct device *dev = &hda->chip.pci->dev; + + component_master_del(dev, &hda_component_master_ops); return 0; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 323abf9..95a5399 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1890,11 +1890,8 @@ static int azx_probe_continue(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { #ifdef CONFIG_SND_HDA_I915 err = hda_i915_init(hda); - if (err < 0) { - dev_err(chip->card->dev, - "Error request power-well from i915\n"); + if (err < 0) goto out_free; - } err = hda_display_power(hda, true); if (err < 0) { dev_err(chip->card->dev, diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 70b8306..3486118 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -16,6 +16,7 @@ #ifndef __SOUND_HDA_INTEL_H #define __SOUND_HDA_INTEL_H +#include #include "hda_priv.h" struct hda_intel { @@ -41,6 +42,9 @@ struct hda_intel { /* secondary power domain for hdmi audio under vga device */ struct dev_pm_domain hdmi_pm_domain; + + /* i915 component interface */ + struct i915_audio_component audio_component; }; #ifdef CONFIG_SND_HDA_I915 -- cgit v0.10.2 From fcf3aac5fc307f0cae429f5844ddc25761662858 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 8 Jan 2015 17:54:18 +0200 Subject: drm/i915: remove unused power_well/get_cdclk_freq api After switching to using the component interface this API isn't needed any more. v2-3: unchanged v4: - move the removal of i915_powerwell.h to this patch (Takashi) Signed-off-by: Imre Deak Reviewed-by: Takashi Iwai Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index ac6da71..39ddf40 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -31,7 +31,6 @@ #include "i915_drv.h" #include "intel_drv.h" -#include /** * DOC: runtime pm @@ -50,8 +49,6 @@ * present for a given platform. */ -static struct i915_power_domains *hsw_pwr; - #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ i < (power_domains)->power_well_count && \ @@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) */ if (IS_HASWELL(dev_priv->dev)) { set_power_wells(power_domains, hsw_power_wells); - hsw_pwr = power_domains; } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); - hsw_pwr = power_domains; } else if (IS_CHERRYVIEW(dev_priv->dev)) { set_power_wells(power_domains, chv_power_wells); } else if (IS_VALLEYVIEW(dev_priv->dev)) { @@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv) * the power well is not enabled, so just enable it in case * we're going to unload/reload. */ intel_display_set_init_power(dev_priv, true); - - hsw_pwr = NULL; } static void intel_power_domains_resume(struct drm_i915_private *dev_priv) @@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) pm_runtime_put_autosuspend(device); } -/* Display audio driver power well request */ -int i915_request_power_well(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); - return 0; -} -EXPORT_SYMBOL_GPL(i915_request_power_well); - -/* Display audio driver power well release */ -int i915_release_power_well(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); - return 0; -} -EXPORT_SYMBOL_GPL(i915_release_power_well); - -/* - * Private interface for the audio driver to get CDCLK in kHz. - * - * Caller must request power well using i915_request_power_well() prior to - * making the call. - */ -int i915_get_cdclk_freq(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - - return intel_ddi_get_cdclk_freq(dev_priv); -} -EXPORT_SYMBOL_GPL(i915_get_cdclk_freq); diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h deleted file mode 100644 index baa6f11..0000000 --- a/include/drm/i915_powerwell.h +++ /dev/null @@ -1,37 +0,0 @@ -/************************************************************************** - * - * Copyright 2013 Intel Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * - **************************************************************************/ - -#ifndef _I915_POWERWELL_H_ -#define _I915_POWERWELL_H_ - -/* For use by hda_i915 driver */ -extern int i915_request_power_well(void); -extern int i915_release_power_well(void); -extern int i915_get_cdclk_freq(void); - -#endif /* _I915_POWERWELL_H_ */ -- cgit v0.10.2 From e1e1fddae74b72d0415965821ad00fe39aac6f13 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 20 Oct 2014 14:02:15 +0200 Subject: arm64/mm: add explicit struct_mm argument to __create_mapping() Currently, swapper_pg_dir and idmap_pg_dir share the init_mm mm_struct instance. To allow the introduction of other pg_dir instances, for instance, for UEFI's mapping of Runtime Services, make the struct_mm instance an explicit argument that gets passed down to the pmd and pte instantiation functions. Note that the consumers (pmd_populate/pgd_populate) of the mm_struct argument don't actually inspect it, but let's fix it for correctness' sake. Acked-by: Steve Capper Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 6032f3e..7d5dfe2 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -156,9 +156,9 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, } while (pte++, addr += PAGE_SIZE, addr != end); } -static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, - unsigned long end, phys_addr_t phys, - int map_io) +static void __init alloc_init_pmd(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, + phys_addr_t phys, int map_io) { pmd_t *pmd; unsigned long next; @@ -178,7 +178,7 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, */ if (pud_none(*pud) || pud_bad(*pud)) { pmd = early_alloc(PTRS_PER_PMD * sizeof(pmd_t)); - pud_populate(&init_mm, pud, pmd); + pud_populate(mm, pud, pmd); } pmd = pmd_offset(pud, addr); @@ -202,16 +202,16 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, } while (pmd++, addr = next, addr != end); } -static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, - unsigned long end, phys_addr_t phys, - int map_io) +static void __init alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, + phys_addr_t phys, int map_io) { pud_t *pud; unsigned long next; if (pgd_none(*pgd)) { pud = early_alloc(PTRS_PER_PUD * sizeof(pud_t)); - pgd_populate(&init_mm, pgd, pud); + pgd_populate(mm, pgd, pud); } BUG_ON(pgd_bad(*pgd)); @@ -240,7 +240,7 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, flush_tlb_all(); } } else { - alloc_init_pmd(pud, addr, next, phys, map_io); + alloc_init_pmd(mm, pud, addr, next, phys, map_io); } phys += next - addr; } while (pud++, addr = next, addr != end); @@ -250,9 +250,9 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, * Create the page directory entries and any necessary page tables for the * mapping specified by 'md'. */ -static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys, - unsigned long virt, phys_addr_t size, - int map_io) +static void __init __create_mapping(struct mm_struct *mm, pgd_t *pgd, + phys_addr_t phys, unsigned long virt, + phys_addr_t size, int map_io) { unsigned long addr, length, end, next; @@ -262,7 +262,7 @@ static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys, end = addr + length; do { next = pgd_addr_end(addr, end); - alloc_init_pud(pgd, addr, next, phys, map_io); + alloc_init_pud(mm, pgd, addr, next, phys, map_io); phys += next - addr; } while (pgd++, addr = next, addr != end); } @@ -275,7 +275,8 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt, &phys, virt); return; } - __create_mapping(pgd_offset_k(virt & PAGE_MASK), phys, virt, size, 0); + __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt, + size, 0); } void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) @@ -284,7 +285,7 @@ void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) pr_warn("BUG: not creating id mapping for %pa\n", &addr); return; } - __create_mapping(&idmap_pg_dir[pgd_index(addr)], + __create_mapping(&init_mm, &idmap_pg_dir[pgd_index(addr)], addr, addr, size, map_io); } -- cgit v0.10.2 From 8ce837cee8f51fb0eacb32c85461ea2f0fafc9f8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 20 Oct 2014 15:42:07 +0200 Subject: arm64/mm: add create_pgd_mapping() to create private page tables For UEFI, we need to install the memory mappings used for Runtime Services in a dedicated set of page tables. Add create_pgd_mapping(), which allows us to allocate and install those page table entries early. Reviewed-by: Will Deacon Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index c2f006c..5fd40c4 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -33,5 +33,8 @@ extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); extern void init_mem_pgprot(void); /* create an identity mapping for memory (or io if map_io is true) */ extern void create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io); +extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot); #endif diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 210d632..5907924 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -264,6 +264,11 @@ static inline pmd_t pte_pmd(pte_t pte) return __pmd(pte_val(pte)); } +static inline pgprot_t mk_sect_prot(pgprot_t prot) +{ + return __pgprot(pgprot_val(prot) & ~PTE_TABLE_BIT); +} + /* * THP definitions. */ diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 7d5dfe2..3f3d5aa 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -158,20 +158,10 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, static void __init alloc_init_pmd(struct mm_struct *mm, pud_t *pud, unsigned long addr, unsigned long end, - phys_addr_t phys, int map_io) + phys_addr_t phys, pgprot_t prot) { pmd_t *pmd; unsigned long next; - pmdval_t prot_sect; - pgprot_t prot_pte; - - if (map_io) { - prot_sect = PROT_SECT_DEVICE_nGnRE; - prot_pte = __pgprot(PROT_DEVICE_nGnRE); - } else { - prot_sect = PROT_SECT_NORMAL_EXEC; - prot_pte = PAGE_KERNEL_EXEC; - } /* * Check for initial section mappings in the pgd/pud and remove them. @@ -187,7 +177,8 @@ static void __init alloc_init_pmd(struct mm_struct *mm, pud_t *pud, /* try section mapping first */ if (((addr | next | phys) & ~SECTION_MASK) == 0) { pmd_t old_pmd =*pmd; - set_pmd(pmd, __pmd(phys | prot_sect)); + set_pmd(pmd, __pmd(phys | + pgprot_val(mk_sect_prot(prot)))); /* * Check for previous table entries created during * boot (__create_page_tables) and flush them. @@ -196,7 +187,7 @@ static void __init alloc_init_pmd(struct mm_struct *mm, pud_t *pud, flush_tlb_all(); } else { alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), - prot_pte); + prot); } phys += next - addr; } while (pmd++, addr = next, addr != end); @@ -204,7 +195,7 @@ static void __init alloc_init_pmd(struct mm_struct *mm, pud_t *pud, static void __init alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, unsigned long addr, unsigned long end, - phys_addr_t phys, int map_io) + phys_addr_t phys, pgprot_t prot) { pud_t *pud; unsigned long next; @@ -222,10 +213,11 @@ static void __init alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, /* * For 4K granule only, attempt to put down a 1GB block */ - if (!map_io && (PAGE_SHIFT == 12) && + if ((PAGE_SHIFT == 12) && ((addr | next | phys) & ~PUD_MASK) == 0) { pud_t old_pud = *pud; - set_pud(pud, __pud(phys | PROT_SECT_NORMAL_EXEC)); + set_pud(pud, __pud(phys | + pgprot_val(mk_sect_prot(prot)))); /* * If we have an old value for a pud, it will @@ -240,7 +232,7 @@ static void __init alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, flush_tlb_all(); } } else { - alloc_init_pmd(mm, pud, addr, next, phys, map_io); + alloc_init_pmd(mm, pud, addr, next, phys, prot); } phys += next - addr; } while (pud++, addr = next, addr != end); @@ -252,7 +244,7 @@ static void __init alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, */ static void __init __create_mapping(struct mm_struct *mm, pgd_t *pgd, phys_addr_t phys, unsigned long virt, - phys_addr_t size, int map_io) + phys_addr_t size, pgprot_t prot) { unsigned long addr, length, end, next; @@ -262,7 +254,7 @@ static void __init __create_mapping(struct mm_struct *mm, pgd_t *pgd, end = addr + length; do { next = pgd_addr_end(addr, end); - alloc_init_pud(mm, pgd, addr, next, phys, map_io); + alloc_init_pud(mm, pgd, addr, next, phys, prot); phys += next - addr; } while (pgd++, addr = next, addr != end); } @@ -276,7 +268,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt, return; } __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt, - size, 0); + size, PAGE_KERNEL_EXEC); } void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) @@ -286,7 +278,16 @@ void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) return; } __create_mapping(&init_mm, &idmap_pg_dir[pgd_index(addr)], - addr, addr, size, map_io); + addr, addr, size, + map_io ? __pgprot(PROT_DEVICE_nGnRE) + : PAGE_KERNEL_EXEC); +} + +void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot) +{ + __create_mapping(mm, pgd_offset(mm, virt), phys, virt, size, prot); } static void __init map_mem(void) -- cgit v0.10.2 From 7bb68410ef22067b08fd52887875b8f337f89dcc Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Sat, 18 Oct 2014 15:04:15 +0200 Subject: efi: split off remapping code from efi_config_init() Split of the remapping code from efi_config_init() so that the caller can perform its own remapping. This is necessary to correctly handle virtually remapped UEFI memory regions under kexec, as efi.systab will have been updated to a virtual address. Acked-by: Matt Fleming Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 9035c1b..b7ba9d8 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -293,29 +293,15 @@ static __init int match_config_table(efi_guid_t *guid, return 0; } -int __init efi_config_init(efi_config_table_type_t *arch_tables) +int __init efi_config_parse_tables(void *config_tables, int count, int sz, + efi_config_table_type_t *arch_tables) { - void *config_tables, *tablep; - int i, sz; - - if (efi_enabled(EFI_64BIT)) - sz = sizeof(efi_config_table_64_t); - else - sz = sizeof(efi_config_table_32_t); - - /* - * Let's see what config tables the firmware passed to us. - */ - config_tables = early_memremap(efi.systab->tables, - efi.systab->nr_tables * sz); - if (config_tables == NULL) { - pr_err("Could not map Configuration table!\n"); - return -ENOMEM; - } + void *tablep; + int i; tablep = config_tables; pr_info(""); - for (i = 0; i < efi.systab->nr_tables; i++) { + for (i = 0; i < count; i++) { efi_guid_t guid; unsigned long table; @@ -328,8 +314,6 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables) if (table64 >> 32) { pr_cont("\n"); pr_err("Table located above 4GB, disabling EFI.\n"); - early_memunmap(config_tables, - efi.systab->nr_tables * sz); return -EINVAL; } #endif @@ -344,13 +328,37 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables) tablep += sz; } pr_cont("\n"); - early_memunmap(config_tables, efi.systab->nr_tables * sz); - set_bit(EFI_CONFIG_TABLES, &efi.flags); - return 0; } +int __init efi_config_init(efi_config_table_type_t *arch_tables) +{ + void *config_tables; + int sz, ret; + + if (efi_enabled(EFI_64BIT)) + sz = sizeof(efi_config_table_64_t); + else + sz = sizeof(efi_config_table_32_t); + + /* + * Let's see what config tables the firmware passed to us. + */ + config_tables = early_memremap(efi.systab->tables, + efi.systab->nr_tables * sz); + if (config_tables == NULL) { + pr_err("Could not map Configuration table!\n"); + return -ENOMEM; + } + + ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz, + arch_tables); + + early_memunmap(config_tables, efi.systab->nr_tables * sz); + return ret; +} + #ifdef CONFIG_EFI_VARS_MODULE static int __init efi_load_efivars(void) { diff --git a/include/linux/efi.h b/include/linux/efi.h index 0238d61..5ffe511 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -875,6 +875,8 @@ static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned lon #endif extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr); extern int efi_config_init(efi_config_table_type_t *arch_tables); +extern int efi_config_parse_tables(void *config_tables, int count, int sz, + efi_config_table_type_t *arch_tables); extern u64 efi_get_iobase (void); extern u32 efi_mem_type (unsigned long phys_addr); extern u64 efi_mem_attributes (unsigned long phys_addr); -- cgit v0.10.2 From cf2b0f102cdf912eedb87b10271fa0ad582cf2c1 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 17 Nov 2014 13:46:44 +0100 Subject: efi: efistub: allow allocation alignment larger than EFI_PAGE_SIZE On systems with 64 KB pages, it is preferable for UEFI memory map entries to be 64 KB aligned multiples of 64 KB, because it relieves us of having to deal with the residues. So, if EFI_ALLOC_ALIGN is #define'd by the platform, use it to round up all memory allocations made. Acked-by: Matt Fleming Acked-by: Borislav Petkov Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index a920fec..e766df6 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,6 +32,15 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; +/* + * Allow the platform to override the allocation granularity: this allows + * systems that have the capability to run with a larger page size to deal + * with the allocations for initrd and fdt more efficiently. + */ +#ifndef EFI_ALLOC_ALIGN +#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE +#endif + struct file_info { efi_file_handle_t *handle; u64 size; @@ -150,10 +159,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, * a specific address. We are doing page-based allocations, * so we must be aligned to a page. */ - if (align < EFI_PAGE_SIZE) - align = EFI_PAGE_SIZE; + if (align < EFI_ALLOC_ALIGN) + align = EFI_ALLOC_ALIGN; - nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; again: for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; @@ -235,10 +244,10 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, * a specific address. We are doing page-based allocations, * so we must be aligned to a page. */ - if (align < EFI_PAGE_SIZE) - align = EFI_PAGE_SIZE; + if (align < EFI_ALLOC_ALIGN) + align = EFI_ALLOC_ALIGN; - nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; unsigned long m = (unsigned long)map; @@ -292,7 +301,7 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, if (!size) return; - nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; efi_call_early(free_pages, addr, nr_pages); } @@ -561,7 +570,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, * to the preferred address. If that fails, allocate as low * as possible while respecting the required alignment. */ - nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, nr_pages, &efi_addr); -- cgit v0.10.2 From 1bd0abb0c924a8b28c6466cdd6bb34ea053541dc Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 17 Nov 2014 13:50:21 +0100 Subject: arm64/efi: set EFI_ALLOC_ALIGN to 64 KB Set EFI_ALLOC_ALIGN to 64 KB so that all allocations done by the stub are naturally compatible with a 64 KB granule kernel. Acked-by: Leif Lindholm Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index a34fd3b..7129125 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -44,4 +44,6 @@ extern void efi_idmap_init(void); #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) +#define EFI_ALLOC_ALIGN SZ_64K + #endif /* _ASM_EFI_H */ -- cgit v0.10.2 From b8aed6ea39a70a9b9b8de9df8655ac36719b4d3b Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 8 Jan 2015 14:51:36 -0800 Subject: HID: rmi: Use hid_report_len to compute the size of reports Now that hid_report_len is in hid.h we can use this function instead of duplicating the code which computes it. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 018f80f..6270d2c 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -1007,7 +1007,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) goto start; } - data->input_report_size = (input_report->size >> 3) + 1 /* report id */; + data->input_report_size = hid_report_len(input_report); if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, RMI_WRITE_REPORT_ID, &output_report)) { @@ -1016,8 +1016,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) goto start; } - data->output_report_size = (output_report->size >> 3) - + 1 /* report id */; + data->output_report_size = hid_report_len(output_report); data->device_flags |= RMI_DEVICE; alloc_size = data->output_report_size + data->input_report_size; -- cgit v0.10.2 From 79364d87af239e2029aeba3b82bd79c355b9bb86 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 8 Jan 2015 14:51:34 -0800 Subject: HID: rmi: Support touchpads with external buttons The external buttons on HID touchpads are connected as pass through devices and button events are not reported in the rmi registers. As a result on these devices we need to allow the HID generic desktop button events to be processed by hid-input. Unfortunately, there is no way to query the touchpad to determine that it has pass through buttons so the RMI_DEVICE_HAS_PHYS_BUTTONS should be set manually when adding the device to rmi_id[]. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 6270d2c..4bf43c8 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -35,6 +35,7 @@ /* device flags */ #define RMI_DEVICE BIT(0) +#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) enum rmi_mode_type { RMI_MODE_OFF = 0, @@ -472,6 +473,15 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, if ((data->device_flags & RMI_DEVICE) && (field->application == HID_GD_POINTER || field->application == HID_GD_MOUSE)) { + if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) { + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) + return 0; + + if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y) + && !value) + return 1; + } + rmi_schedule_reset(hdev); return 1; } @@ -942,8 +952,13 @@ static int rmi_input_mapping(struct hid_device *hdev, * we want to make HID ignore the advertised HID collection * for RMI deivces */ - if (data->device_flags & RMI_DEVICE) + if (data->device_flags & RMI_DEVICE) { + if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) && + ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)) + return 0; + return -1; + } return 0; } @@ -991,6 +1006,9 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } + if (id->driver_data) + data->device_flags = id->driver_data; + /* * Check for the RMI specific report ids. If they are misisng * simply return and let the events be processed by hid-input -- cgit v0.10.2 From e9287099ba6539bccb20cd791269186f3ae28b85 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 8 Jan 2015 14:51:35 -0800 Subject: HID: rmi: Add support for the touchpad in the Razer Blade 14 laptop Have hid-rmi handle all of the Razer Blade HID devices that are part of the composite USB device. This will allow hid-rmi to operate the touchpad in rmi mode while passing events from the other devices to hid-input. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 81665b4..ef718f9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1982,6 +1982,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7460f34..7d0912d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -767,6 +767,9 @@ #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 +#define USB_VENDOR_ID_RAZER 0x1532 +#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D + #define USB_VENDOR_ID_REALTEK 0x0bda #define USB_DEVICE_ID_REALTEK_READER 0x0152 diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 4bf43c8..49d4fe4 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -1082,6 +1082,8 @@ static void rmi_remove(struct hid_device *hdev) } static const struct hid_device_id rmi_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14), + .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { } }; -- cgit v0.10.2 From 373a5356dfb75ea7140f8d37cf26eb6a62910617 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 9 Jan 2015 11:04:50 -0800 Subject: HID: wacom: process invalid Cintiq and Intuos data in wacom_intuos_inout() Users may use unsupported tools on Cintiq or Intuos. When invalid tools or data are detected, they should be ignored. That is, no event from those tools should be reported. Consolidating that code in wacom_intuos_inout simplifies the logic and make it easier for future code change. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 596a6fb5..5276689 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -534,9 +534,24 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 1; } + /* + * don't report events for invalid data + */ /* older I4 styli don't work with new Cintiqs */ - if (!((wacom->id[idx] >> 20) & 0x01) && - (features->type == WACOM_21UX2)) + if ((!((wacom->id[idx] >> 20) & 0x01) && + (features->type == WACOM_21UX2)) || + /* Only large Intuos support Lense Cursor */ + (wacom->tool[idx] == BTN_TOOL_LENS && + (features->type == INTUOS3 || + features->type == INTUOS3S || + features->type == INTUOS4 || + features->type == INTUOS4S || + features->type == INTUOS5 || + features->type == INTUOS5S || + features->type == INTUOSPM || + features->type == INTUOSPS)) || + /* Cintiq doesn't send data when RDY bit isn't set */ + (features->type == CINTIQ && !(data[1] & 0x40))) return 1; /* Range Report */ @@ -553,6 +568,10 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; + /* don't report exit if we don't know the ID */ + if (!wacom->id[idx]) + return 1; + /* * Reset all states otherwise we lose the initial states * when in-prox next time @@ -585,6 +604,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) wacom->id[idx] = 0; return 2; } + + /* don't report other events if we don't know the ID */ + if (!wacom->id[idx]) + return 1; + return 0; } @@ -842,28 +866,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) if (result) return result - 1; - /* don't proceed if we don't know the ID */ - if (!wacom->id[idx]) - return 0; - - /* Only large Intuos support Lense Cursor */ - if (wacom->tool[idx] == BTN_TOOL_LENS && - (features->type == INTUOS3 || - features->type == INTUOS3S || - features->type == INTUOS4 || - features->type == INTUOS4S || - features->type == INTUOS5 || - features->type == INTUOS5S || - features->type == INTUOSPM || - features->type == INTUOSPS)) { - - return 0; - } - - /* Cintiq doesn't send data when RDY bit isn't set */ - if (features->type == CINTIQ && !(data[1] & 0x40)) - return 0; - if (features->type >= INTUOS3S) { input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); -- cgit v0.10.2 From b3bd7ef397a6031f5398c76a9a0b0695a38f6587 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 9 Jan 2015 11:05:13 -0800 Subject: HID: wacom: peport In Range event according to the spec Some Cintiq and Intuos tablets report In Range event. This event is sent before valid data is reported when tool enters proximity; or before out of proximity event is reported when tool exits. While entering proximity, In Range means a pen is detected. This information can be used for palm/touch rejection on both pen and touch enabled devices. While exiting, it means the tool has reached its maximum detectable distance. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 5276689..a4ba8ca 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -443,9 +443,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { - if (features->quirks & WACOM_QUIRK_MULTI_INPUT) - wacom->shared->stylus_in_proximity = true; - /* serial number of the tool */ wacom->serial[idx] = ((data[3] & 0x0f) << 28) + (data[4] << 20) + (data[5] << 12) + @@ -554,19 +551,22 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) (features->type == CINTIQ && !(data[1] & 0x40))) return 1; - /* Range Report */ - if ((data[1] & 0xfe) == 0x20) { + if (features->quirks & WACOM_QUIRK_MULTI_INPUT) + wacom->shared->stylus_in_proximity = true; + + /* in Range while exiting */ + if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) { input_report_key(input, BTN_TOUCH, 0); input_report_abs(input, ABS_PRESSURE, 0); input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max); - if (features->quirks & WACOM_QUIRK_MULTI_INPUT) - wacom->shared->stylus_in_proximity = true; + return 2; } /* Exit report */ if ((data[1] & 0xfe) == 0x80) { if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; + wacom->reporting_data = false; /* don't report exit if we don't know the ID */ if (!wacom->id[idx]) @@ -952,6 +952,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */ input_report_key(input, wacom->tool[idx], 1); input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + wacom->reporting_data = true; return 1; } diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 7afd929..72e78cc 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -189,6 +189,7 @@ struct wacom_wac { int tool[2]; int id[2]; __u32 serial[2]; + bool reporting_data; struct wacom_features features; struct wacom_shared *shared; struct input_dev *input; -- cgit v0.10.2 From bbe48dd811474adc2df96803f910d4dc2b5e5bde Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 10 Jan 2015 19:13:32 +0100 Subject: udf: destroy sbi mutex in put_super Call mutex_destroy() on superblock mutex in udf_put_super() otherwise mutex debugging code isn't able to detect that mutex is used after being freed. (thanks to Jan Kara for complete definition). Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara diff --git a/fs/udf/super.c b/fs/udf/super.c index 3ccb2f1..3d35a75 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2300,6 +2300,7 @@ static void udf_put_super(struct super_block *sb) udf_close_lvid(sb); brelse(sbi->s_lvid_bh); udf_sb_free_partitions(sb); + mutex_destroy(&sbi->s_alloc_mutex); kfree(sb->s_fs_info); sb->s_fs_info = NULL; } -- cgit v0.10.2 From 2859dff97e54db4795b8b7d9606cb8efcec722ff Mon Sep 17 00:00:00 2001 From: Steve McIntyre Date: Fri, 9 Jan 2015 15:29:53 +0000 Subject: efi: Expose underlying UEFI firmware platform size to userland In some cases (e.g. Intel Bay Trail machines), the kernel will happily run in 64-bit even if the underlying UEFI firmware platform is 32-bit. That's great, but it's difficult for userland utilities like grub-install to do the right thing in such a situation. The kernel already knows about the size of the firmware via efi_enabled(EFI_64BIT). Add an extra sysfs interface /sys/firmware/efi/fw_platform_size to expose that information to userland for low-level utilities to use. Signed-off-by: Steve McIntyre Cc: Matthew Garrett Signed-off-by: Matt Fleming diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index ff0bbe3..9bdbc05 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -112,15 +112,24 @@ EFI_ATTR_SHOW(fw_vendor); EFI_ATTR_SHOW(runtime); EFI_ATTR_SHOW(config_table); +static ssize_t fw_platform_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32); +} + static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor); static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime); static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table); +static struct kobj_attribute efi_attr_fw_platform_size = + __ATTR_RO(fw_platform_size); static struct attribute *efi_subsys_attrs[] = { &efi_attr_systab.attr, &efi_attr_fw_vendor.attr, &efi_attr_runtime.attr, &efi_attr_config_table.attr, + &efi_attr_fw_platform_size.attr, NULL, }; -- cgit v0.10.2 From cb16ef384f15d33a53b4db47878aa818be059d77 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 12 Jan 2015 11:38:55 +0530 Subject: mpt2sas: MPI2 Rev AA (2.00.19) specifications Below is the changeset from the MPI specification and 2.00.34 header files: 1) Defined additional bits in the BiosOptions field of BIOS Page 1 to allow for finer control of X86 BIOS and UEFI BSD. 2) For the Clean Tool, reserved bit 26 of the Flags field for product specific use. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 088eefa..76cde3f 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.32 + * mpi2.h Version: 02.00.34 * * Version History * --------------- @@ -83,6 +83,8 @@ * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. + * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 510ef0d..f055310 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.26 + * mpi2_cnfg.h Version: 02.00.28 * * Version History * --------------- @@ -157,6 +157,18 @@ * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to * match the specification. + * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for + * MPI2_CONFIG_PAGE_MAN_7. + * Added EnclosureLevel and ConnectorName fields to + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added EnclosureLevel field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 01-08-14 02.00.28 Added more defines for the BiosOptions field of + * MPI2_CONFIG_PAGE_BIOS_1. * -------------------------------------------------------------------------- */ @@ -706,6 +718,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 #define MPI2_MANUFACTURING7_PAGEVERSION (0x01) /* defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) #define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) @@ -1235,9 +1248,17 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 } MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; -#define MPI2_BIOSPAGE1_PAGEVERSION (0x05) +#define MPI2_BIOSPAGE1_PAGEVERSION (0x06) /* values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) + +#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) +#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) +#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) + #define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) #define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) @@ -2420,13 +2441,13 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 U8 PortGroups; /* 0x2C */ U8 DmaGroup; /* 0x2D */ U8 ControlGroup; /* 0x2E */ - U8 Reserved1; /* 0x2F */ - U32 Reserved2; /* 0x30 */ + U8 EnclosureLevel; /* 0x2F */ + U8 ConnectorName[4]; /* 0x30 */ U32 Reserved3; /* 0x34 */ } MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; -#define MPI2_SASDEVICE0_PAGEVERSION (0x08) +#define MPI2_SASDEVICE0_PAGEVERSION (0x09) /* values for SAS Device Page 0 AccessStatus field */ #define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) @@ -2464,6 +2485,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 #define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) #define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) #define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) #define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) @@ -2732,7 +2754,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 U16 EnclosureHandle; /* 0x16 */ U16 NumSlots; /* 0x18 */ U16 StartSlot; /* 0x1A */ - U16 Reserved2; /* 0x1C */ + U8 Reserved2; /* 0x1C */ + U8 EnclosureLevel; /* 0x1D */ U16 SEPDevHandle; /* 0x1E */ U32 Reserved3; /* 0x20 */ U32 Reserved4; /* 0x24 */ @@ -2740,9 +2763,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; -#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03) +#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) /* values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) #define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) #define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) #define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 2c3b0f2..b02de48 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.23 + * mpi2_ioc.h Version: 02.00.24 * * Version History * --------------- @@ -126,6 +126,7 @@ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. * Added Encrypted Hash Extended Image. + * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. * -------------------------------------------------------------------------- */ @@ -1589,6 +1590,7 @@ Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t; /* values for HashImageType */ #define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) #define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) +#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) /* values for HashAlgorithm */ #define MPI25_HASH_ALGORITHM_UNUSED (0x00) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 9be03ed..659b8ac 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -6,7 +6,7 @@ * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * - * mpi2_tool.h Version: 02.00.11 + * mpi2_tool.h Version: 02.00.12 * * Version History * --------------- @@ -29,7 +29,8 @@ * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that * it uses MPI Chain SGE as well as MPI Simple SGE. - * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- */ @@ -101,6 +102,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST #define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) #define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) #define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000) #define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) #define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) #define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) -- cgit v0.10.2 From ecedf5c8ed978116c57b4661651747d4bf3387b5 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Sun, 11 Jan 2015 21:58:55 +0800 Subject: spi: sirf: add missed devicetree binding document Signed-off-by: Barry Song Signed-off-by: Qipan Li Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/spi/spi-sirf.txt b/Documentation/devicetree/bindings/spi/spi-sirf.txt new file mode 100644 index 0000000..4c7adb8f --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sirf.txt @@ -0,0 +1,41 @@ +* CSR SiRFprimaII Serial Peripheral Interface + +Required properties: +- compatible : Should be "sirf,prima2-spi" +- reg : Offset and length of the register set for the device +- interrupts : Should contain SPI interrupt +- resets: phandle to the reset controller asserting this device in + reset + See ../reset/reset.txt for details. +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + +- #address-cells: Number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: Should be zero. + +Optional properties: +- spi-max-frequency: Specifies maximum SPI clock frequency, + Units - Hz. Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt +- cs-gpios: should specify GPIOs used for chipselects. + +Example: + +spi0: spi@b00d0000 { + compatible = "sirf,prima2-spi"; + reg = <0xb00d0000 0x10000>; + interrupts = <15>; + dmas = <&dmac1 9>, + <&dmac1 4>; + dma-names = "rx", "tx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clks 19>; + resets = <&rstc 26>; +}; -- cgit v0.10.2 From bdb2c74d44be691e6d3b6d441e81ea13dab34145 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 12 Jan 2015 13:54:13 +0100 Subject: ASoC: ad193x: Don't power down DAC in CODEC probe The DAC powerdown bit is managed by DAPM. Manually powering down the DAC in the CODEC probe function may cause unnecessary power state transitions which can lead to click and pop noises. So leave the DAC powerdown bit in its default poweron-reset state and let DAPM do all the management. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 387530b..17c9535 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -333,8 +333,8 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec) regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0); /* de-emphasis: 48kHz, powedown dac */ regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A); - /* powerdown dac, dac in tdm mode */ - regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41); + /* dac in tdm mode */ + regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40); /* high-pass filter enable */ regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3); /* sata delay=1, adc aux mode */ -- cgit v0.10.2 From cfcefe01265cbaf5ca7209226d043b07bfa8b587 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Jan 2015 01:52:36 +0000 Subject: ASoC: rsnd: add recovery support for under/over flow error on SRC L/R channel will be switched if under/over flow error happen on Renesas R-Car sound device by the HW bugs. Then, HW restart is required for salvage. This patch add salvage support for SRC. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 83284ca..4cecd0c 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -55,6 +55,7 @@ struct rsnd_ssi_platform_info { struct rsnd_src_platform_info { u32 convert_rate; /* sampling rate convert */ int dma_id; /* for Gen2 SCU */ + int irq; }; /* diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 87a6f2d..de0685f 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -309,8 +309,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), + RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), + RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), + RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc), + RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0), + RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4), RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), @@ -403,6 +408,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev, RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40), + /* + * ADD US + * + * SRC_STATUS + * SRC_INT_EN + * SCU_SYS_STATUS0 + * SCU_SYS_STATUS1 + * SCU_SYS_INT_EN0 + * SCU_SYS_INT_EN1 + */ }; struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5826c8a..c457003 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -44,6 +44,8 @@ enum rsnd_reg { RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSVR, RSND_REG_SRC_SRCCR, + RSND_REG_SCU_SYS_STATUS0, + RSND_REG_SCU_SYS_INT_EN0, RSND_REG_CMD_ROUTE_SLCT, RSND_REG_DVC_SWRSR, RSND_REG_DVC_DVUIR, @@ -94,6 +96,9 @@ enum rsnd_reg { RSND_REG_SHARE23, RSND_REG_SHARE24, RSND_REG_SHARE25, + RSND_REG_SHARE26, + RSND_REG_SHARE27, + RSND_REG_SHARE28, RSND_REG_MAX, }; @@ -135,6 +140,9 @@ enum rsnd_reg { #define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 #define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 #define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 +#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26 +#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27 +#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28 struct rsnd_of_data; struct rsnd_priv; diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index eede3ac..648b35e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -12,10 +12,18 @@ #define SRC_NAME "src" +/* SRCx_STATUS */ +#define OUF_SRCO ((1 << 12) | (1 << 13)) +#define OUF_SRCI ((1 << 9) | (1 << 8)) + +/* SCU_SYSTEM_STATUS0/1 */ +#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) + struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct clk *clk; + int err; }; #define RSND_SRC_NAME_SIZE 16 @@ -280,6 +288,8 @@ static int rsnd_src_init(struct rsnd_mod *mod, clk_prepare_enable(src->clk); + src->err = 0; + /* * Initialize the operation of the SRC internal circuits * see rsnd_src_start() @@ -293,9 +303,14 @@ static int rsnd_src_quit(struct rsnd_mod *mod, struct rsnd_dai *rdai) { struct rsnd_src *src = rsnd_mod_to_src(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); clk_disable_unprepare(src->clk); + if (src->err) + dev_warn(dev, "src under/over flow err = %d\n", src->err); + return 0; } @@ -510,6 +525,110 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { /* * Gen2 functions */ +#define rsnd_src_irq_enable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 1) +#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0) +static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 sys_int_val, int_val, sys_int_mask; + int irq = src->info->irq; + int id = rsnd_mod_id(mod); + + sys_int_val = + sys_int_mask = OUF_SRC(id); + int_val = 0x3300; + + /* + * IRQ is not supported on non-DT + * see + * rsnd_src_probe_gen2() + */ + if ((irq <= 0) || !enable) { + sys_int_val = 0; + int_val = 0; + } + + rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); + rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); + rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); +} + +static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) +{ + u32 val = OUF_SRC(rsnd_mod_id(mod)); + + rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val); + rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); +} + +static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) +{ + u32 val = OUF_SRC(rsnd_mod_id(mod)); + bool ret = false; + + if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) || + (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) { + struct rsnd_src *src = rsnd_mod_to_src(mod); + + src->err++; + ret = true; + } + + /* clear error static */ + rsnd_src_error_clear_gen2(mod); + + return ret; +} + +static int _rsnd_src_start_gen2(struct rsnd_mod *mod) +{ + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; + + rsnd_mod_write(mod, SRC_CTRL, val); + + rsnd_src_error_clear_gen2(mod); + + rsnd_src_start(mod); + + rsnd_src_irq_enable_gen2(mod); + + return 0; +} + +static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) +{ + rsnd_src_irq_disable_gen2(mod); + + rsnd_mod_write(mod, SRC_CTRL, 0); + + rsnd_src_error_record_gen2(mod); + + return rsnd_src_stop(mod); +} + +static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) +{ + struct rsnd_mod *mod = data; + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + + if (!io) + return IRQ_NONE; + + if (rsnd_src_error_record_gen2(mod)) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + _rsnd_src_stop_gen2(mod); + _rsnd_src_start_gen2(mod); + + dev_dbg(dev, "%s[%d] restart\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + } + + return IRQ_HANDLED; +} + static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, struct rsnd_dai *rdai) { @@ -588,18 +707,38 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_src *src = rsnd_mod_to_src(mod); struct device *dev = rsnd_priv_to_dev(priv); + int irq = src->info->irq; int ret; + if (irq > 0) { + /* + * IRQ is not supported on non-DT + * see + * rsnd_src_irq_enable_gen2() + */ + ret = devm_request_irq(dev, irq, + rsnd_src_interrupt_gen2, + IRQF_SHARED, + dev_name(dev), mod); + if (ret) + goto rsnd_src_probe_gen2_fail; + } + ret = rsnd_dma_init(priv, rsnd_mod_to_dma(mod), rsnd_info_is_playback(priv, src), src->info->dma_id); - if (ret < 0) - dev_err(dev, "%s[%d] (Gen2) failed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - else - dev_dbg(dev, "%s[%d] (Gen2) is probed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + if (ret) + goto rsnd_src_probe_gen2_fail; + + dev_dbg(dev, "%s[%d] (Gen2) is probed\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + + return ret; + +rsnd_src_probe_gen2_fail: + dev_err(dev, "%s[%d] (Gen2) failed\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); return ret; } @@ -635,27 +774,21 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, static int rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_dai *rdai) { - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; - - rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); + rsnd_dma_start(rsnd_mod_to_dma(mod)); - rsnd_mod_write(mod, SRC_CTRL, val); - - return rsnd_src_start(mod); + return _rsnd_src_start_gen2(mod); } static int rsnd_src_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai *rdai) { - struct rsnd_src *src = rsnd_mod_to_src(mod); + int ret; - rsnd_mod_write(mod, SRC_CTRL, 0); + ret = _rsnd_src_stop_gen2(mod); - rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); + rsnd_dma_stop(rsnd_mod_to_dma(mod)); - return rsnd_src_stop(mod); + return ret; } static struct rsnd_mod_ops rsnd_src_gen2_ops = { @@ -681,10 +814,11 @@ static void rsnd_of_parse_src(struct platform_device *pdev, struct rsnd_priv *priv) { struct device_node *src_node; + struct device_node *np; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct rsnd_src_platform_info *src_info; struct device *dev = &pdev->dev; - int nr; + int nr, i; if (!of_data) return; @@ -708,6 +842,13 @@ static void rsnd_of_parse_src(struct platform_device *pdev, info->src_info = src_info; info->src_info_nr = nr; + i = 0; + for_each_child_of_node(src_node, np) { + src_info[i].irq = irq_of_parse_and_map(np, 0); + + i++; + } + rsnd_of_parse_src_end: of_node_put(src_node); } -- cgit v0.10.2 From 2de5a9c004e92aaf49b800e60820f7a030d42eb9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 12 Jan 2015 14:57:44 +0200 Subject: sata_dwc_460ex: disable compilation on ARM and ARM64 For now disable the compilation of the driver on ARM and ARM64. In the future we will fix the DMA handling in that driver and re-enable compilation back. Reported-by: kbuild test robot Signed-off-by: Andy Shevchenko Signed-off-by: Tejun Heo diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 5ed20e3..9f2ba27 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -269,7 +269,7 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" - depends on 460EX || COMPILE_TEST + depends on 460EX || (COMPILE_TEST && !(ARM || ARM64)) help This option enables support for the on-chip SATA controller of the AppliedMicro processor 460EX. -- cgit v0.10.2 From 1730fd9cce32ba88d9b157546044b2b07db9c936 Mon Sep 17 00:00:00 2001 From: David Flater Date: Sun, 11 Jan 2015 16:08:58 -0500 Subject: ALSA: fix emu8000 DRAM sizing for AWE64 Value Applicable to any kernel since 2013: The special case added in commit 1338fc97d07a did not handle the possibility that the address space on an AWE64 Value would wrap around at 512 KiB. That is what it does, so the memory is still not detected on those cards. Fix that with a logic clean-up that eliminates the need for a special case. Signed-off-by: David Flater Signed-off-by: Takashi Iwai diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 45fcdff..d25e384 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -378,13 +378,12 @@ init_arrays(struct snd_emu8000 *emu) static void size_dram(struct snd_emu8000 *emu) { - int i, size, detected_size; + int i, size; if (emu->dram_checked) return; size = 0; - detected_size = 0; /* write out a magic number */ snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE); @@ -392,10 +391,19 @@ size_dram(struct snd_emu8000 *emu) EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET); EMU8000_SMLD_WRITE(emu, UNIQUE_ID1); snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */ + snd_emu8000_write_wait(emu); - while (size < EMU8000_MAX_DRAM) { + /* + * Detect first 512 KiB. If a write succeeds at the beginning of a + * 512 KiB page we assume that the whole page is there. + */ + EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET); + EMU8000_SMLD_READ(emu); /* discard stale data */ + if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1) + goto skip_detect; /* No RAM */ + snd_emu8000_read_wait(emu); - size += 512 * 1024; /* increment 512kbytes */ + for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) { /* Write a unique data on the test address. * if the address is out of range, the data is written on @@ -431,18 +439,9 @@ size_dram(struct snd_emu8000 *emu) snd_emu8000_read_wait(emu); /* Otherwise, it's valid memory. */ - detected_size = size + 512 * 1024; - } - - /* Distinguish 512 KiB from 0. */ - if (detected_size == 0) { - snd_emu8000_read_wait(emu); - EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET); - EMU8000_SMLD_READ(emu); /* discard stale data */ - if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1) - detected_size = 512 * 1024; } +skip_detect: /* wait until FULL bit in SMAxW register is false */ for (i = 0; i < 10000; i++) { if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0) @@ -455,9 +454,9 @@ size_dram(struct snd_emu8000 *emu) snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE); snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n", - emu->port1, detected_size/1024); + emu->port1, size/1024); - emu->mem_size = detected_size; + emu->mem_size = size; emu->dram_checked = 1; } -- cgit v0.10.2 From d2866409baaf644c8f875498b05fd3adf26fcdcd Mon Sep 17 00:00:00 2001 From: David Flater Date: Sun, 11 Jan 2015 16:10:07 -0500 Subject: ALSA: log emu8000 DRAM size at level INFO Detected sound font memory goes unreported unless the kernel was built with ALSA debugging enabled. Elevate that to a pr_info. Signed-off-by: David Flater Signed-off-by: Takashi Iwai diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index d25e384..96e9d94 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -453,7 +453,7 @@ skip_detect: snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE); snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE); - snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n", + pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n", emu->port1, size/1024); emu->mem_size = size; -- cgit v0.10.2 From a4972b1b9a04439c2dc15a98b333ed28378d3509 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 11 Jan 2015 18:57:10 +0100 Subject: edac: i5100_edac: Remove unused i5100_recmema_dm_buf_id Remove the function i5100_recmema_dm_buf_id() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Link: http://lkml.kernel.org/r/1420999030-21770-1-git-send-email-rickard_strandqvist@spectrumdigital.se Signed-off-by: Borislav Petkov diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 6247d18..e9f8a39 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -279,11 +279,6 @@ static inline u32 i5100_recmema_rank(u32 a) return i5100_nrecmema_rank(a); } -static inline u32 i5100_recmema_dm_buf_id(u32 a) -{ - return i5100_nrecmema_dm_buf_id(a); -} - static inline u32 i5100_recmemb_cas(u32 a) { return i5100_nrecmemb_cas(a); -- cgit v0.10.2 From 6c869d301bda3f672f001e2c9fcb01685000fc83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Jan 2015 16:56:51 +0100 Subject: ALSA: rme*: Use snd_pcm_format_t Fix sparse warnings below by using snd_pcm_format_t properly: sound/pci/rme32.c:682:60: sparse: incorrect type in argument 2 (different base types) sound/pci/rme96.c:1006:69: sparse: incorrect type in argument 2 (different base types) ..... Signed-off-by: Takashi Iwai diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 6c60dcd..1a7affa 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -632,7 +632,7 @@ snd_rme32_setframelog(struct rme32 * rme32, int n_channels, int is_playback) } } -static int snd_rme32_setformat(struct rme32 * rme32, int format) +static int snd_rme32_setformat(struct rme32 *rme32, snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S16_LE: diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index e33e79e..236ac1d 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -922,8 +922,7 @@ snd_rme96_setframelog(struct rme96 *rme96, } static int -snd_rme96_playback_setformat(struct rme96 *rme96, - int format) +snd_rme96_playback_setformat(struct rme96 *rme96, snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S16_LE: @@ -940,8 +939,7 @@ snd_rme96_playback_setformat(struct rme96 *rme96, } static int -snd_rme96_capture_setformat(struct rme96 *rme96, - int format) +snd_rme96_capture_setformat(struct rme96 *rme96, snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S16_LE: -- cgit v0.10.2 From f3cdfd239da56a4cea75a2920dc326f0f45f67e3 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 20 Oct 2014 16:27:26 +0200 Subject: arm64/efi: move SetVirtualAddressMap() to UEFI stub In order to support kexec, the kernel needs to be able to deal with the state of the UEFI firmware after SetVirtualAddressMap() has been called. To avoid having separate code paths for non-kexec and kexec, let's move the call to SetVirtualAddressMap() to the stub: this will guarantee us that it will only be called once (since the stub is not executed during kexec), and ensures that the UEFI state is identical between kexec and normal boot. This implies that the layout of the virtual mapping needs to be created by the stub as well. All regions are rounded up to a naturally aligned multiple of 64 KB (for compatibility with 64k pages kernels) and recorded in the UEFI memory map. The kernel proper reads those values and installs the mappings in a dedicated set of page tables that are swapped in during UEFI Runtime Services calls. Acked-by: Leif Lindholm Acked-by: Matt Fleming Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 7129125..effef37 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -7,28 +7,36 @@ #ifdef CONFIG_EFI extern void efi_init(void); extern void efi_idmap_init(void); +extern void efi_virtmap_init(void); #else #define efi_init() #define efi_idmap_init() +#define efi_virtmap_init() #endif #define efi_call_virt(f, ...) \ ({ \ - efi_##f##_t *__f = efi.systab->runtime->f; \ + efi_##f##_t *__f; \ efi_status_t __s; \ \ kernel_neon_begin(); \ + efi_virtmap_load(); \ + __f = efi.systab->runtime->f; \ __s = __f(__VA_ARGS__); \ + efi_virtmap_unload(); \ kernel_neon_end(); \ __s; \ }) #define __efi_call_virt(f, ...) \ ({ \ - efi_##f##_t *__f = efi.systab->runtime->f; \ + efi_##f##_t *__f; \ \ kernel_neon_begin(); \ + efi_virtmap_load(); \ + __f = efi.systab->runtime->f; \ __f(__VA_ARGS__); \ + efi_virtmap_unload(); \ kernel_neon_end(); \ }) @@ -46,4 +54,26 @@ extern void efi_idmap_init(void); #define EFI_ALLOC_ALIGN SZ_64K +/* + * On ARM systems, virtually remapped UEFI runtime services are set up in three + * distinct stages: + * - The stub retrieves the final version of the memory map from UEFI, populates + * the virt_addr fields and calls the SetVirtualAddressMap() [SVAM] runtime + * service to communicate the new mapping to the firmware (Note that the new + * mapping is not live at this time) + * - During early boot, the page tables are allocated and populated based on the + * virt_addr fields in the memory map, but only if all descriptors with the + * EFI_MEMORY_RUNTIME attribute have a non-zero value for virt_addr. If this + * succeeds, the EFI_VIRTMAP flag is set to indicate that the virtual mappings + * have been installed successfully. + * - During an early initcall(), the UEFI Runtime Services are enabled and the + * EFI_RUNTIME_SERVICES bit set if some conditions are met, i.e., we need a + * non-early mapping of the UEFI system table, and we need to have the virtmap + * installed. + */ +#define EFI_VIRTMAP EFI_ARCH_1 + +void efi_virtmap_load(void); +void efi_virtmap_unload(void); + #endif /* _ASM_EFI_H */ diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 2bb4347..755e545 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -11,25 +11,31 @@ * */ +#include #include #include #include #include +#include #include #include #include +#include +#include +#include #include #include +#include #include #include #include #include +#include +#include struct efi_memory_map memmap; -static efi_runtime_services_t *runtime; - static u64 efi_system_table; static int uefi_debug __initdata; @@ -69,9 +75,33 @@ static void __init efi_setup_idmap(void) } } +/* + * Translate a EFI virtual address into a physical address: this is necessary, + * as some data members of the EFI system table are virtually remapped after + * SetVirtualAddressMap() has been called. + */ +static phys_addr_t efi_to_phys(unsigned long addr) +{ + efi_memory_desc_t *md; + + for_each_efi_memory_desc(&memmap, md) { + if (!(md->attribute & EFI_MEMORY_RUNTIME)) + continue; + if (md->virt_addr == 0) + /* no virtual mapping has been installed by the stub */ + break; + if (md->virt_addr <= addr && + (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT)) + return md->phys_addr + addr - md->virt_addr; + } + return addr; +} + static int __init uefi_init(void) { efi_char16_t *c16; + void *config_tables; + u64 table_size; char vendor[100] = "unknown"; int i, retval; @@ -99,7 +129,7 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0xffff); /* Show what we know for posterity */ - c16 = early_memremap(efi.systab->fw_vendor, + c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor), sizeof(vendor)); if (c16) { for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) @@ -112,8 +142,14 @@ static int __init uefi_init(void) efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor); - retval = efi_config_init(NULL); + table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; + config_tables = early_memremap(efi_to_phys(efi.systab->tables), + table_size); + + retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, + sizeof(efi_config_table_64_t), NULL); + early_memunmap(config_tables, table_size); out: early_memunmap(efi.systab, sizeof(efi_system_table_t)); return retval; @@ -329,51 +365,14 @@ void __init efi_idmap_init(void) early_memunmap(memmap.map, memmap.map_end - memmap.map); } -static int __init remap_region(efi_memory_desc_t *md, void **new) -{ - u64 paddr, vaddr, npages, size; - - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - - if (is_normal_ram(md)) - vaddr = (__force u64)ioremap_cache(paddr, size); - else - vaddr = (__force u64)ioremap(paddr, size); - - if (!vaddr) { - pr_err("Unable to remap 0x%llx pages @ %p\n", - npages, (void *)paddr); - return 0; - } - - /* adjust for any rounding when EFI and system pagesize differs */ - md->virt_addr = vaddr + (md->phys_addr - paddr); - - if (uefi_debug) - pr_info(" EFI remap 0x%012llx => %p\n", - md->phys_addr, (void *)md->virt_addr); - - memcpy(*new, md, memmap.desc_size); - *new += memmap.desc_size; - - return 1; -} - /* - * Switch UEFI from an identity map to a kernel virtual map + * Enable the UEFI Runtime Services if all prerequisites are in place, i.e., + * non-early mapping of the UEFI system table and virtual mappings for all + * EFI_MEMORY_RUNTIME regions. */ -static int __init arm64_enter_virtual_mode(void) +static int __init arm64_enable_runtime_services(void) { - efi_memory_desc_t *md; - phys_addr_t virtmap_phys; - void *virtmap, *virt_md; - efi_status_t status; u64 mapsize; - int count = 0; - unsigned long flags; if (!efi_enabled(EFI_BOOT)) { pr_info("EFI services will not be available.\n"); @@ -395,81 +394,30 @@ static int __init arm64_enter_virtual_mode(void) efi.memmap = &memmap; - /* Map the runtime regions */ - virtmap = kmalloc(mapsize, GFP_KERNEL); - if (!virtmap) { - pr_err("Failed to allocate EFI virtual memmap\n"); - return -1; - } - virtmap_phys = virt_to_phys(virtmap); - virt_md = virtmap; - - for_each_efi_memory_desc(&memmap, md) { - if (!(md->attribute & EFI_MEMORY_RUNTIME)) - continue; - if (!remap_region(md, &virt_md)) - goto err_unmap; - ++count; - } - - efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table); + efi.systab = (__force void *)ioremap_cache(efi_system_table, + sizeof(efi_system_table_t)); if (!efi.systab) { - /* - * If we have no virtual mapping for the System Table at this - * point, the memory map doesn't cover the physical offset where - * it resides. This means the System Table will be inaccessible - * to Runtime Services themselves once the virtual mapping is - * installed. - */ - pr_err("Failed to remap EFI System Table -- buggy firmware?\n"); - goto err_unmap; + pr_err("Failed to remap EFI System Table\n"); + return -1; } set_bit(EFI_SYSTEM_TABLES, &efi.flags); - local_irq_save(flags); - cpu_switch_mm(idmap_pg_dir, &init_mm); - - /* Call SetVirtualAddressMap with the physical address of the map */ - runtime = efi.systab->runtime; - efi.set_virtual_address_map = runtime->set_virtual_address_map; - - status = efi.set_virtual_address_map(count * memmap.desc_size, - memmap.desc_size, - memmap.desc_version, - (efi_memory_desc_t *)virtmap_phys); - cpu_set_reserved_ttbr0(); - flush_tlb_all(); - local_irq_restore(flags); - - kfree(virtmap); - free_boot_services(); - if (status != EFI_SUCCESS) { - pr_err("Failed to set EFI virtual address map! [%lx]\n", - status); + if (!efi_enabled(EFI_VIRTMAP)) { + pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); return -1; } /* Set up runtime services function pointers */ - runtime = efi.systab->runtime; efi_native_runtime_setup(); set_bit(EFI_RUNTIME_SERVICES, &efi.flags); efi.runtime_version = efi.systab->hdr.revision; return 0; - -err_unmap: - /* unmap all mappings that succeeded: there are 'count' of those */ - for (virt_md = virtmap; count--; virt_md += memmap.desc_size) { - md = virt_md; - iounmap((__force void __iomem *)md->virt_addr); - } - kfree(virtmap); - return -1; } -early_initcall(arm64_enter_virtual_mode); +early_initcall(arm64_enable_runtime_services); static int __init arm64_dmi_init(void) { @@ -484,3 +432,79 @@ static int __init arm64_dmi_init(void) return 0; } core_initcall(arm64_dmi_init); + +static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss; + +static struct mm_struct efi_mm = { + .mm_rb = RB_ROOT, + .pgd = efi_pgd, + .mm_users = ATOMIC_INIT(2), + .mm_count = ATOMIC_INIT(1), + .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), + .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), + .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), + INIT_MM_CONTEXT(efi_mm) +}; + +static void efi_set_pgd(struct mm_struct *mm) +{ + cpu_switch_mm(mm->pgd, mm); + flush_tlb_all(); + if (icache_is_aivivt()) + __flush_icache_all(); +} + +void efi_virtmap_load(void) +{ + preempt_disable(); + efi_set_pgd(&efi_mm); +} + +void efi_virtmap_unload(void) +{ + efi_set_pgd(current->active_mm); + preempt_enable(); +} + +void __init efi_virtmap_init(void) +{ + efi_memory_desc_t *md; + + if (!efi_enabled(EFI_BOOT)) + return; + + for_each_efi_memory_desc(&memmap, md) { + u64 paddr, npages, size; + pgprot_t prot; + + if (!(md->attribute & EFI_MEMORY_RUNTIME)) + continue; + if (WARN(md->virt_addr == 0, + "UEFI virtual mapping incomplete or missing -- no entry found for 0x%llx\n", + md->phys_addr)) + return; + + paddr = md->phys_addr; + npages = md->num_pages; + memrange_efi_to_native(&paddr, &npages); + size = npages << PAGE_SHIFT; + + pr_info(" EFI remap 0x%016llx => %p\n", + md->phys_addr, (void *)md->virt_addr); + + /* + * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be + * executable, everything else can be mapped with the XN bits + * set. + */ + if (!is_normal_ram(md)) + prot = __pgprot(PROT_DEVICE_nGnRE); + else if (md->type == EFI_RUNTIME_SERVICES_CODE) + prot = PAGE_KERNEL_EXEC; + else + prot = PAGE_KERNEL; + + create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot); + } + set_bit(EFI_VIRTMAP, &efi.flags); +} diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 20fe293..beac818 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -401,6 +401,7 @@ void __init setup_arch(char **cmdline_p) paging_init(); request_standard_resources(); + efi_virtmap_init(); efi_idmap_init(); early_ioremap_reset(); diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index eb48a1a..e2432b3 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -295,3 +295,62 @@ fail_free_image: fail: return EFI_ERROR; } + +/* + * This is the base address at which to start allocating virtual memory ranges + * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use + * any allocation we choose, and eliminate the risk of a conflict after kexec. + * The value chosen is the largest non-zero power of 2 suitable for this purpose + * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can + * be mapped efficiently. + */ +#define EFI_RT_VIRTUAL_BASE 0x40000000 + +/* + * efi_get_virtmap() - create a virtual mapping for the EFI memory map + * + * This function populates the virt_addr fields of all memory region descriptors + * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors + * are also copied to @runtime_map, and their total count is returned in @count. + */ +void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, + unsigned long desc_size, efi_memory_desc_t *runtime_map, + int *count) +{ + u64 efi_virt_base = EFI_RT_VIRTUAL_BASE; + efi_memory_desc_t *out = runtime_map; + int l; + + for (l = 0; l < map_size; l += desc_size) { + efi_memory_desc_t *in = (void *)memory_map + l; + u64 paddr, size; + + if (!(in->attribute & EFI_MEMORY_RUNTIME)) + continue; + + /* + * Make the mapping compatible with 64k pages: this allows + * a 4k page size kernel to kexec a 64k page size kernel and + * vice versa. + */ + paddr = round_down(in->phys_addr, SZ_64K); + size = round_up(in->num_pages * EFI_PAGE_SIZE + + in->phys_addr - paddr, SZ_64K); + + /* + * Avoid wasting memory on PTEs by choosing a virtual base that + * is compatible with section mappings if this region has the + * appropriate size and physical alignment. (Sections are 2 MB + * on 4k granule kernels) + */ + if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M) + efi_virt_base = round_up(efi_virt_base, SZ_2M); + + in->virt_addr = efi_virt_base + in->phys_addr - paddr; + efi_virt_base += size; + + memcpy(out, in, desc_size); + out = (void *)out + desc_size; + ++*count; + } +} diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 304ab29..2be1098 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -39,4 +39,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, void *get_fdt(efi_system_table_t *sys_table); +void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, + unsigned long desc_size, efi_memory_desc_t *runtime_map, + int *count); + #endif diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index c846a96..91da56c 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -14,6 +14,8 @@ #include #include +#include "efistub.h" + efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, @@ -193,9 +195,26 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, unsigned long map_size, desc_size; u32 desc_ver; unsigned long mmap_key; - efi_memory_desc_t *memory_map; + efi_memory_desc_t *memory_map, *runtime_map; unsigned long new_fdt_size; efi_status_t status; + int runtime_entry_count = 0; + + /* + * Get a copy of the current memory map that we will use to prepare + * the input for SetVirtualAddressMap(). We don't have to worry about + * subsequent allocations adding entries, since they could not affect + * the number of EFI_MEMORY_RUNTIME regions. + */ + status = efi_get_memory_map(sys_table, &runtime_map, &map_size, + &desc_size, &desc_ver, &mmap_key); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n"); + return status; + } + + pr_efi(sys_table, + "Exiting boot services and installing virtual address map...\n"); /* * Estimate size of new FDT, and allocate memory for it. We @@ -248,12 +267,48 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, } } + /* + * Update the memory map with virtual addresses. The function will also + * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME + * entries so that we can pass it straight into SetVirtualAddressMap() + */ + efi_get_virtmap(memory_map, map_size, desc_size, runtime_map, + &runtime_entry_count); + /* Now we are ready to exit_boot_services.*/ status = sys_table->boottime->exit_boot_services(handle, mmap_key); + if (status == EFI_SUCCESS) { + efi_set_virtual_address_map_t *svam; - if (status == EFI_SUCCESS) - return status; + /* Install the new virtual address map */ + svam = sys_table->runtime->set_virtual_address_map; + status = svam(runtime_entry_count * desc_size, desc_size, + desc_ver, runtime_map); + + /* + * We are beyond the point of no return here, so if the call to + * SetVirtualAddressMap() failed, we need to signal that to the + * incoming kernel but proceed normally otherwise. + */ + if (status != EFI_SUCCESS) { + int l; + + /* + * Set the virtual address field of all + * EFI_MEMORY_RUNTIME entries to 0. This will signal + * the incoming kernel that no virtual translation has + * been installed. + */ + for (l = 0; l < map_size; l += desc_size) { + efi_memory_desc_t *p = (void *)memory_map + l; + + if (p->attribute & EFI_MEMORY_RUNTIME) + p->virt_addr = 0; + } + } + return EFI_SUCCESS; + } pr_efi_err(sys_table, "Exit boot services failed.\n"); @@ -264,6 +319,7 @@ fail_free_new_fdt: efi_free(sys_table, new_fdt_size, *new_fdt_addr); fail: + sys_table->boottime->free_pool(runtime_map); return EFI_LOAD_ERROR; } -- cgit v0.10.2 From 3033b84596eaec0093b68c5711c265738eb0745d Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 20 Oct 2014 16:35:21 +0200 Subject: arm64/efi: remove free_boot_services() and friends Now that we are calling SetVirtualAddressMap() from the stub, there is no need to reserve boot-only memory regions, which implies that there is also no reason to free them again later. Acked-by: Leif Lindholm Acked-by: Will Deacon Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 755e545..4a5d734 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -199,9 +199,7 @@ static __init void reserve_regions(void) if (is_normal_ram(md)) early_init_dt_add_memory_arch(paddr, size); - if (is_reserve_region(md) || - md->type == EFI_BOOT_SERVICES_CODE || - md->type == EFI_BOOT_SERVICES_DATA) { + if (is_reserve_region(md)) { memblock_reserve(paddr, size); if (uefi_debug) pr_cont("*"); @@ -214,123 +212,6 @@ static __init void reserve_regions(void) set_bit(EFI_MEMMAP, &efi.flags); } - -static u64 __init free_one_region(u64 start, u64 end) -{ - u64 size = end - start; - - if (uefi_debug) - pr_info(" EFI freeing: 0x%012llx-0x%012llx\n", start, end - 1); - - free_bootmem_late(start, size); - return size; -} - -static u64 __init free_region(u64 start, u64 end) -{ - u64 map_start, map_end, total = 0; - - if (end <= start) - return total; - - map_start = (u64)memmap.phys_map; - map_end = PAGE_ALIGN(map_start + (memmap.map_end - memmap.map)); - map_start &= PAGE_MASK; - - if (start < map_end && end > map_start) { - /* region overlaps UEFI memmap */ - if (start < map_start) - total += free_one_region(start, map_start); - - if (map_end < end) - total += free_one_region(map_end, end); - } else - total += free_one_region(start, end); - - return total; -} - -static void __init free_boot_services(void) -{ - u64 total_freed = 0; - u64 keep_end, free_start, free_end; - efi_memory_desc_t *md; - - /* - * If kernel uses larger pages than UEFI, we have to be careful - * not to inadvertantly free memory we want to keep if there is - * overlap at the kernel page size alignment. We do not want to - * free is_reserve_region() memory nor the UEFI memmap itself. - * - * The memory map is sorted, so we keep track of the end of - * any previous region we want to keep, remember any region - * we want to free and defer freeing it until we encounter - * the next region we want to keep. This way, before freeing - * it, we can clip it as needed to avoid freeing memory we - * want to keep for UEFI. - */ - - keep_end = 0; - free_start = 0; - - for_each_efi_memory_desc(&memmap, md) { - u64 paddr, npages, size; - - if (is_reserve_region(md)) { - /* - * We don't want to free any memory from this region. - */ - if (free_start) { - /* adjust free_end then free region */ - if (free_end > md->phys_addr) - free_end -= PAGE_SIZE; - total_freed += free_region(free_start, free_end); - free_start = 0; - } - keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - continue; - } - - if (md->type != EFI_BOOT_SERVICES_CODE && - md->type != EFI_BOOT_SERVICES_DATA) { - /* no need to free this region */ - continue; - } - - /* - * We want to free memory from this region. - */ - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - - if (free_start) { - if (paddr <= free_end) - free_end = paddr + size; - else { - total_freed += free_region(free_start, free_end); - free_start = paddr; - free_end = paddr + size; - } - } else { - free_start = paddr; - free_end = paddr + size; - } - if (free_start < keep_end) { - free_start += PAGE_SIZE; - if (free_start >= free_end) - free_start = 0; - } - } - if (free_start) - total_freed += free_region(free_start, free_end); - - if (total_freed) - pr_info("Freed 0x%llx bytes of EFI boot services memory", - total_freed); -} - void __init efi_init(void) { struct efi_fdt_params params; @@ -402,8 +283,6 @@ static int __init arm64_enable_runtime_services(void) } set_bit(EFI_SYSTEM_TABLES, &efi.flags); - free_boot_services(); - if (!efi_enabled(EFI_VIRTMAP)) { pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); return -1; -- cgit v0.10.2 From 9679be103108926cfe9e6fd2f6829cefa77e47b0 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 20 Oct 2014 16:41:38 +0200 Subject: arm64/efi: remove idmap manipulations from UEFI code Now that we have moved the call to SetVirtualAddressMap() to the stub, UEFI has no use for the ID map, so we can drop the code that installs ID mappings for UEFI memory regions. Acked-by: Leif Lindholm Acked-by: Will Deacon Tested-by: Leif Lindholm Signed-off-by: Ard Biesheuvel diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index effef37..7baf2cc 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -6,11 +6,9 @@ #ifdef CONFIG_EFI extern void efi_init(void); -extern void efi_idmap_init(void); extern void efi_virtmap_init(void); #else #define efi_init() -#define efi_idmap_init() #define efi_virtmap_init() #endif diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 5fd40c4..3d31176 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -31,8 +31,6 @@ extern void paging_init(void); extern void setup_mm_for_reboot(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); extern void init_mem_pgprot(void); -/* create an identity mapping for memory (or io if map_io is true) */ -extern void create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io); extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot); diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 4a5d734..a98415b 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -54,27 +54,6 @@ static int __init is_normal_ram(efi_memory_desc_t *md) return 0; } -static void __init efi_setup_idmap(void) -{ - struct memblock_region *r; - efi_memory_desc_t *md; - u64 paddr, npages, size; - - for_each_memblock(memory, r) - create_id_mapping(r->base, r->size, 0); - - /* map runtime io spaces */ - for_each_efi_memory_desc(&memmap, md) { - if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md)) - continue; - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - create_id_mapping(paddr, size, 1); - } -} - /* * Translate a EFI virtual address into a physical address: this is necessary, * as some data members of the EFI system table are virtually remapped after @@ -236,16 +215,6 @@ void __init efi_init(void) reserve_regions(); } -void __init efi_idmap_init(void) -{ - if (!efi_enabled(EFI_BOOT)) - return; - - /* boot time idmap_pg_dir is incomplete, so fill in missing parts */ - efi_setup_idmap(); - early_memunmap(memmap.map, memmap.map_end - memmap.map); -} - /* * Enable the UEFI Runtime Services if all prerequisites are in place, i.e., * non-early mapping of the UEFI system table and virtual mappings for all @@ -386,4 +355,5 @@ void __init efi_virtmap_init(void) create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot); } set_bit(EFI_VIRTMAP, &efi.flags); + early_memunmap(memmap.map, memmap.map_end - memmap.map); } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index beac818..199d1b7 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -402,7 +402,6 @@ void __init setup_arch(char **cmdline_p) request_standard_resources(); efi_virtmap_init(); - efi_idmap_init(); early_ioremap_reset(); unflatten_device_tree(); diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 3f3d5aa..3286385 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -271,18 +271,6 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt, size, PAGE_KERNEL_EXEC); } -void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) -{ - if ((addr >> PGDIR_SHIFT) >= ARRAY_SIZE(idmap_pg_dir)) { - pr_warn("BUG: not creating id mapping for %pa\n", &addr); - return; - } - __create_mapping(&init_mm, &idmap_pg_dir[pgd_index(addr)], - addr, addr, size, - map_io ? __pgprot(PROT_DEVICE_nGnRE) - : PAGE_KERNEL_EXEC); -} - void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot) -- cgit v0.10.2 From a248ce068f560ece6b72eb75b54380e3d800cbab Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Mon, 12 Jan 2015 12:42:34 -0800 Subject: staging: line6: toneport.c: Fix for possible null pointer dereference The NULL check was done to late, and there it was a risk of a possible null pointer dereference. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 6943715..660dc3f 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -433,12 +433,16 @@ void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) void line6_toneport_disconnect(struct usb_interface *interface) { struct usb_line6_toneport *toneport; + struct snd_line6_pcm *line6pcm; u16 idProduct; if (interface == NULL) return; toneport = usb_get_intfdata(interface); + if (NULL == toneport) + return; + del_timer_sync(&toneport->timer); idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); @@ -447,13 +451,10 @@ void line6_toneport_disconnect(struct usb_interface *interface) device_remove_file(&interface->dev, &dev_attr_led_green); } - if (toneport != NULL) { - struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; - - if (line6pcm != NULL) { - line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); - line6_pcm_disconnect(line6pcm); - } + line6pcm = toneport->line6.line6pcm; + if (line6pcm != NULL) { + line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); + line6_pcm_disconnect(line6pcm); } toneport_destruct(interface); -- cgit v0.10.2 From 690ea44ede52e3e45eeab3b0e9704d7c3b258ae5 Mon Sep 17 00:00:00 2001 From: Jonas Lundqvist Date: Mon, 12 Jan 2015 12:42:35 -0800 Subject: Staging: line6: remove spaces before commas. Fix three space prohibited errors in pcm.h found by checkpatch.pl. Signed-off-by: Jonas Lundqvist Reviewed-by: Jeremiah Mahler Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h index 6aa0d46..5d87934 100644 --- a/drivers/staging/line6/pcm.h +++ b/drivers/staging/line6/pcm.h @@ -145,21 +145,21 @@ enum { LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | #endif LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER , + LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, LINE6_BITS_PLAYBACK_STREAM = #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | #endif LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM , + LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, LINE6_BITS_CAPTURE_BUFFER = #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | #endif LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER , + LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, LINE6_BITS_CAPTURE_STREAM = #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE -- cgit v0.10.2 From 5c3396f909aa02d0b7337258c78bd872510e837d Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:36 -0800 Subject: staging: line6: Remove `device_bit' from properties The `device_bit' member was no longer used as of commit 2807904441d4 (staging: line6: drop MIDI parameter sysfs attrs). Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 503b2d7..15f3bc4 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -57,32 +57,32 @@ static const struct usb_device_id line6_id_table[] = { MODULE_DEVICE_TABLE(usb, line6_id_table); -#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\ - {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\ +#define L6PROP(dev_id, dev_name, dev_cap)\ + {.id = dev_id,\ .name = dev_name, .capabilities = LINE6_BIT_##dev_cap} /* *INDENT-OFF* */ static const struct line6_properties line6_properties_table[] = { - L6PROP(BASSPODXT, "BassPODxt", "BassPODxt", CTRL_PCM_HW), - L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW), - L6PROP(BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW), - L6PROP(GUITARPORT, "GuitarPort", "GuitarPort", PCM), - L6PROP(POCKETPOD, "PocketPOD", "Pocket POD", CONTROL), - L6PROP(PODHD300, "PODHD300", "POD HD300", CTRL_PCM_HW), - L6PROP(PODHD400, "PODHD400", "POD HD400", CTRL_PCM_HW), - L6PROP(PODHD500, "PODHD500", "POD HD500", CTRL_PCM_HW), - L6PROP(PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", PCM), - L6PROP(PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", PCM), - L6PROP(PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", PCM), - L6PROP(PODX3, "PODX3", "POD X3", PCM), - L6PROP(PODX3LIVE, "PODX3Live", "POD X3 Live", PCM), - L6PROP(PODXT, "PODxt", "PODxt", CTRL_PCM_HW), - L6PROP(PODXTLIVE, "PODxtLive", "PODxt Live", CTRL_PCM_HW), - L6PROP(PODXTPRO, "PODxtPro", "PODxt Pro", CTRL_PCM_HW), - L6PROP(TONEPORT_GX, "TonePortGX", "TonePort GX", PCM), - L6PROP(TONEPORT_UX1, "TonePortUX1", "TonePort UX1", PCM), - L6PROP(TONEPORT_UX2, "TonePortUX2", "TonePort UX2", PCM), - L6PROP(VARIAX, "Variax", "Variax Workbench", CONTROL), + L6PROP("BassPODxt", "BassPODxt", CTRL_PCM_HW), + L6PROP("BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW), + L6PROP("BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW), + L6PROP("GuitarPort", "GuitarPort", PCM), + L6PROP("PocketPOD", "Pocket POD", CONTROL), + L6PROP("PODHD300", "POD HD300", CTRL_PCM_HW), + L6PROP("PODHD400", "POD HD400", CTRL_PCM_HW), + L6PROP("PODHD500", "POD HD500", CTRL_PCM_HW), + L6PROP("PODStudioGX", "POD Studio GX", PCM), + L6PROP("PODStudioUX1", "POD Studio UX1", PCM), + L6PROP("PODStudioUX2", "POD Studio UX2", PCM), + L6PROP("PODX3", "POD X3", PCM), + L6PROP("PODX3Live", "POD X3 Live", PCM), + L6PROP("PODxt", "PODxt", CTRL_PCM_HW), + L6PROP("PODxtLive", "PODxt Live", CTRL_PCM_HW), + L6PROP("PODxtPro", "PODxt Pro", CTRL_PCM_HW), + L6PROP("TonePortGX", "TonePort GX", PCM), + L6PROP("TonePortUX1", "TonePort UX1", PCM), + L6PROP("TonePortUX2", "TonePort UX2", PCM), + L6PROP("Variax", "Variax Workbench", CONTROL), }; /* *INDENT-ON* */ diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 16e3fc2..1cc7532 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -76,11 +76,6 @@ static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; */ struct line6_properties { /** - Bit identifying this device in the line6usb driver. - */ - int device_bit; - - /** Card id string (maximum 16 characters). This can be used to address the device in ALSA programs as "default:CARD=" diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h index 5d87934..4f60823 100644 --- a/drivers/staging/line6/pcm.h +++ b/drivers/staging/line6/pcm.h @@ -98,6 +98,8 @@ enum { LINE6_INDEX_PAUSE_PLAYBACK, LINE6_INDEX_PREPARED, +#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x + /* individual bit masks: */ LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index 2d1cc47..2bc2fe7 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -40,65 +40,6 @@ #define LINE6_DEVID_TONEPORT_UX2 0x4142 #define LINE6_DEVID_VARIAX 0x534d -#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x - -enum { - LINE6_INDEX_BASSPODXT, - LINE6_INDEX_BASSPODXTLIVE, - LINE6_INDEX_BASSPODXTPRO, - LINE6_INDEX_GUITARPORT, - LINE6_INDEX_POCKETPOD, - LINE6_INDEX_PODHD300, - LINE6_INDEX_PODHD400, - LINE6_INDEX_PODHD500, - LINE6_INDEX_PODSTUDIO_GX, - LINE6_INDEX_PODSTUDIO_UX1, - LINE6_INDEX_PODSTUDIO_UX2, - LINE6_INDEX_PODX3, - LINE6_INDEX_PODX3LIVE, - LINE6_INDEX_PODXT, - LINE6_INDEX_PODXTLIVE, - LINE6_INDEX_PODXTPRO, - LINE6_INDEX_TONEPORT_GX, - LINE6_INDEX_TONEPORT_UX1, - LINE6_INDEX_TONEPORT_UX2, - LINE6_INDEX_VARIAX, - - LINE6_BIT(BASSPODXT), - LINE6_BIT(BASSPODXTLIVE), - LINE6_BIT(BASSPODXTPRO), - LINE6_BIT(GUITARPORT), - LINE6_BIT(POCKETPOD), - LINE6_BIT(PODHD300), - LINE6_BIT(PODHD400), - LINE6_BIT(PODHD500), - LINE6_BIT(PODSTUDIO_GX), - LINE6_BIT(PODSTUDIO_UX1), - LINE6_BIT(PODSTUDIO_UX2), - LINE6_BIT(PODX3), - LINE6_BIT(PODX3LIVE), - LINE6_BIT(PODXT), - LINE6_BIT(PODXTLIVE), - LINE6_BIT(PODXTPRO), - LINE6_BIT(TONEPORT_GX), - LINE6_BIT(TONEPORT_UX1), - LINE6_BIT(TONEPORT_UX2), - LINE6_BIT(VARIAX), - - LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO, - LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE | - LINE6_BIT_PODX3LIVE, - LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE | - LINE6_BIT_PODXTPRO, - LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE, - LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 | - LINE6_BIT_PODHD400 | - LINE6_BIT_PODHD500, - LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT | - LINE6_BIT_BASSPODXTLIVE | - LINE6_BIT_BASSPODXTPRO -}; - /* device supports settings parameter via USB */ #define LINE6_BIT_CONTROL (1 << 0) /* device supports PCM input/output via USB */ -- cgit v0.10.2 From c667ee1bac76f52d6fa3bd5430f471213b0e755f Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:37 -0800 Subject: staging: line6: Remove line6_pod_transmit_paramter() This function was no longer used as of commit 2807904441d4 (staging: line6: drop MIDI parameter sysfs attrs). Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index 44f4b2f..7b4ec92 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -159,15 +159,6 @@ void line6_pod_process_message(struct usb_line6_pod *pod) } /* - Transmit PODxt Pro control parameter. -*/ -void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param, - u8 value) -{ - line6_transmit_parameter(&pod->line6, param, value); -} - -/* Send system parameter (from integer). */ static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h index 3e3f167..397d94c 100644 --- a/drivers/staging/line6/pod.h +++ b/drivers/staging/line6/pod.h @@ -96,7 +96,5 @@ extern void line6_pod_disconnect(struct usb_interface *interface); extern int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod); extern void line6_pod_process_message(struct usb_line6_pod *pod); -extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param, - u8 value); #endif -- cgit v0.10.2 From e45bfe5e7c6d8563cad171df052218baa6226fc2 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:38 -0800 Subject: staging: line6: Remove unsupported X3 devices Support for these devices appears to have never been completed. Remove them from the device table along with a minimal amount of supporting code. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 15f3bc4..e40400b 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -43,8 +43,6 @@ static const struct usb_device_id line6_id_table[] = { {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)}, @@ -74,8 +72,6 @@ static const struct line6_properties line6_properties_table[] = { L6PROP("PODStudioGX", "POD Studio GX", PCM), L6PROP("PODStudioUX1", "POD Studio UX1", PCM), L6PROP("PODStudioUX2", "POD Studio UX2", PCM), - L6PROP("PODX3", "POD X3", PCM), - L6PROP("PODX3Live", "POD X3 Live", PCM), L6PROP("PODxt", "PODxt", CTRL_PCM_HW), L6PROP("PODxtLive", "PODxt Live", CTRL_PCM_HW), L6PROP("PODxtPro", "PODxt Pro", CTRL_PCM_HW), @@ -673,8 +669,6 @@ static int line6_probe(struct usb_interface *interface, break; case LINE6_DEVID_PODHD500: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: switch (interface_number) { case 0: alternate = 1; @@ -765,14 +759,6 @@ static int line6_probe(struct usb_interface *interface, ep_write = 0x02; break; - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - /* currently unused! */ - size = sizeof(struct usb_line6_pod); - ep_read = 0x81; - ep_write = 0x01; - break; - case LINE6_DEVID_PODSTUDIO_GX: case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX2: @@ -898,8 +884,6 @@ static int line6_probe(struct usb_interface *interface, case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); @@ -971,14 +955,6 @@ static int line6_probe(struct usb_interface *interface, dev_info(&interface->dev, "Line6 %s now attached\n", line6->properties->name); - switch (product) { - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - dev_info(&interface->dev, - "NOTE: the Line6 %s is detected, but not yet supported\n", - line6->properties->name); - } - /* increment reference counters: */ usb_get_intf(interface); usb_get_dev(usbdev); @@ -1026,8 +1002,6 @@ static void line6_disconnect(struct usb_interface *interface) case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: line6_pod_disconnect(interface); diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index a3136b1..076c87b 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -442,8 +442,6 @@ int line6_init_pcm(struct usb_line6 *line6, break; case LINE6_DEVID_PODHD500: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: ep_read = 0x86; ep_write = 0x02; break; diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index 2bc2fe7..06bf909 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -30,8 +30,6 @@ #define LINE6_DEVID_PODSTUDIO_GX 0x4153 #define LINE6_DEVID_PODSTUDIO_UX1 0x4150 #define LINE6_DEVID_PODSTUDIO_UX2 0x4151 -#define LINE6_DEVID_PODX3 0x414a -#define LINE6_DEVID_PODX3LIVE 0x414b #define LINE6_DEVID_PODXT 0x5044 #define LINE6_DEVID_PODXTLIVE 0x4650 #define LINE6_DEVID_PODXTPRO 0x5050 -- cgit v0.10.2 From daf54a59f37cb156f4d3044810ac4fe2fdb2b208 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:39 -0800 Subject: staging: line6: Cleanup device table Wrap USB_DEVICE to avoid repeating the Line 6 vendor ID. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index e40400b..a263bce 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -30,27 +30,29 @@ #define DRIVER_DESC "Line6 USB Driver" #define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION +#define LINE6_DEVICE(prod) USB_DEVICE(LINE6_VENDOR_ID, prod) + /* table of devices that work with this driver */ static const struct usb_device_id line6_id_table[] = { - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD400)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)}, - {}, + { LINE6_DEVICE(LINE6_DEVID_BASSPODXT) }, + { LINE6_DEVICE(LINE6_DEVID_BASSPODXTLIVE) }, + { LINE6_DEVICE(LINE6_DEVID_BASSPODXTPRO) }, + { LINE6_DEVICE(LINE6_DEVID_GUITARPORT) }, + { LINE6_DEVICE(LINE6_DEVID_POCKETPOD) }, + { LINE6_DEVICE(LINE6_DEVID_PODHD300) }, + { LINE6_DEVICE(LINE6_DEVID_PODHD400) }, + { LINE6_DEVICE(LINE6_DEVID_PODHD500) }, + { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_GX) }, + { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX1) }, + { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX2) }, + { LINE6_DEVICE(LINE6_DEVID_PODXT) }, + { LINE6_DEVICE(LINE6_DEVID_PODXTLIVE) }, + { LINE6_DEVICE(LINE6_DEVID_PODXTPRO) }, + { LINE6_DEVICE(LINE6_DEVID_TONEPORT_GX) }, + { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX1) }, + { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX2) }, + { LINE6_DEVICE(LINE6_DEVID_VARIAX) }, + {} }; MODULE_DEVICE_TABLE(usb, line6_id_table); -- cgit v0.10.2 From 410dca8d99ae508078c90414b19f1758c1b4d6fd Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:40 -0800 Subject: staging: line6: Define a device type enum Define an enum containing the supported devices and associate each entry in the device table to the respective value. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index a263bce..2797e41 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -34,24 +34,42 @@ /* table of devices that work with this driver */ static const struct usb_device_id line6_id_table[] = { - { LINE6_DEVICE(LINE6_DEVID_BASSPODXT) }, - { LINE6_DEVICE(LINE6_DEVID_BASSPODXTLIVE) }, - { LINE6_DEVICE(LINE6_DEVID_BASSPODXTPRO) }, - { LINE6_DEVICE(LINE6_DEVID_GUITARPORT) }, - { LINE6_DEVICE(LINE6_DEVID_POCKETPOD) }, - { LINE6_DEVICE(LINE6_DEVID_PODHD300) }, - { LINE6_DEVICE(LINE6_DEVID_PODHD400) }, - { LINE6_DEVICE(LINE6_DEVID_PODHD500) }, - { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_GX) }, - { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX1) }, - { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX2) }, - { LINE6_DEVICE(LINE6_DEVID_PODXT) }, - { LINE6_DEVICE(LINE6_DEVID_PODXTLIVE) }, - { LINE6_DEVICE(LINE6_DEVID_PODXTPRO) }, - { LINE6_DEVICE(LINE6_DEVID_TONEPORT_GX) }, - { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX1) }, - { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX2) }, - { LINE6_DEVICE(LINE6_DEVID_VARIAX) }, + { LINE6_DEVICE(LINE6_DEVID_BASSPODXT), + .driver_info = LINE6_BASSPODXT }, + { LINE6_DEVICE(LINE6_DEVID_BASSPODXTLIVE), + .driver_info = LINE6_BASSPODXTLIVE }, + { LINE6_DEVICE(LINE6_DEVID_BASSPODXTPRO), + .driver_info = LINE6_BASSPODXTPRO }, + { LINE6_DEVICE(LINE6_DEVID_GUITARPORT), + .driver_info = LINE6_GUITARPORT }, + { LINE6_DEVICE(LINE6_DEVID_POCKETPOD), + .driver_info = LINE6_POCKETPOD }, + { LINE6_DEVICE(LINE6_DEVID_PODHD300), + .driver_info = LINE6_PODHD300 }, + { LINE6_DEVICE(LINE6_DEVID_PODHD400), + .driver_info = LINE6_PODHD400 }, + { LINE6_DEVICE(LINE6_DEVID_PODHD500), + .driver_info = LINE6_PODHD500 }, + { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_GX), + .driver_info = LINE6_PODSTUDIO_GX }, + { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX1), + .driver_info = LINE6_PODSTUDIO_UX1 }, + { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX2), + .driver_info = LINE6_PODSTUDIO_UX2 }, + { LINE6_DEVICE(LINE6_DEVID_PODXT), + .driver_info = LINE6_PODXT }, + { LINE6_DEVICE(LINE6_DEVID_PODXTLIVE), + .driver_info = LINE6_PODXTLIVE }, + { LINE6_DEVICE(LINE6_DEVID_PODXTPRO), + .driver_info = LINE6_PODXTPRO }, + { LINE6_DEVICE(LINE6_DEVID_TONEPORT_GX), + .driver_info = LINE6_TONEPORT_GX }, + { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX1), + .driver_info = LINE6_TONEPORT_UX1 }, + { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX2), + .driver_info = LINE6_TONEPORT_UX2 }, + { LINE6_DEVICE(LINE6_DEVID_VARIAX), + .driver_info = LINE6_VARIAX }, {} }; diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 1cc7532..8fb4a9c 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -20,6 +20,27 @@ #define DRIVER_NAME "line6usb" +enum line6_device_type { + LINE6_BASSPODXT, + LINE6_BASSPODXTLIVE, + LINE6_BASSPODXTPRO, + LINE6_GUITARPORT, + LINE6_POCKETPOD, + LINE6_PODHD300, + LINE6_PODHD400, + LINE6_PODHD500, + LINE6_PODSTUDIO_GX, + LINE6_PODSTUDIO_UX1, + LINE6_PODSTUDIO_UX2, + LINE6_PODXT, + LINE6_PODXTLIVE, + LINE6_PODXTPRO, + LINE6_TONEPORT_GX, + LINE6_TONEPORT_UX1, + LINE6_TONEPORT_UX2, + LINE6_VARIAX +}; + #define LINE6_TIMEOUT 1 #define LINE6_BUFSIZE_LISTEN 32 #define LINE6_MESSAGE_MAXLEN 256 -- cgit v0.10.2 From c33a20b71daf7e7d0d5746200621867ae44d09e9 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:41 -0800 Subject: staging: line6: Index properties array with device type The current logic uses the index of the matched entry from the device table as an offset to the corresponding properties entry. The values of the new `line6_device_type' enum are ordered such that they can be used as an index into either of these arrays. Drop the device entry lookup logic and use the device type (via the .driver_info member) instead. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 2797e41..c090b2b 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -624,7 +624,7 @@ static void line6_destruct(struct usb_interface *interface) static int line6_probe(struct usb_interface *interface, const struct usb_device_id *id) { - int devtype; + enum line6_device_type devtype; struct usb_device *usbdev; struct usb_line6 *line6; const struct line6_properties *properties; @@ -646,20 +646,7 @@ static int line6_probe(struct usb_interface *interface, goto err_put; } - /* check vendor and product id */ - for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) { - u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor); - u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct); - - if (idVendor == line6_id_table[devtype].idVendor && - idProduct == line6_id_table[devtype].idProduct) - break; - } - - if (devtype < 0) { - ret = -ENODEV; - goto err_put; - } + devtype = id->driver_info; /* initialize device info: */ properties = &line6_properties_table[devtype]; -- cgit v0.10.2 From a23a8bff1535ddf2f7b9f358f3eb47973d757c54 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:42 -0800 Subject: staging: line6: Key off of device type The driver currently uses the device's idProduct as input to several switch statements. In some cases this is not sufficiently granular and the interface number must be taken into account. Store the device type in `usb_line6' and key off of it instead. New types can then be added that map to specific interfaces on the device so that this conditional logic can be flattened out. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index c090b2b..81d5a27 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -363,23 +363,23 @@ static void line6_data_received(struct urb *urb) line6->message_length = done; line6_midi_receive(line6, line6->buffer_message, done); - switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - case LINE6_DEVID_POCKETPOD: + switch (line6->type) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_PODXT: + case LINE6_PODXTPRO: + case LINE6_POCKETPOD: line6_pod_process_message((struct usb_line6_pod *) line6); break; - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - case LINE6_DEVID_PODHD500: + case LINE6_PODHD300: + case LINE6_PODHD400: + case LINE6_PODHD500: break; /* let userspace handle MIDI */ - case LINE6_DEVID_PODXTLIVE: + case LINE6_PODXTLIVE: switch (line6->interface_number) { case PODXTLIVE_INTERFACE_POD: line6_pod_process_message((struct usb_line6_pod @@ -399,7 +399,7 @@ static void line6_data_received(struct urb *urb) } break; - case LINE6_DEVID_VARIAX: + case LINE6_VARIAX: line6_variax_process_message((struct usb_line6_variax *) line6); break; @@ -629,7 +629,6 @@ static int line6_probe(struct usb_interface *interface, struct usb_line6 *line6; const struct line6_properties *properties; int interface_number, alternate = 0; - int product; int size = 0; int ep_read = 0, ep_write = 0; int ret; @@ -651,19 +650,18 @@ static int line6_probe(struct usb_interface *interface, /* initialize device info: */ properties = &line6_properties_table[devtype]; dev_info(&interface->dev, "Line6 %s found\n", properties->name); - product = le16_to_cpu(usbdev->descriptor.idProduct); /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - switch (product) { - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_PODXTLIVE: - case LINE6_DEVID_VARIAX: + switch (devtype) { + case LINE6_BASSPODXTLIVE: + case LINE6_PODXTLIVE: + case LINE6_VARIAX: alternate = 1; break; - case LINE6_DEVID_POCKETPOD: + case LINE6_POCKETPOD: switch (interface_number) { case 0: return -ENODEV; /* this interface has no endpoints */ @@ -675,7 +673,7 @@ static int line6_probe(struct usb_interface *interface, } break; - case LINE6_DEVID_PODHD500: + case LINE6_PODHD500: switch (interface_number) { case 0: alternate = 1; @@ -688,25 +686,25 @@ static int line6_probe(struct usb_interface *interface, } break; - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: + case LINE6_BASSPODXT: + case LINE6_BASSPODXTPRO: + case LINE6_PODXT: + case LINE6_PODXTPRO: + case LINE6_PODHD300: + case LINE6_PODHD400: alternate = 5; break; - case LINE6_DEVID_GUITARPORT: - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: + case LINE6_GUITARPORT: + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: alternate = 2; /* 1..4 seem to be ok */ break; - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_PODSTUDIO_UX2: + case LINE6_TONEPORT_UX2: + case LINE6_PODSTUDIO_UX2: switch (interface_number) { case 0: /* defaults to 44.1kHz, 16-bit */ @@ -735,49 +733,49 @@ static int line6_probe(struct usb_interface *interface, goto err_put; } - /* initialize device data based on product id: */ - switch (product) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: + /* initialize device data based on device: */ + switch (devtype) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_PODXT: + case LINE6_PODXTPRO: size = sizeof(struct usb_line6_pod); ep_read = 0x84; ep_write = 0x03; break; - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: + case LINE6_PODHD300: + case LINE6_PODHD400: size = sizeof(struct usb_line6_podhd); ep_read = 0x84; ep_write = 0x03; break; - case LINE6_DEVID_PODHD500: + case LINE6_PODHD500: size = sizeof(struct usb_line6_podhd); ep_read = 0x81; ep_write = 0x01; break; - case LINE6_DEVID_POCKETPOD: + case LINE6_POCKETPOD: size = sizeof(struct usb_line6_pod); ep_read = 0x82; ep_write = 0x02; break; - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: size = sizeof(struct usb_line6_toneport); /* these don't have a control channel */ break; - case LINE6_DEVID_PODXTLIVE: + case LINE6_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: size = sizeof(struct usb_line6_pod); @@ -797,7 +795,7 @@ static int line6_probe(struct usb_interface *interface, } break; - case LINE6_DEVID_VARIAX: + case LINE6_VARIAX: size = sizeof(struct usb_line6_variax); ep_read = 0x82; ep_write = 0x01; @@ -829,7 +827,7 @@ static int line6_probe(struct usb_interface *interface, line6->ifcdev = &interface->dev; line6->ep_control_read = ep_read; line6->ep_control_write = ep_write; - line6->product = product; + line6->type = devtype; /* get data from endpoint descriptor (see usb_maxpacket): */ { @@ -885,25 +883,25 @@ static int line6_probe(struct usb_interface *interface, } } - /* initialize device data based on product id: */ - switch (product) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_POCKETPOD: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: + /* initialize device data based on device: */ + switch (devtype) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_POCKETPOD: + case LINE6_PODXT: + case LINE6_PODXTPRO: ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); break; - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - case LINE6_DEVID_PODHD500: + case LINE6_PODHD300: + case LINE6_PODHD400: + case LINE6_PODHD500: ret = line6_podhd_init(interface, (struct usb_line6_podhd *)line6); break; - case LINE6_DEVID_PODXTLIVE: + case LINE6_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: ret = @@ -926,19 +924,19 @@ static int line6_probe(struct usb_interface *interface, break; - case LINE6_DEVID_VARIAX: + case LINE6_VARIAX: ret = line6_variax_init(interface, (struct usb_line6_variax *)line6); break; - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: ret = line6_toneport_init(interface, (struct usb_line6_toneport *)line6); @@ -1004,23 +1002,23 @@ static void line6_disconnect(struct usb_interface *interface) dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); - switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_POCKETPOD: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: + switch (line6->type) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_POCKETPOD: + case LINE6_PODXT: + case LINE6_PODXTPRO: line6_pod_disconnect(interface); break; - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - case LINE6_DEVID_PODHD500: + case LINE6_PODHD300: + case LINE6_PODHD400: + case LINE6_PODHD500: line6_podhd_disconnect(interface); break; - case LINE6_DEVID_PODXTLIVE: + case LINE6_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: line6_pod_disconnect(interface); @@ -1033,17 +1031,17 @@ static void line6_disconnect(struct usb_interface *interface) break; - case LINE6_DEVID_VARIAX: + case LINE6_VARIAX: line6_variax_disconnect(interface); break; - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: line6_toneport_disconnect(interface); break; @@ -1107,15 +1105,18 @@ static int line6_reset_resume(struct usb_interface *interface) { struct usb_line6 *line6 = usb_get_intfdata(interface); - switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) { - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: + switch (line6->type) { + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: line6_toneport_reset_resume((struct usb_line6_toneport *)line6); + + default: + break; } return line6_resume(interface); diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 8fb4a9c..c536795 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -126,9 +126,9 @@ struct usb_line6 { struct usb_device *usbdev; /** - Product id. + Device type. */ - int product; + enum line6_device_type type; /** Properties. diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 076c87b..86c7bcb 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -427,37 +427,37 @@ int line6_init_pcm(struct usb_line6 *line6, if (!(line6->properties->capabilities & LINE6_BIT_PCM)) return 0; /* skip PCM initialization and report success */ - /* initialize PCM subsystem based on product id: */ - switch (line6->product) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTLIVE: - case LINE6_DEVID_PODXTPRO: - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: + /* initialize PCM subsystem based on device: */ + switch (line6->type) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_PODXT: + case LINE6_PODXTLIVE: + case LINE6_PODXTPRO: + case LINE6_PODHD300: + case LINE6_PODHD400: ep_read = 0x82; ep_write = 0x01; break; - case LINE6_DEVID_PODHD500: + case LINE6_PODHD500: ep_read = 0x86; ep_write = 0x02; break; - case LINE6_DEVID_POCKETPOD: + case LINE6_POCKETPOD: ep_read = 0x82; ep_write = 0x02; break; - case LINE6_DEVID_GUITARPORT: - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: + case LINE6_GUITARPORT: + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: ep_read = 0x82; ep_write = 0x01; break; diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 660dc3f..9e5cee1 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -97,11 +97,11 @@ static const struct { {"Inst & Mic", 0x0901} }; -static bool toneport_has_led(short product) +static bool toneport_has_led(enum line6_device_type type) { return - (product == LINE6_DEVID_GUITARPORT) || - (product == LINE6_DEVID_TONEPORT_GX); + (type == LINE6_GUITARPORT) || + (type == LINE6_TONEPORT_GX); /* add your device here if you are missing support for the LEDs */ } @@ -310,7 +310,6 @@ static void toneport_setup(struct usb_line6_toneport *toneport) int ticks; struct usb_line6 *line6 = &toneport->line6; struct usb_device *usbdev = line6->usbdev; - u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct); /* sync time on device with host: */ ticks = (int)get_seconds(); @@ -320,17 +319,19 @@ static void toneport_setup(struct usb_line6_toneport *toneport) toneport_send_cmd(usbdev, 0x0301, 0x0000); /* initialize source select: */ - switch (le16_to_cpu(usbdev->descriptor.idProduct)) { - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: + switch (line6->type) { + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: toneport_send_cmd(usbdev, toneport_source_info[toneport->source].code, 0x0000); + default: + break; } - if (toneport_has_led(idProduct)) + if (toneport_has_led(line6->type)) toneport_update_led(&usbdev->dev); } @@ -342,8 +343,6 @@ static int toneport_try_init(struct usb_interface *interface, { int err; struct usb_line6 *line6 = &toneport->line6; - struct usb_device *usbdev = line6->usbdev; - u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct); if ((interface == NULL) || (toneport == NULL)) return -ENODEV; @@ -366,17 +365,20 @@ static int toneport_try_init(struct usb_interface *interface, return err; /* register source select control: */ - switch (le16_to_cpu(usbdev->descriptor.idProduct)) { - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: + switch (line6->type) { + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: err = snd_ctl_add(line6->card, snd_ctl_new1(&toneport_control_source, line6->line6pcm)); if (err < 0) return err; + + default: + break; } /* register audio system: */ @@ -387,7 +389,7 @@ static int toneport_try_init(struct usb_interface *interface, line6_read_serial_number(line6, &toneport->serial_number); line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); - if (toneport_has_led(idProduct)) { + if (toneport_has_led(line6->type)) { CHECK_RETURN(device_create_file (&interface->dev, &dev_attr_led_red)); CHECK_RETURN(device_create_file @@ -434,7 +436,6 @@ void line6_toneport_disconnect(struct usb_interface *interface) { struct usb_line6_toneport *toneport; struct snd_line6_pcm *line6pcm; - u16 idProduct; if (interface == NULL) return; @@ -444,9 +445,8 @@ void line6_toneport_disconnect(struct usb_interface *interface) return; del_timer_sync(&toneport->timer); - idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); - if (toneport_has_led(idProduct)) { + if (toneport_has_led(toneport->line6.type)) { device_remove_file(&interface->dev, &dev_attr_led_red); device_remove_file(&interface->dev, &dev_attr_led_green); } -- cgit v0.10.2 From f45be7dcc9e50b254eab2bd6373dda0b382e5ca1 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:43 -0800 Subject: staging: line6: Remove idVendor and idProduct macros These are now only used to build the device table. Each entry in this table is already clearly documented as to what device it maps to so the macros become unnecessary indirection. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 81d5a27..6dc8a0d 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -30,46 +30,28 @@ #define DRIVER_DESC "Line6 USB Driver" #define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION -#define LINE6_DEVICE(prod) USB_DEVICE(LINE6_VENDOR_ID, prod) +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) /* table of devices that work with this driver */ static const struct usb_device_id line6_id_table[] = { - { LINE6_DEVICE(LINE6_DEVID_BASSPODXT), - .driver_info = LINE6_BASSPODXT }, - { LINE6_DEVICE(LINE6_DEVID_BASSPODXTLIVE), - .driver_info = LINE6_BASSPODXTLIVE }, - { LINE6_DEVICE(LINE6_DEVID_BASSPODXTPRO), - .driver_info = LINE6_BASSPODXTPRO }, - { LINE6_DEVICE(LINE6_DEVID_GUITARPORT), - .driver_info = LINE6_GUITARPORT }, - { LINE6_DEVICE(LINE6_DEVID_POCKETPOD), - .driver_info = LINE6_POCKETPOD }, - { LINE6_DEVICE(LINE6_DEVID_PODHD300), - .driver_info = LINE6_PODHD300 }, - { LINE6_DEVICE(LINE6_DEVID_PODHD400), - .driver_info = LINE6_PODHD400 }, - { LINE6_DEVICE(LINE6_DEVID_PODHD500), - .driver_info = LINE6_PODHD500 }, - { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_GX), - .driver_info = LINE6_PODSTUDIO_GX }, - { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX1), - .driver_info = LINE6_PODSTUDIO_UX1 }, - { LINE6_DEVICE(LINE6_DEVID_PODSTUDIO_UX2), - .driver_info = LINE6_PODSTUDIO_UX2 }, - { LINE6_DEVICE(LINE6_DEVID_PODXT), - .driver_info = LINE6_PODXT }, - { LINE6_DEVICE(LINE6_DEVID_PODXTLIVE), - .driver_info = LINE6_PODXTLIVE }, - { LINE6_DEVICE(LINE6_DEVID_PODXTPRO), - .driver_info = LINE6_PODXTPRO }, - { LINE6_DEVICE(LINE6_DEVID_TONEPORT_GX), - .driver_info = LINE6_TONEPORT_GX }, - { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX1), - .driver_info = LINE6_TONEPORT_UX1 }, - { LINE6_DEVICE(LINE6_DEVID_TONEPORT_UX2), - .driver_info = LINE6_TONEPORT_UX2 }, - { LINE6_DEVICE(LINE6_DEVID_VARIAX), - .driver_info = LINE6_VARIAX }, + { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, + { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, + { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, + { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, + { LINE6_DEVICE(0x5051), .driver_info = LINE6_POCKETPOD }, + { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, + { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, + { LINE6_DEVICE(0x414D), .driver_info = LINE6_PODHD500 }, + { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, + { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, + { LINE6_DEVICE(0x4151), .driver_info = LINE6_PODSTUDIO_UX2 }, + { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, + { LINE6_DEVICE(0x4650), .driver_info = LINE6_PODXTLIVE }, + { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, + { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, + { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, + { LINE6_DEVICE(0x4142), .driver_info = LINE6_TONEPORT_UX2 }, + { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, {} }; diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index 06bf909..c897dba 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -12,32 +12,8 @@ #ifndef USBDEFS_H #define USBDEFS_H -#define LINE6_VENDOR_ID 0x0e41 - #define USB_INTERVALS_PER_SECOND 1000 -/* - Device ids. -*/ -#define LINE6_DEVID_BASSPODXT 0x4250 -#define LINE6_DEVID_BASSPODXTLIVE 0x4642 -#define LINE6_DEVID_BASSPODXTPRO 0x4252 -#define LINE6_DEVID_GUITARPORT 0x4750 -#define LINE6_DEVID_POCKETPOD 0x5051 -#define LINE6_DEVID_PODHD300 0x5057 -#define LINE6_DEVID_PODHD400 0x5058 -#define LINE6_DEVID_PODHD500 0x414D -#define LINE6_DEVID_PODSTUDIO_GX 0x4153 -#define LINE6_DEVID_PODSTUDIO_UX1 0x4150 -#define LINE6_DEVID_PODSTUDIO_UX2 0x4151 -#define LINE6_DEVID_PODXT 0x5044 -#define LINE6_DEVID_PODXTLIVE 0x4650 -#define LINE6_DEVID_PODXTPRO 0x5050 -#define LINE6_DEVID_TONEPORT_GX 0x4147 -#define LINE6_DEVID_TONEPORT_UX1 0x4141 -#define LINE6_DEVID_TONEPORT_UX2 0x4142 -#define LINE6_DEVID_VARIAX 0x534d - /* device supports settings parameter via USB */ #define LINE6_BIT_CONTROL (1 << 0) /* device supports PCM input/output via USB */ -- cgit v0.10.2 From 5a8584742586373cd749335b4f7bcb983f39d34e Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:44 -0800 Subject: staging: line6: Remove useless comments Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 6dc8a0d..acde205 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -61,7 +61,6 @@ MODULE_DEVICE_TABLE(usb, line6_id_table); {.id = dev_id,\ .name = dev_name, .capabilities = LINE6_BIT_##dev_cap} -/* *INDENT-OFF* */ static const struct line6_properties line6_properties_table[] = { L6PROP("BassPODxt", "BassPODxt", CTRL_PCM_HW), L6PROP("BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW), @@ -82,7 +81,6 @@ static const struct line6_properties line6_properties_table[] = { L6PROP("TonePortUX2", "TonePort UX2", PCM), L6PROP("Variax", "Variax Workbench", CONTROL), }; -/* *INDENT-ON* */ /* This is Line6's MIDI manufacturer ID. -- cgit v0.10.2 From 4cb1a4ae4afb36234bb0521b282d4861e12ff80b Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:45 -0800 Subject: staging: line6: Rename capability macros Including "BIT" in the macro name is pointless. Replace with "CAP" to provide some context for what its value represents. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index acde205..4ec87a3 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -59,7 +59,7 @@ MODULE_DEVICE_TABLE(usb, line6_id_table); #define L6PROP(dev_id, dev_name, dev_cap)\ {.id = dev_id,\ - .name = dev_name, .capabilities = LINE6_BIT_##dev_cap} + .name = dev_name, .capabilities = LINE6_CAP_##dev_cap} static const struct line6_properties line6_properties_table[] = { L6PROP("BassPODxt", "BassPODxt", CTRL_PCM_HW), @@ -830,7 +830,7 @@ static int line6_probe(struct usb_interface *interface, usb_set_intfdata(interface, line6); - if (properties->capabilities & LINE6_BIT_CONTROL) { + if (properties->capabilities & LINE6_CAP_CONTROL) { /* initialize USB buffers: */ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); @@ -1052,7 +1052,7 @@ static int line6_suspend(struct usb_interface *interface, pm_message_t message) snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); - if (line6->properties->capabilities & LINE6_BIT_CONTROL) + if (line6->properties->capabilities & LINE6_CAP_CONTROL) line6_stop_listen(line6); if (line6pcm != NULL) { @@ -1071,7 +1071,7 @@ static int line6_resume(struct usb_interface *interface) { struct usb_line6 *line6 = usb_get_intfdata(interface); - if (line6->properties->capabilities & LINE6_BIT_CONTROL) + if (line6->properties->capabilities & LINE6_CAP_CONTROL) line6_start_listen(line6); snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index 1ac343b..c453485 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -279,7 +279,7 @@ int line6_init_midi(struct usb_line6 *line6) int err; struct snd_line6_midi *line6midi; - if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) { + if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { /* skip MIDI initialization and report success */ return 0; } diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 86c7bcb..e09772f 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -424,7 +424,7 @@ int line6_init_pcm(struct usb_line6 *line6, int ep_read = 0, ep_write = 0; struct snd_line6_pcm *line6pcm; - if (!(line6->properties->capabilities & LINE6_BIT_PCM)) + if (!(line6->properties->capabilities & LINE6_CAP_PCM)) return 0; /* skip PCM initialization and report success */ /* initialize PCM subsystem based on device: */ diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c index 2ca8900..54b7f60 100644 --- a/drivers/staging/line6/playback.c +++ b/drivers/staging/line6/playback.c @@ -261,7 +261,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) #endif if (! (line6pcm->line6-> - properties->capabilities & LINE6_BIT_HWMON) + properties->capabilities & LINE6_CAP_HWMON) && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)) add_monitor_signal(urb_out, line6pcm->prev_fbuf, diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index 7b4ec92..0fb1788 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -396,7 +396,7 @@ static int pod_try_init(struct usb_interface *interface, handler. */ - if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) { + if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { pod->monitor_level = POD_SYSTEM_INVALID; /* initiate startup procedure: */ diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index c897dba..d6e46ee 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -15,15 +15,15 @@ #define USB_INTERVALS_PER_SECOND 1000 /* device supports settings parameter via USB */ -#define LINE6_BIT_CONTROL (1 << 0) +#define LINE6_CAP_CONTROL (1 << 0) /* device supports PCM input/output via USB */ -#define LINE6_BIT_PCM (1 << 1) +#define LINE6_CAP_PCM (1 << 1) /* device support hardware monitoring */ -#define LINE6_BIT_HWMON (1 << 2) +#define LINE6_CAP_HWMON (1 << 2) -#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \ - LINE6_BIT_PCM | \ - LINE6_BIT_HWMON) +#define LINE6_CAP_CTRL_PCM_HW (LINE6_CAP_CONTROL | \ + LINE6_CAP_PCM | \ + LINE6_CAP_HWMON) #define LINE6_FALLBACK_INTERVAL 10 #define LINE6_FALLBACK_MAXPACKETSIZE 16 -- cgit v0.10.2 From 4d947546c3fb6bc426a7527cf6f8ddb8368fbbc7 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:46 -0800 Subject: staging: line6: Use explicit indexes when defining properties Specify the index of the properties entry explicitly to define this structure more robustly. Also, drop the `L6PROP' macro in favor of initializing each member explicitly on its own line since horizontal space is limited and more attributes will be added later. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 4ec87a3..c988b78 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -57,29 +57,97 @@ static const struct usb_device_id line6_id_table[] = { MODULE_DEVICE_TABLE(usb, line6_id_table); -#define L6PROP(dev_id, dev_name, dev_cap)\ - {.id = dev_id,\ - .name = dev_name, .capabilities = LINE6_CAP_##dev_cap} - static const struct line6_properties line6_properties_table[] = { - L6PROP("BassPODxt", "BassPODxt", CTRL_PCM_HW), - L6PROP("BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW), - L6PROP("BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW), - L6PROP("GuitarPort", "GuitarPort", PCM), - L6PROP("PocketPOD", "Pocket POD", CONTROL), - L6PROP("PODHD300", "POD HD300", CTRL_PCM_HW), - L6PROP("PODHD400", "POD HD400", CTRL_PCM_HW), - L6PROP("PODHD500", "POD HD500", CTRL_PCM_HW), - L6PROP("PODStudioGX", "POD Studio GX", PCM), - L6PROP("PODStudioUX1", "POD Studio UX1", PCM), - L6PROP("PODStudioUX2", "POD Studio UX2", PCM), - L6PROP("PODxt", "PODxt", CTRL_PCM_HW), - L6PROP("PODxtLive", "PODxt Live", CTRL_PCM_HW), - L6PROP("PODxtPro", "PODxt Pro", CTRL_PCM_HW), - L6PROP("TonePortGX", "TonePort GX", PCM), - L6PROP("TonePortUX1", "TonePort UX1", PCM), - L6PROP("TonePortUX2", "TonePort UX2", PCM), - L6PROP("Variax", "Variax Workbench", CONTROL), + [LINE6_BASSPODXT] = { + .id = "BassPODxt", + .name = "BassPODxt", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_BASSPODXTLIVE] = { + .id = "BassPODxtLive", + .name = "BassPODxt Live", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_BASSPODXTPRO] = { + .id = "BassPODxtPro", + .name = "BassPODxt Pro", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_GUITARPORT] = { + .id = "GuitarPort", + .name = "GuitarPort", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_POCKETPOD] = { + .id = "PocketPOD", + .name = "Pocket POD", + .capabilities = LINE6_CAP_CONTROL, + }, + [LINE6_PODHD300] = { + .id = "PODHD300", + .name = "POD HD300", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_PODHD400] = { + .id = "PODHD400", + .name = "POD HD400", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_PODHD500] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_PODSTUDIO_GX] = { + .id = "PODStudioGX", + .name = "POD Studio GX", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_PODSTUDIO_UX1] = { + .id = "PODStudioUX1", + .name = "POD Studio UX1", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_PODSTUDIO_UX2] = { + .id = "PODStudioUX2", + .name = "POD Studio UX2", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_PODXT] = { + .id = "PODxt", + .name = "PODxt", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_PODXTLIVE] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_PODXTPRO] = { + .id = "PODxtPro", + .name = "PODxt Pro", + .capabilities = LINE6_CAP_CTRL_PCM_HW, + }, + [LINE6_TONEPORT_GX] = { + .id = "TonePortGX", + .name = "TonePort GX", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_TONEPORT_UX1] = { + .id = "TonePortUX1", + .name = "TonePort UX1", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_TONEPORT_UX2] = { + .id = "TonePortUX2", + .name = "TonePort UX2", + .capabilities = LINE6_CAP_PCM, + }, + [LINE6_VARIAX] = { + .id = "Variax", + .name = "Variax Workbench", + .capabilities = LINE6_CAP_CONTROL, + } }; /* -- cgit v0.10.2 From 7b3e4d47ca372c4e54f0a1f2e7cffca0b9f9c070 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:47 -0800 Subject: staging: line6: List out capabilities individually The `LINE6_CAP_CTRL_PCM_HW' macro combines three capabilities to save horizontal space when defining the properties entries. Now that these are no longer limited to single lines this is not such a concern. Specify capabilities individually when defining each property for better clarity. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index c988b78..6fecc1b 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -61,92 +61,110 @@ static const struct line6_properties line6_properties_table[] = { [LINE6_BASSPODXT] = { .id = "BassPODxt", .name = "BassPODxt", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_BASSPODXTLIVE] = { .id = "BassPODxtLive", .name = "BassPODxt Live", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_BASSPODXTPRO] = { .id = "BassPODxtPro", .name = "BassPODxt Pro", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_GUITARPORT] = { .id = "GuitarPort", .name = "GuitarPort", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_POCKETPOD] = { .id = "PocketPOD", .name = "Pocket POD", - .capabilities = LINE6_CAP_CONTROL, + .capabilities = LINE6_CAP_CONTROL, }, [LINE6_PODHD300] = { .id = "PODHD300", .name = "POD HD300", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_PODHD400] = { .id = "PODHD400", .name = "POD HD400", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_PODHD500] = { .id = "PODHD500", .name = "POD HD500", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_PODSTUDIO_GX] = { .id = "PODStudioGX", .name = "POD Studio GX", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_PODSTUDIO_UX1] = { .id = "PODStudioUX1", .name = "POD Studio UX1", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_PODSTUDIO_UX2] = { .id = "PODStudioUX2", .name = "POD Studio UX2", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_PODXT] = { .id = "PODxt", .name = "PODxt", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_PODXTLIVE] = { .id = "PODxtLive", .name = "PODxt Live", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_PODXTPRO] = { .id = "PODxtPro", .name = "PODxt Pro", - .capabilities = LINE6_CAP_CTRL_PCM_HW, + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, }, [LINE6_TONEPORT_GX] = { .id = "TonePortGX", .name = "TonePort GX", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_TONEPORT_UX1] = { .id = "TonePortUX1", .name = "TonePort UX1", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_TONEPORT_UX2] = { .id = "TonePortUX2", .name = "TonePort UX2", - .capabilities = LINE6_CAP_PCM, + .capabilities = LINE6_CAP_PCM, }, [LINE6_VARIAX] = { .id = "Variax", .name = "Variax Workbench", - .capabilities = LINE6_CAP_CONTROL, + .capabilities = LINE6_CAP_CONTROL, } }; diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index d6e46ee..f4d080e 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -21,10 +21,6 @@ /* device support hardware monitoring */ #define LINE6_CAP_HWMON (1 << 2) -#define LINE6_CAP_CTRL_PCM_HW (LINE6_CAP_CONTROL | \ - LINE6_CAP_PCM | \ - LINE6_CAP_HWMON) - #define LINE6_FALLBACK_INTERVAL 10 #define LINE6_FALLBACK_MAXPACKETSIZE 16 -- cgit v0.10.2 From 7ad07310d57dec80d32572479f58decb6a8529e0 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:48 -0800 Subject: staging: line6: Split out PODxt Live interfaces The PODxt Live device has both a POD and a Variax interface. Add device type entries for each of these. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 6fecc1b..cb96029 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -31,6 +31,7 @@ #define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) /* table of devices that work with this driver */ static const struct usb_device_id line6_id_table[] = { @@ -46,7 +47,8 @@ static const struct usb_device_id line6_id_table[] = { { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, { LINE6_DEVICE(0x4151), .driver_info = LINE6_PODSTUDIO_UX2 }, { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, - { LINE6_DEVICE(0x4650), .driver_info = LINE6_PODXTLIVE }, + { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, + { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, @@ -132,7 +134,14 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, }, - [LINE6_PODXTLIVE] = { + [LINE6_PODXTLIVE_POD] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + }, + [LINE6_PODXTLIVE_VARIAX] = { .id = "PODxtLive", .name = "PODxt Live", .capabilities = LINE6_CAP_CONTROL @@ -445,24 +454,15 @@ static void line6_data_received(struct urb *urb) case LINE6_PODHD500: break; /* let userspace handle MIDI */ - case LINE6_PODXTLIVE: - switch (line6->interface_number) { - case PODXTLIVE_INTERFACE_POD: - line6_pod_process_message((struct usb_line6_pod + case LINE6_PODXTLIVE_POD: + line6_pod_process_message((struct usb_line6_pod *)line6); - break; - - case PODXTLIVE_INTERFACE_VARIAX: - line6_variax_process_message((struct - usb_line6_variax - *)line6); - break; - - default: - dev_err(line6->ifcdev, - "PODxt Live interface %d not supported\n", - line6->interface_number); - } + break; + + case LINE6_PODXTLIVE_VARIAX: + line6_variax_process_message((struct + usb_line6_variax + *)line6); break; case LINE6_VARIAX: @@ -722,7 +722,8 @@ static int line6_probe(struct usb_interface *interface, switch (devtype) { case LINE6_BASSPODXTLIVE: - case LINE6_PODXTLIVE: + case LINE6_PODXTLIVE_POD: + case LINE6_PODXTLIVE_VARIAX: case LINE6_VARIAX: alternate = 1; break; @@ -841,24 +842,16 @@ static int line6_probe(struct usb_interface *interface, /* these don't have a control channel */ break; - case LINE6_PODXTLIVE: - switch (interface_number) { - case PODXTLIVE_INTERFACE_POD: - size = sizeof(struct usb_line6_pod); - ep_read = 0x84; - ep_write = 0x03; - break; - - case PODXTLIVE_INTERFACE_VARIAX: - size = sizeof(struct usb_line6_variax); - ep_read = 0x86; - ep_write = 0x05; - break; + case LINE6_PODXTLIVE_POD: + size = sizeof(struct usb_line6_pod); + ep_read = 0x84; + ep_write = 0x03; + break; - default: - ret = -ENODEV; - goto err_put; - } + case LINE6_PODXTLIVE_VARIAX: + size = sizeof(struct usb_line6_variax); + ep_read = 0x86; + ep_write = 0x05; break; case LINE6_VARIAX: @@ -887,7 +880,6 @@ static int line6_probe(struct usb_interface *interface, } /* store basic data: */ - line6->interface_number = interface_number; line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; @@ -967,27 +959,16 @@ static int line6_probe(struct usb_interface *interface, (struct usb_line6_podhd *)line6); break; - case LINE6_PODXTLIVE: - switch (interface_number) { - case PODXTLIVE_INTERFACE_POD: - ret = - line6_pod_init(interface, - (struct usb_line6_pod *)line6); - break; - - case PODXTLIVE_INTERFACE_VARIAX: - ret = - line6_variax_init(interface, - (struct usb_line6_variax *)line6); - break; - - default: - dev_err(&interface->dev, - "PODxt Live interface %d not supported\n", - interface_number); - ret = -ENODEV; - } + case LINE6_PODXTLIVE_POD: + ret = + line6_pod_init(interface, + (struct usb_line6_pod *)line6); + break; + case LINE6_PODXTLIVE_VARIAX: + ret = + line6_variax_init(interface, + (struct usb_line6_variax *)line6); break; case LINE6_VARIAX: @@ -1084,17 +1065,12 @@ static void line6_disconnect(struct usb_interface *interface) line6_podhd_disconnect(interface); break; - case LINE6_PODXTLIVE: - switch (interface_number) { - case PODXTLIVE_INTERFACE_POD: - line6_pod_disconnect(interface); - break; - - case PODXTLIVE_INTERFACE_VARIAX: - line6_variax_disconnect(interface); - break; - } + case LINE6_PODXTLIVE_POD: + line6_pod_disconnect(interface); + break; + case LINE6_PODXTLIVE_VARIAX: + line6_variax_disconnect(interface); break; case LINE6_VARIAX: diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index c536795..085aa44 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -33,7 +33,8 @@ enum line6_device_type { LINE6_PODSTUDIO_UX1, LINE6_PODSTUDIO_UX2, LINE6_PODXT, - LINE6_PODXTLIVE, + LINE6_PODXTLIVE_POD, + LINE6_PODXTLIVE_VARIAX, LINE6_PODXTPRO, LINE6_TONEPORT_GX, LINE6_TONEPORT_UX1, @@ -136,11 +137,6 @@ struct usb_line6 { const struct line6_properties *properties; /** - Interface number. - */ - int interface_number; - - /** Interval (ms). */ int interval; diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index e09772f..d09d1ea 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -433,7 +433,8 @@ int line6_init_pcm(struct usb_line6 *line6, case LINE6_BASSPODXTLIVE: case LINE6_BASSPODXTPRO: case LINE6_PODXT: - case LINE6_PODXTLIVE: + case LINE6_PODXTLIVE_POD: + case LINE6_PODXTLIVE_VARIAX: case LINE6_PODXTPRO: case LINE6_PODHD300: case LINE6_PODHD400: diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h index 397d94c..91fd4c5 100644 --- a/drivers/staging/line6/pod.h +++ b/drivers/staging/line6/pod.h @@ -21,12 +21,6 @@ #include "driver.h" /* - PODxt Live interfaces -*/ -#define PODXTLIVE_INTERFACE_POD 0 -#define PODXTLIVE_INTERFACE_VARIAX 1 - -/* Locate name in binary program dump */ #define POD_NAME_OFFSET 0 -- cgit v0.10.2 From 951dd316119ca5fb7eedcb1950d9e19154e7c332 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:49 -0800 Subject: staging: line6: Split out POD HD500 interfaces The driver uses a different altsetting depending on the interface. Add device type entries for each of these. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index cb96029..e97e2cb 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -42,7 +42,8 @@ static const struct usb_device_id line6_id_table[] = { { LINE6_DEVICE(0x5051), .driver_info = LINE6_POCKETPOD }, { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, - { LINE6_DEVICE(0x414D), .driver_info = LINE6_PODHD500 }, + { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, + { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, { LINE6_DEVICE(0x4151), .driver_info = LINE6_PODSTUDIO_UX2 }, @@ -105,7 +106,14 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, }, - [LINE6_PODHD500] = { + [LINE6_PODHD500_0] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + }, + [LINE6_PODHD500_1] = { .id = "PODHD500", .name = "POD HD500", .capabilities = LINE6_CAP_CONTROL @@ -451,7 +459,8 @@ static void line6_data_received(struct urb *urb) case LINE6_PODHD300: case LINE6_PODHD400: - case LINE6_PODHD500: + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: break; /* let userspace handle MIDI */ case LINE6_PODXTLIVE_POD: @@ -740,17 +749,12 @@ static int line6_probe(struct usb_interface *interface, } break; - case LINE6_PODHD500: - switch (interface_number) { - case 0: - alternate = 1; - break; - case 1: - alternate = 0; - break; - default: - MISSING_CASE; - } + case LINE6_PODHD500_0: + alternate = 1; + break; + + case LINE6_PODHD500_1: + alternate = 0; break; case LINE6_BASSPODXT: @@ -819,7 +823,8 @@ static int line6_probe(struct usb_interface *interface, ep_write = 0x03; break; - case LINE6_PODHD500: + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: size = sizeof(struct usb_line6_podhd); ep_read = 0x81; ep_write = 0x01; @@ -954,7 +959,8 @@ static int line6_probe(struct usb_interface *interface, case LINE6_PODHD300: case LINE6_PODHD400: - case LINE6_PODHD500: + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: ret = line6_podhd_init(interface, (struct usb_line6_podhd *)line6); break; @@ -1061,7 +1067,8 @@ static void line6_disconnect(struct usb_interface *interface) case LINE6_PODHD300: case LINE6_PODHD400: - case LINE6_PODHD500: + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: line6_podhd_disconnect(interface); break; diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 085aa44..9d6b351 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -28,7 +28,8 @@ enum line6_device_type { LINE6_POCKETPOD, LINE6_PODHD300, LINE6_PODHD400, - LINE6_PODHD500, + LINE6_PODHD500_0, + LINE6_PODHD500_1, LINE6_PODSTUDIO_GX, LINE6_PODSTUDIO_UX1, LINE6_PODSTUDIO_UX2, diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index d09d1ea..d8450af 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -442,7 +442,8 @@ int line6_init_pcm(struct usb_line6 *line6, ep_write = 0x01; break; - case LINE6_PODHD500: + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: ep_read = 0x86; ep_write = 0x02; break; -- cgit v0.10.2 From 3a3eae6c18e3b90311e6372a0df1371d193db2a1 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:50 -0800 Subject: staging: line6: Filter on Pocket POD interface The driver only supports interface 1 of the Pocket POD. Use the device table to filter on this. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index e97e2cb..8b03bc0 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -39,7 +39,7 @@ static const struct usb_device_id line6_id_table[] = { { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, - { LINE6_DEVICE(0x5051), .driver_info = LINE6_POCKETPOD }, + { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, @@ -738,15 +738,7 @@ static int line6_probe(struct usb_interface *interface, break; case LINE6_POCKETPOD: - switch (interface_number) { - case 0: - return -ENODEV; /* this interface has no endpoints */ - case 1: - alternate = 0; - break; - default: - MISSING_CASE; - } + alternate = 0; break; case LINE6_PODHD500_0: -- cgit v0.10.2 From b98a8115f7cb5c8342606eb9a3cb1d808d01efb7 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:51 -0800 Subject: staging: line6: Filter on UX2 interfaces The driver only supports interface 0 of the TonePort UX2 and POD Studio UX2 devices. Use the device table to filter on this. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 8b03bc0..f04ff80 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -46,14 +46,14 @@ static const struct usb_device_id line6_id_table[] = { { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, - { LINE6_DEVICE(0x4151), .driver_info = LINE6_PODSTUDIO_UX2 }, + { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, - { LINE6_DEVICE(0x4142), .driver_info = LINE6_TONEPORT_UX2 }, + { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, {} }; @@ -768,20 +768,8 @@ static int line6_probe(struct usb_interface *interface, case LINE6_TONEPORT_UX2: case LINE6_PODSTUDIO_UX2: - switch (interface_number) { - case 0: - /* defaults to 44.1kHz, 16-bit */ - alternate = 2; - break; - case 1: - /* don't know yet what this is ... - alternate = 1; - break; - */ - return -ENODEV; - default: - MISSING_CASE; - } + /* defaults to 44.1kHz, 16-bit */ + alternate = 2; break; default: -- cgit v0.10.2 From 7b9584fa1c0be583a8981763dba7ef9f4d1fe67b Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:52 -0800 Subject: staging: line6: Move altsetting to properties The device type can now be used to determine the altsetting for the interface. Drop the conditional logic and make this value a property. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index f04ff80..0150470 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -67,6 +67,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 5, }, [LINE6_BASSPODXTLIVE] = { .id = "BassPODxtLive", @@ -74,6 +75,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, }, [LINE6_BASSPODXTPRO] = { .id = "BassPODxtPro", @@ -81,16 +83,19 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 5, }, [LINE6_GUITARPORT] = { .id = "GuitarPort", .name = "GuitarPort", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ }, [LINE6_POCKETPOD] = { .id = "PocketPOD", .name = "Pocket POD", .capabilities = LINE6_CAP_CONTROL, + .altsetting = 0, }, [LINE6_PODHD300] = { .id = "PODHD300", @@ -98,6 +103,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 5, }, [LINE6_PODHD400] = { .id = "PODHD400", @@ -105,6 +111,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 5, }, [LINE6_PODHD500_0] = { .id = "PODHD500", @@ -112,6 +119,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, }, [LINE6_PODHD500_1] = { .id = "PODHD500", @@ -119,21 +127,25 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, }, [LINE6_PODSTUDIO_GX] = { .id = "PODStudioGX", .name = "POD Studio GX", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ }, [LINE6_PODSTUDIO_UX1] = { .id = "PODStudioUX1", .name = "POD Studio UX1", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ }, [LINE6_PODSTUDIO_UX2] = { .id = "PODStudioUX2", .name = "POD Studio UX2", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ }, [LINE6_PODXT] = { .id = "PODxt", @@ -141,6 +153,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 5, }, [LINE6_PODXTLIVE_POD] = { .id = "PODxtLive", @@ -148,6 +161,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, }, [LINE6_PODXTLIVE_VARIAX] = { .id = "PODxtLive", @@ -155,6 +169,7 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, }, [LINE6_PODXTPRO] = { .id = "PODxtPro", @@ -162,26 +177,31 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 5, }, [LINE6_TONEPORT_GX] = { .id = "TonePortGX", .name = "TonePort GX", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ }, [LINE6_TONEPORT_UX1] = { .id = "TonePortUX1", .name = "TonePort UX1", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ }, [LINE6_TONEPORT_UX2] = { .id = "TonePortUX2", .name = "TonePort UX2", .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ }, [LINE6_VARIAX] = { .id = "Variax", .name = "Variax Workbench", .capabilities = LINE6_CAP_CONTROL, + .altsetting = 1, } }; @@ -703,7 +723,7 @@ static int line6_probe(struct usb_interface *interface, struct usb_device *usbdev; struct usb_line6 *line6; const struct line6_properties *properties; - int interface_number, alternate = 0; + int interface_number; int size = 0; int ep_read = 0, ep_write = 0; int ret; @@ -729,56 +749,8 @@ static int line6_probe(struct usb_interface *interface, /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - switch (devtype) { - case LINE6_BASSPODXTLIVE: - case LINE6_PODXTLIVE_POD: - case LINE6_PODXTLIVE_VARIAX: - case LINE6_VARIAX: - alternate = 1; - break; - - case LINE6_POCKETPOD: - alternate = 0; - break; - - case LINE6_PODHD500_0: - alternate = 1; - break; - - case LINE6_PODHD500_1: - alternate = 0; - break; - - case LINE6_BASSPODXT: - case LINE6_BASSPODXTPRO: - case LINE6_PODXT: - case LINE6_PODXTPRO: - case LINE6_PODHD300: - case LINE6_PODHD400: - alternate = 5; - break; - - case LINE6_GUITARPORT: - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - alternate = 2; /* 1..4 seem to be ok */ - break; - - case LINE6_TONEPORT_UX2: - case LINE6_PODSTUDIO_UX2: - /* defaults to 44.1kHz, 16-bit */ - alternate = 2; - break; - - default: - MISSING_CASE; - ret = -ENODEV; - goto err_put; - } - - ret = usb_set_interface(usbdev, interface_number, alternate); + ret = usb_set_interface(usbdev, interface_number, + properties->altsetting); if (ret < 0) { dev_err(&interface->dev, "set_interface failed\n"); goto err_put; diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 9d6b351..97d6be1 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -115,6 +115,8 @@ struct line6_properties { line6usb driver. */ int capabilities; + + int altsetting; }; /** -- cgit v0.10.2 From 9e165be72f49b2de0cb859304a1eb7e6e26da1e1 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:53 -0800 Subject: staging: line6: Move control endpoints to properties The device type can now be used to determine the addresses of the control endpoints for the interface. Drop the conditional logic and make these values properties. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 0150470..40ec57c 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -68,6 +68,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_BASSPODXTLIVE] = { .id = "BassPODxtLive", @@ -76,6 +78,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_BASSPODXTPRO] = { .id = "BassPODxtPro", @@ -84,18 +88,23 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_GUITARPORT] = { .id = "GuitarPort", .name = "GuitarPort", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ }, [LINE6_POCKETPOD] = { .id = "PocketPOD", .name = "Pocket POD", .capabilities = LINE6_CAP_CONTROL, .altsetting = 0, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x02, }, [LINE6_PODHD300] = { .id = "PODHD300", @@ -104,6 +113,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_PODHD400] = { .id = "PODHD400", @@ -112,6 +123,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_PODHD500_0] = { .id = "PODHD500", @@ -120,6 +133,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, }, [LINE6_PODHD500_1] = { .id = "PODHD500", @@ -128,24 +143,29 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, }, [LINE6_PODSTUDIO_GX] = { .id = "PODStudioGX", .name = "POD Studio GX", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ }, [LINE6_PODSTUDIO_UX1] = { .id = "PODStudioUX1", .name = "POD Studio UX1", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ }, [LINE6_PODSTUDIO_UX2] = { .id = "PODStudioUX2", .name = "POD Studio UX2", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ }, [LINE6_PODXT] = { .id = "PODxt", @@ -154,6 +174,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_PODXTLIVE_POD] = { .id = "PODxtLive", @@ -162,6 +184,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_PODXTLIVE_VARIAX] = { .id = "PODxtLive", @@ -170,6 +194,8 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 1, + .ep_ctrl_r = 0x86, + .ep_ctrl_w = 0x05, }, [LINE6_PODXTPRO] = { .id = "PODxtPro", @@ -178,30 +204,37 @@ static const struct line6_properties line6_properties_table[] = { | LINE6_CAP_PCM | LINE6_CAP_HWMON, .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, }, [LINE6_TONEPORT_GX] = { .id = "TonePortGX", .name = "TonePort GX", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ }, [LINE6_TONEPORT_UX1] = { .id = "TonePortUX1", .name = "TonePort UX1", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ }, [LINE6_TONEPORT_UX2] = { .id = "TonePortUX2", .name = "TonePort UX2", .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ }, [LINE6_VARIAX] = { .id = "Variax", .name = "Variax Workbench", .capabilities = LINE6_CAP_CONTROL, .altsetting = 1, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x01, } }; @@ -245,9 +278,9 @@ static int line6_start_listen(struct usb_line6 *line6) int err; usb_fill_int_urb(line6->urb_listen, line6->usbdev, - usb_rcvintpipe(line6->usbdev, line6->ep_control_read), - line6->buffer_listen, LINE6_BUFSIZE_LISTEN, - line6_data_received, line6, line6->interval); + usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), + line6->buffer_listen, LINE6_BUFSIZE_LISTEN, + line6_data_received, line6, line6->interval); line6->urb_listen->actual_length = 0; err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); return err; @@ -277,7 +310,7 @@ int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, retval = usb_interrupt_msg(line6->usbdev, usb_sndintpipe(line6->usbdev, - line6->ep_control_write), + line6->properties->ep_ctrl_w), (char *)frag_buf, frag_size, &partial, LINE6_TIMEOUT * HZ); @@ -319,9 +352,9 @@ static int line6_send_raw_message_async_part(struct message *msg, int bytes = min(msg->size - done, line6->max_packet_size); usb_fill_int_urb(urb, line6->usbdev, - usb_sndintpipe(line6->usbdev, line6->ep_control_write), - (char *)msg->buffer + done, bytes, - line6_async_request_sent, msg, line6->interval); + usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), + (char *)msg->buffer + done, bytes, + line6_async_request_sent, msg, line6->interval); msg->done += bytes; retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -525,7 +558,7 @@ int line6_send_program(struct usb_line6 *line6, u8 value) retval = usb_interrupt_msg(line6->usbdev, usb_sndintpipe(line6->usbdev, - line6->ep_control_write), + line6->properties->ep_ctrl_w), buffer, 2, &partial, LINE6_TIMEOUT * HZ); if (retval) @@ -555,7 +588,7 @@ int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) retval = usb_interrupt_msg(line6->usbdev, usb_sndintpipe(line6->usbdev, - line6->ep_control_write), + line6->properties->ep_ctrl_w), buffer, 3, &partial, LINE6_TIMEOUT * HZ); if (retval) @@ -725,7 +758,6 @@ static int line6_probe(struct usb_interface *interface, const struct line6_properties *properties; int interface_number; int size = 0; - int ep_read = 0, ep_write = 0; int ret; if (interface == NULL) @@ -764,28 +796,20 @@ static int line6_probe(struct usb_interface *interface, case LINE6_PODXT: case LINE6_PODXTPRO: size = sizeof(struct usb_line6_pod); - ep_read = 0x84; - ep_write = 0x03; break; case LINE6_PODHD300: case LINE6_PODHD400: size = sizeof(struct usb_line6_podhd); - ep_read = 0x84; - ep_write = 0x03; break; case LINE6_PODHD500_0: case LINE6_PODHD500_1: size = sizeof(struct usb_line6_podhd); - ep_read = 0x81; - ep_write = 0x01; break; case LINE6_POCKETPOD: size = sizeof(struct usb_line6_pod); - ep_read = 0x82; - ep_write = 0x02; break; case LINE6_PODSTUDIO_GX: @@ -796,25 +820,18 @@ static int line6_probe(struct usb_interface *interface, case LINE6_TONEPORT_UX2: case LINE6_GUITARPORT: size = sizeof(struct usb_line6_toneport); - /* these don't have a control channel */ break; case LINE6_PODXTLIVE_POD: size = sizeof(struct usb_line6_pod); - ep_read = 0x84; - ep_write = 0x03; break; case LINE6_PODXTLIVE_VARIAX: size = sizeof(struct usb_line6_variax); - ep_read = 0x86; - ep_write = 0x05; break; case LINE6_VARIAX: size = sizeof(struct usb_line6_variax); - ep_read = 0x82; - ep_write = 0x01; break; default: @@ -840,15 +857,13 @@ static int line6_probe(struct usb_interface *interface, line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; - line6->ep_control_read = ep_read; - line6->ep_control_write = ep_write; line6->type = devtype; /* get data from endpoint descriptor (see usb_maxpacket): */ { struct usb_host_endpoint *ep; - unsigned epnum = - usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read)); + unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r); + unsigned epnum = usb_pipeendpoint(pipe); ep = usbdev->ep_in[epnum]; if (ep != NULL) { diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 97d6be1..a0555f4 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -117,6 +117,9 @@ struct line6_properties { int capabilities; int altsetting; + + unsigned ep_ctrl_r; + unsigned ep_ctrl_w; }; /** @@ -171,16 +174,6 @@ struct usb_line6 { struct snd_line6_midi *line6midi; /** - USB endpoint for listening to control commands. - */ - int ep_control_read; - - /** - USB endpoint for writing control commands. - */ - int ep_control_write; - - /** URB for listening to PODxt Pro control endpoint. */ struct urb *urb_listen; diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index c453485..c9d725a 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -136,7 +136,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, usb_fill_int_urb(urb, line6->usbdev, usb_sndbulkpipe(line6->usbdev, - line6->ep_control_write), + line6->properties->ep_ctrl_w), transfer_buffer, length, midi_sent, line6, line6->interval); urb->actual_length = 0; -- cgit v0.10.2 From b95d2e408bf94ad73d022e36937b38335890af8f Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:54 -0800 Subject: staging: line6: Remove stale Pocket POD PCM endpoints Commit 1027f476f507 (staging: line6: sync with upstream) removed PCM from the Pocket POD capabilities but left the endpoint configuration. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index d8450af..19aa927 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -448,11 +448,6 @@ int line6_init_pcm(struct usb_line6 *line6, ep_write = 0x02; break; - case LINE6_POCKETPOD: - ep_read = 0x82; - ep_write = 0x02; - break; - case LINE6_GUITARPORT: case LINE6_PODSTUDIO_GX: case LINE6_PODSTUDIO_UX1: -- cgit v0.10.2 From 16d603d32d3437abd1867c7671ed2763bd3aaf0d Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:55 -0800 Subject: staging: line6: Move audio endpoints to properties The device type can now be used to determine the addresses of the audio endpoints for the interface. Drop the conditional logic and make these values properties. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c index e6ca631..f24c7c5 100644 --- a/drivers/staging/line6/capture.c +++ b/drivers/staging/line6/capture.c @@ -400,6 +400,7 @@ struct snd_pcm_ops snd_line6_capture_ops = { int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) { + struct usb_line6 *line6 = line6pcm->line6; int i; /* create audio URBs and fill in constant values: */ @@ -411,14 +412,14 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); if (urb == NULL) { - dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); + dev_err(line6->ifcdev, "Out of memory\n"); return -ENOMEM; } - urb->dev = line6pcm->line6->usbdev; + urb->dev = line6->usbdev; urb->pipe = - usb_rcvisocpipe(line6pcm->line6->usbdev, - line6pcm->ep_audio_read & + usb_rcvisocpipe(line6->usbdev, + line6->properties->ep_audio_r & USB_ENDPOINT_NUMBER_MASK); urb->transfer_flags = URB_ISO_ASAP; urb->start_frame = -1; diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 40ec57c..4bfef21 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -70,6 +70,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 5, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_BASSPODXTLIVE] = { .id = "BassPODxtLive", @@ -80,6 +82,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_BASSPODXTPRO] = { .id = "BassPODxtPro", @@ -90,6 +94,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 5, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_GUITARPORT] = { .id = "GuitarPort", @@ -97,6 +103,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_POCKETPOD] = { .id = "PocketPOD", @@ -105,6 +113,7 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 0, .ep_ctrl_r = 0x82, .ep_ctrl_w = 0x02, + /* no audio channel */ }, [LINE6_PODHD300] = { .id = "PODHD300", @@ -115,6 +124,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 5, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODHD400] = { .id = "PODHD400", @@ -125,6 +136,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 5, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODHD500_0] = { .id = "PODHD500", @@ -135,6 +148,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x81, .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, }, [LINE6_PODHD500_1] = { .id = "PODHD500", @@ -145,6 +160,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x81, .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, }, [LINE6_PODSTUDIO_GX] = { .id = "PODStudioGX", @@ -152,6 +169,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODSTUDIO_UX1] = { .id = "PODStudioUX1", @@ -159,6 +178,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODSTUDIO_UX2] = { .id = "PODStudioUX2", @@ -166,6 +187,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODXT] = { .id = "PODxt", @@ -176,6 +199,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 5, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODXTLIVE_POD] = { .id = "PODxtLive", @@ -186,6 +211,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODXTLIVE_VARIAX] = { .id = "PODxtLive", @@ -196,6 +223,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x86, .ep_ctrl_w = 0x05, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_PODXTPRO] = { .id = "PODxtPro", @@ -206,6 +235,8 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 5, .ep_ctrl_r = 0x84, .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_TONEPORT_GX] = { .id = "TonePortGX", @@ -213,6 +244,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_TONEPORT_UX1] = { .id = "TonePortUX1", @@ -220,6 +253,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* 1..4 seem to be ok */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_TONEPORT_UX2] = { .id = "TonePortUX2", @@ -227,6 +262,8 @@ static const struct line6_properties line6_properties_table[] = { .capabilities = LINE6_CAP_PCM, .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, }, [LINE6_VARIAX] = { .id = "Variax", @@ -235,6 +272,7 @@ static const struct line6_properties line6_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x82, .ep_ctrl_w = 0x01, + /* no audio channel */ } }; diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index a0555f4..a4bde71 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -120,6 +120,8 @@ struct line6_properties { unsigned ep_ctrl_r; unsigned ep_ctrl_w; + unsigned ep_audio_r; + unsigned ep_audio_w; }; /** diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 19aa927..6d4e5cd 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -421,55 +421,13 @@ int line6_init_pcm(struct usb_line6 *line6, }; int err; - int ep_read = 0, ep_write = 0; + unsigned ep_read = line6->properties->ep_audio_r; + unsigned ep_write = line6->properties->ep_audio_w; struct snd_line6_pcm *line6pcm; if (!(line6->properties->capabilities & LINE6_CAP_PCM)) return 0; /* skip PCM initialization and report success */ - /* initialize PCM subsystem based on device: */ - switch (line6->type) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_PODXT: - case LINE6_PODXTLIVE_POD: - case LINE6_PODXTLIVE_VARIAX: - case LINE6_PODXTPRO: - case LINE6_PODHD300: - case LINE6_PODHD400: - ep_read = 0x82; - ep_write = 0x01; - break; - - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - ep_read = 0x86; - ep_write = 0x02; - break; - - case LINE6_GUITARPORT: - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - ep_read = 0x82; - ep_write = 0x01; - break; - - /* this is for interface_number == 1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_PODSTUDIO_UX2: - ep_read = 0x87; - ep_write = 0x00; - break; */ - - default: - MISSING_CASE; - } - line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); if (line6pcm == NULL) @@ -478,8 +436,6 @@ int line6_init_pcm(struct usb_line6 *line6, line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; line6pcm->volume_monitor = 255; line6pcm->line6 = line6; - line6pcm->ep_audio_read = ep_read; - line6pcm->ep_audio_write = ep_write; /* Read and write buffers are sized identically, so choose minimum */ line6pcm->max_packet_size = min( diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h index 4f60823..7315e81 100644 --- a/drivers/staging/line6/pcm.h +++ b/drivers/staging/line6/pcm.h @@ -297,16 +297,6 @@ struct snd_line6_pcm { int max_packet_size; /** - USB endpoint for listening to audio data. - */ - int ep_audio_read; - - /** - USB endpoint for writing audio data. - */ - int ep_audio_write; - - /** Bit mask of active capture URBs. */ unsigned long active_urb_in; diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c index 54b7f60..da2e3b8 100644 --- a/drivers/staging/line6/playback.c +++ b/drivers/staging/line6/playback.c @@ -560,6 +560,7 @@ struct snd_pcm_ops snd_line6_playback_ops = { int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) { + struct usb_line6 *line6 = line6pcm->line6; int i; /* create audio URBs and fill in constant values: */ @@ -571,14 +572,14 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); if (urb == NULL) { - dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); + dev_err(line6->ifcdev, "Out of memory\n"); return -ENOMEM; } - urb->dev = line6pcm->line6->usbdev; + urb->dev = line6->usbdev; urb->pipe = - usb_sndisocpipe(line6pcm->line6->usbdev, - line6pcm->ep_audio_write & + usb_sndisocpipe(line6->usbdev, + line6->properties->ep_audio_w & USB_ENDPOINT_NUMBER_MASK); urb->transfer_flags = URB_ISO_ASAP; urb->start_frame = -1; -- cgit v0.10.2 From a221dd453a311eb55c1f1ee6322947d99d9b6170 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:56 -0800 Subject: staging: line6: Pass *_init() `usb_line6' pointers Casting the `struct usb_line6' pointer at the call point makes the code difficult to read. This is substantially cleaned up by moving the cast into the callees. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 4bfef21..08f8051 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -959,33 +959,26 @@ static int line6_probe(struct usb_interface *interface, case LINE6_POCKETPOD: case LINE6_PODXT: case LINE6_PODXTPRO: - ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); + ret = line6_pod_init(interface, line6); break; case LINE6_PODHD300: case LINE6_PODHD400: case LINE6_PODHD500_0: case LINE6_PODHD500_1: - ret = line6_podhd_init(interface, - (struct usb_line6_podhd *)line6); + ret = line6_podhd_init(interface, line6); break; case LINE6_PODXTLIVE_POD: - ret = - line6_pod_init(interface, - (struct usb_line6_pod *)line6); + ret = line6_pod_init(interface, line6); break; case LINE6_PODXTLIVE_VARIAX: - ret = - line6_variax_init(interface, - (struct usb_line6_variax *)line6); + ret = line6_variax_init(interface, line6); break; case LINE6_VARIAX: - ret = - line6_variax_init(interface, - (struct usb_line6_variax *)line6); + ret = line6_variax_init(interface, line6); break; case LINE6_PODSTUDIO_GX: @@ -995,9 +988,7 @@ static int line6_probe(struct usb_interface *interface, case LINE6_TONEPORT_UX1: case LINE6_TONEPORT_UX2: case LINE6_GUITARPORT: - ret = - line6_toneport_init(interface, - (struct usb_line6_toneport *)line6); + ret = line6_toneport_init(interface, line6); break; default: diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index 0fb1788..9292b72 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -353,10 +353,10 @@ static int pod_create_files2(struct device *dev) Try to init POD device. */ static int pod_try_init(struct usb_interface *interface, - struct usb_line6_pod *pod) + struct usb_line6 *line6) { int err; - struct usb_line6 *line6 = &pod->line6; + struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; init_timer(&pod->startup_timer); INIT_WORK(&pod->startup_work, pod_startup4); @@ -409,9 +409,9 @@ static int pod_try_init(struct usb_interface *interface, /* Init POD device (and clean up in case of failure). */ -int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod) +int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) { - int err = pod_try_init(interface, pod); + int err = pod_try_init(interface, line6); if (err < 0) pod_destruct(interface); diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h index 91fd4c5..cf6c75cd 100644 --- a/drivers/staging/line6/pod.h +++ b/drivers/staging/line6/pod.h @@ -88,7 +88,7 @@ struct usb_line6_pod { extern void line6_pod_disconnect(struct usb_interface *interface); extern int line6_pod_init(struct usb_interface *interface, - struct usb_line6_pod *pod); + struct usb_line6 *line6); extern void line6_pod_process_message(struct usb_line6_pod *pod); #endif diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c index 7ef4543..3bb942e 100644 --- a/drivers/staging/line6/podhd.c +++ b/drivers/staging/line6/podhd.c @@ -121,9 +121,9 @@ static int podhd_try_init(struct usb_interface *interface, /* Init POD HD device (and clean up in case of failure). */ -int line6_podhd_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd) +int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) { + struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; int err = podhd_try_init(interface, podhd); if (err < 0) diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h index 652f740..b7d9568 100644 --- a/drivers/staging/line6/podhd.h +++ b/drivers/staging/line6/podhd.h @@ -25,6 +25,6 @@ struct usb_line6_podhd { extern void line6_podhd_disconnect(struct usb_interface *interface); extern int line6_podhd_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd); + struct usb_line6 *line6); #endif /* PODHD_H */ diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 9e5cee1..de91910 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -339,10 +339,10 @@ static void toneport_setup(struct usb_line6_toneport *toneport) Try to init Toneport device. */ static int toneport_try_init(struct usb_interface *interface, - struct usb_line6_toneport *toneport) + struct usb_line6 *line6) { int err; - struct usb_line6 *line6 = &toneport->line6; + struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; if ((interface == NULL) || (toneport == NULL)) return -ENODEV; @@ -411,9 +411,9 @@ static int toneport_try_init(struct usb_interface *interface, Init Toneport device (and clean up in case of failure). */ int line6_toneport_init(struct usb_interface *interface, - struct usb_line6_toneport *toneport) + struct usb_line6 *line6) { - int err = toneport_try_init(interface, toneport); + int err = toneport_try_init(interface, line6); if (err < 0) toneport_destruct(interface); diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h index 8576b72..af2b4e0 100644 --- a/drivers/staging/line6/toneport.h +++ b/drivers/staging/line6/toneport.h @@ -46,7 +46,7 @@ struct usb_line6_toneport { extern void line6_toneport_disconnect(struct usb_interface *interface); extern int line6_toneport_init(struct usb_interface *interface, - struct usb_line6_toneport *toneport); + struct usb_line6 *line6); extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); #endif diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index ae2be99..f5b618b 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -174,8 +174,9 @@ static void variax_destruct(struct usb_interface *interface) Try to init workbench device. */ static int variax_try_init(struct usb_interface *interface, - struct usb_line6_variax *variax) + struct usb_line6 *line6) { + struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; int err; init_timer(&variax->startup_timer1); @@ -212,10 +213,9 @@ static int variax_try_init(struct usb_interface *interface, /* Init workbench device (and clean up in case of failure). */ -int line6_variax_init(struct usb_interface *interface, - struct usb_line6_variax *variax) +int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) { - int err = variax_try_init(interface, variax); + int err = variax_try_init(interface, line6); if (err < 0) variax_destruct(interface); diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h index 24de796..9bf1464 100644 --- a/drivers/staging/line6/variax.h +++ b/drivers/staging/line6/variax.h @@ -66,7 +66,7 @@ struct usb_line6_variax { extern void line6_variax_disconnect(struct usb_interface *interface); extern int line6_variax_init(struct usb_interface *interface, - struct usb_line6_variax *variax); + struct usb_line6 *line6); extern void line6_variax_process_message(struct usb_line6_variax *variax); #endif -- cgit v0.10.2 From 1cad3e8dcac92ee07c576e93d1b54c8308e2fa80 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:57 -0800 Subject: staging: line6: Pass *_process_message() `usb_line6' pointers Casting the `struct usb_line6' pointer at the call point makes the code difficult to read. This is substantially cleaned up by moving the cast into the callees. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 08f8051..369e60e 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -544,8 +544,7 @@ static void line6_data_received(struct urb *urb) case LINE6_PODXT: case LINE6_PODXTPRO: case LINE6_POCKETPOD: - line6_pod_process_message((struct usb_line6_pod *) - line6); + line6_pod_process_message(line6); break; case LINE6_PODHD300: @@ -555,19 +554,15 @@ static void line6_data_received(struct urb *urb) break; /* let userspace handle MIDI */ case LINE6_PODXTLIVE_POD: - line6_pod_process_message((struct usb_line6_pod - *)line6); + line6_pod_process_message(line6); break; case LINE6_PODXTLIVE_VARIAX: - line6_variax_process_message((struct - usb_line6_variax - *)line6); + line6_variax_process_message(line6); break; case LINE6_VARIAX: - line6_variax_process_message((struct usb_line6_variax *) - line6); + line6_variax_process_message(line6); break; default: diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index 9292b72..aa8977d 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -131,8 +131,9 @@ static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, /* Process a completely received message. */ -void line6_pod_process_message(struct usb_line6_pod *pod) +void line6_pod_process_message(struct usb_line6 *line6) { + struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; const unsigned char *buf = pod->line6.buffer_message; if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h index cf6c75cd..984a00b 100644 --- a/drivers/staging/line6/pod.h +++ b/drivers/staging/line6/pod.h @@ -89,6 +89,6 @@ struct usb_line6_pod { extern void line6_pod_disconnect(struct usb_interface *interface); extern int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6); -extern void line6_pod_process_message(struct usb_line6_pod *pod); +extern void line6_pod_process_message(struct usb_line6 *line6); #endif diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index f5b618b..4d41994 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -130,8 +130,9 @@ static void variax_startup6(struct work_struct *work) /* Process a completely received message. */ -void line6_variax_process_message(struct usb_line6_variax *variax) +void line6_variax_process_message(struct usb_line6 *line6) { + struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; const unsigned char *buf = variax->line6.buffer_message; switch (buf[0]) { diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h index 9bf1464..7d445ff 100644 --- a/drivers/staging/line6/variax.h +++ b/drivers/staging/line6/variax.h @@ -67,6 +67,6 @@ struct usb_line6_variax { extern void line6_variax_disconnect(struct usb_interface *interface); extern int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6); -extern void line6_variax_process_message(struct usb_line6_variax *variax); +extern void line6_variax_process_message(struct usb_line6 *line6); #endif -- cgit v0.10.2 From 01f6b2bc6a40efa2d29b213e636b9208a8126318 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:58 -0800 Subject: staging: line6: Call *_process_message() via pointer Which *_process_message() function (if any) to call when data is received is known at initialization. Add a function pointer to the `usb_line6' struct and use to call into the appropriate logic instead of evaluating the conditional logic for each message. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 369e60e..f7629cb 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -537,37 +537,8 @@ static void line6_data_received(struct urb *urb) line6->message_length = done; line6_midi_receive(line6, line6->buffer_message, done); - switch (line6->type) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_PODXT: - case LINE6_PODXTPRO: - case LINE6_POCKETPOD: - line6_pod_process_message(line6); - break; - - case LINE6_PODHD300: - case LINE6_PODHD400: - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - break; /* let userspace handle MIDI */ - - case LINE6_PODXTLIVE_POD: - line6_pod_process_message(line6); - break; - - case LINE6_PODXTLIVE_VARIAX: - line6_variax_process_message(line6); - break; - - case LINE6_VARIAX: - line6_variax_process_message(line6); - break; - - default: - MISSING_CASE; - } + if (line6->process_message) + line6->process_message(line6); } line6_start_listen(line6); diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index a4bde71..220813f 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -194,6 +194,8 @@ struct usb_line6 { Length of message to be processed. */ int message_length; + + void (*process_message)(struct usb_line6 *); }; extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index aa8977d..79dcff4 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -131,7 +131,7 @@ static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, /* Process a completely received message. */ -void line6_pod_process_message(struct usb_line6 *line6) +static void line6_pod_process_message(struct usb_line6 *line6) { struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; const unsigned char *buf = pod->line6.buffer_message; @@ -359,6 +359,8 @@ static int pod_try_init(struct usb_interface *interface, int err; struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; + line6->process_message = line6_pod_process_message; + init_timer(&pod->startup_timer); INIT_WORK(&pod->startup_work, pod_startup4); diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h index 984a00b..0d78ca7 100644 --- a/drivers/staging/line6/pod.h +++ b/drivers/staging/line6/pod.h @@ -89,6 +89,5 @@ struct usb_line6_pod { extern void line6_pod_disconnect(struct usb_interface *interface); extern int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6); -extern void line6_pod_process_message(struct usb_line6 *line6); #endif diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index 4d41994..ccb1f68 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -130,7 +130,7 @@ static void variax_startup6(struct work_struct *work) /* Process a completely received message. */ -void line6_variax_process_message(struct usb_line6 *line6) +static void line6_variax_process_message(struct usb_line6 *line6) { struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; const unsigned char *buf = variax->line6.buffer_message; @@ -180,6 +180,8 @@ static int variax_try_init(struct usb_interface *interface, struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; int err; + line6->process_message = line6_variax_process_message; + init_timer(&variax->startup_timer1); init_timer(&variax->startup_timer2); INIT_WORK(&variax->startup_work, variax_startup6); diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h index 7d445ff..f21ff20 100644 --- a/drivers/staging/line6/variax.h +++ b/drivers/staging/line6/variax.h @@ -67,6 +67,5 @@ struct usb_line6_variax { extern void line6_variax_disconnect(struct usb_interface *interface); extern int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6); -extern void line6_variax_process_message(struct usb_line6 *line6); #endif -- cgit v0.10.2 From a46c467251353109683d353826208a17aec9383e Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:42:59 -0800 Subject: staging: line6: Call *_disconnect() via pointer Which *_disconnect() to call on disconnect is known at initialization. Add a function pointer to the `usb_line6' struct and use to call into the appropriate logic instead of evaluating the conditional logic. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index f7629cb..fc852f6 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -1017,48 +1017,7 @@ static void line6_disconnect(struct usb_interface *interface) dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); - switch (line6->type) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_POCKETPOD: - case LINE6_PODXT: - case LINE6_PODXTPRO: - line6_pod_disconnect(interface); - break; - - case LINE6_PODHD300: - case LINE6_PODHD400: - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - line6_podhd_disconnect(interface); - break; - - case LINE6_PODXTLIVE_POD: - line6_pod_disconnect(interface); - break; - - case LINE6_PODXTLIVE_VARIAX: - line6_variax_disconnect(interface); - break; - - case LINE6_VARIAX: - line6_variax_disconnect(interface); - break; - - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - line6_toneport_disconnect(interface); - break; - - default: - MISSING_CASE; - } + line6->disconnect(interface); dev_info(&interface->dev, "Line6 %s now disconnected\n", line6->properties->name); diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 220813f..ad203f1 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -196,6 +196,7 @@ struct usb_line6 { int message_length; void (*process_message)(struct usb_line6 *); + void (*disconnect)(struct usb_interface *); }; extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index 79dcff4..b9af5cf 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -360,6 +360,7 @@ static int pod_try_init(struct usb_interface *interface, struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; line6->process_message = line6_pod_process_message; + line6->disconnect = line6_pod_disconnect; init_timer(&pod->startup_timer); INIT_WORK(&pod->startup_work, pod_startup4); diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c index 3bb942e..a57fbce 100644 --- a/drivers/staging/line6/podhd.c +++ b/drivers/staging/line6/podhd.c @@ -98,6 +98,8 @@ static int podhd_try_init(struct usb_interface *interface, if ((interface == NULL) || (podhd == NULL)) return -ENODEV; + line6->disconnect = line6_podhd_disconnect; + /* initialize audio system: */ err = line6_init_audio(line6); if (err < 0) diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index de91910..5c462b7 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -347,6 +347,8 @@ static int toneport_try_init(struct usb_interface *interface, if ((interface == NULL) || (toneport == NULL)) return -ENODEV; + line6->disconnect = line6_toneport_disconnect; + /* initialize audio system: */ err = line6_init_audio(line6); if (err < 0) diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index ccb1f68..ca25b41 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -181,6 +181,7 @@ static int variax_try_init(struct usb_interface *interface, int err; line6->process_message = line6_variax_process_message; + line6->disconnect = line6_variax_disconnect; init_timer(&variax->startup_timer1); init_timer(&variax->startup_timer2); -- cgit v0.10.2 From d29b854fe9036a505af373ac485b2110ebae6ccd Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Mon, 12 Jan 2015 12:43:00 -0800 Subject: staging: line6: Make *_disconnect() functions static Remove declarations from the header and move the definitions up in the source so they need not be forward declared. Signed-off-by: Chris Rorvick Reviewed-by: Stefan Hajnoczi Signed-off-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index b9af5cf..85a4363 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -338,6 +338,35 @@ static void pod_destruct(struct usb_interface *interface) } /* + POD device disconnected. +*/ +static void line6_pod_disconnect(struct usb_interface *interface) +{ + struct usb_line6_pod *pod; + + if (interface == NULL) + return; + pod = usb_get_intfdata(interface); + + if (pod != NULL) { + struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; + struct device *dev = &interface->dev; + + if (line6pcm != NULL) + line6_pcm_disconnect(line6pcm); + + if (dev != NULL) { + /* remove sysfs entries: */ + device_remove_file(dev, &dev_attr_device_id); + device_remove_file(dev, &dev_attr_firmware_version); + device_remove_file(dev, &dev_attr_serial_number); + } + } + + pod_destruct(interface); +} + +/* Create sysfs entries. */ static int pod_create_files2(struct device *dev) @@ -422,32 +451,3 @@ int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) return err; } - -/* - POD device disconnected. -*/ -void line6_pod_disconnect(struct usb_interface *interface) -{ - struct usb_line6_pod *pod; - - if (interface == NULL) - return; - pod = usb_get_intfdata(interface); - - if (pod != NULL) { - struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; - struct device *dev = &interface->dev; - - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - - if (dev != NULL) { - /* remove sysfs entries: */ - device_remove_file(dev, &dev_attr_device_id); - device_remove_file(dev, &dev_attr_firmware_version); - device_remove_file(dev, &dev_attr_serial_number); - } - } - - pod_destruct(interface); -} diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h index 0d78ca7..87a8f0f 100644 --- a/drivers/staging/line6/pod.h +++ b/drivers/staging/line6/pod.h @@ -86,7 +86,6 @@ struct usb_line6_pod { int device_id; }; -extern void line6_pod_disconnect(struct usb_interface *interface); extern int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6); diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c index a57fbce..27c5402 100644 --- a/drivers/staging/line6/podhd.c +++ b/drivers/staging/line6/podhd.c @@ -87,6 +87,27 @@ static void podhd_destruct(struct usb_interface *interface) } /* + POD HD device disconnected. +*/ +static void line6_podhd_disconnect(struct usb_interface *interface) +{ + struct usb_line6_podhd *podhd; + + if (interface == NULL) + return; + podhd = usb_get_intfdata(interface); + + if (podhd != NULL) { + struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; + + if (line6pcm != NULL) + line6_pcm_disconnect(line6pcm); + } + + podhd_destruct(interface); +} + +/* Try to init POD HD device. */ static int podhd_try_init(struct usb_interface *interface, @@ -133,24 +154,3 @@ int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) return err; } - -/* - POD HD device disconnected. -*/ -void line6_podhd_disconnect(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd; - - if (interface == NULL) - return; - podhd = usb_get_intfdata(interface); - - if (podhd != NULL) { - struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; - - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - } - - podhd_destruct(interface); -} diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h index b7d9568..a14f711 100644 --- a/drivers/staging/line6/podhd.h +++ b/drivers/staging/line6/podhd.h @@ -23,7 +23,6 @@ struct usb_line6_podhd { struct usb_line6 line6; }; -extern void line6_podhd_disconnect(struct usb_interface *interface); extern int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6); diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 5c462b7..aae78d8 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -336,6 +336,39 @@ static void toneport_setup(struct usb_line6_toneport *toneport) } /* + Toneport device disconnected. +*/ +static void line6_toneport_disconnect(struct usb_interface *interface) +{ + struct usb_line6_toneport *toneport; + u16 idProduct; + + if (interface == NULL) + return; + + toneport = usb_get_intfdata(interface); + del_timer_sync(&toneport->timer); + idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); + + if (toneport_has_led(idProduct)) { + device_remove_file(&interface->dev, &dev_attr_led_red); + device_remove_file(&interface->dev, &dev_attr_led_green); + } + + if (toneport != NULL) { + struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; + + if (line6pcm != NULL) { + line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); + line6_pcm_disconnect(line6pcm); + } + } + + toneport_destruct(interface); +} + + +/* Try to init Toneport device. */ static int toneport_try_init(struct usb_interface *interface, @@ -430,34 +463,3 @@ void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) { toneport_setup(toneport); } - -/* - Toneport device disconnected. -*/ -void line6_toneport_disconnect(struct usb_interface *interface) -{ - struct usb_line6_toneport *toneport; - struct snd_line6_pcm *line6pcm; - - if (interface == NULL) - return; - - toneport = usb_get_intfdata(interface); - if (NULL == toneport) - return; - - del_timer_sync(&toneport->timer); - - if (toneport_has_led(toneport->line6.type)) { - device_remove_file(&interface->dev, &dev_attr_led_red); - device_remove_file(&interface->dev, &dev_attr_led_green); - } - - line6pcm = toneport->line6.line6pcm; - if (line6pcm != NULL) { - line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); - line6_pcm_disconnect(line6pcm); - } - - toneport_destruct(interface); -} diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h index af2b4e0..8cb1442 100644 --- a/drivers/staging/line6/toneport.h +++ b/drivers/staging/line6/toneport.h @@ -44,7 +44,6 @@ struct usb_line6_toneport { struct timer_list timer; }; -extern void line6_toneport_disconnect(struct usb_interface *interface); extern int line6_toneport_init(struct usb_interface *interface, struct usb_line6 *line6); extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index ca25b41..b4a41b0 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -172,6 +172,17 @@ static void variax_destruct(struct usb_interface *interface) } /* + Workbench device disconnected. +*/ +static void line6_variax_disconnect(struct usb_interface *interface) +{ + if (interface == NULL) + return; + + variax_destruct(interface); +} + +/* Try to init workbench device. */ static int variax_try_init(struct usb_interface *interface, @@ -226,14 +237,3 @@ int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) return err; } - -/* - Workbench device disconnected. -*/ -void line6_variax_disconnect(struct usb_interface *interface) -{ - if (interface == NULL) - return; - - variax_destruct(interface); -} diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h index f21ff20..dfb94e5 100644 --- a/drivers/staging/line6/variax.h +++ b/drivers/staging/line6/variax.h @@ -64,7 +64,6 @@ struct usb_line6_variax { int startup_progress; }; -extern void line6_variax_disconnect(struct usb_interface *interface); extern int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6); -- cgit v0.10.2 From 61864d844c296933d40c02683252bbea5193b101 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Jan 2015 22:29:57 +0100 Subject: ALSA: move line6 usb driver into sound/usb Promote line6 driver from staging to sound/usb/line6 directory, and maintain through sound subsystem tree. This commit just moves the code and adapts Makefile / Kconfig. The further renames and misc cleanups will follow. Signed-off-by: Takashi Iwai diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 815de37..9049dd9 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig" source "drivers/staging/rts5208/Kconfig" -source "drivers/staging/line6/Kconfig" - source "drivers/staging/octeon/Kconfig" source "drivers/staging/octeon-usb/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 33c640b..fe26ff1 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8188EU) += rtl8188eu/ obj-$(CONFIG_R8723AU) += rtl8723au/ obj-$(CONFIG_RTS5208) += rts5208/ -obj-$(CONFIG_LINE6_USB) += line6/ obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ obj-$(CONFIG_OCTEON_USB) += octeon-usb/ diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig deleted file mode 100644 index 4f1219b..0000000 --- a/drivers/staging/line6/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -menuconfig LINE6_USB - tristate "Line6 USB support" - depends on USB && SND - select SND_RAWMIDI - select SND_PCM - help - This is a driver for the guitar amp, cab, and effects modeller - PODxt Pro by Line6 (and similar devices), supporting the - following features: - * Reading/writing individual parameters - * Reading/writing complete channel, effects setup, and amp - setup data - * Channel switching - * Virtual MIDI interface - * Tuner access - * Playback/capture/mixer device for any ALSA-compatible PCM - audio application - * Signal routing (record clean/processed guitar signal, - re-amping) - - Preliminary support for the Variax Workbench and TonePort - devices is included. - -if LINE6_USB - -config LINE6_USB_IMPULSE_RESPONSE - bool "measure impulse response" - default n - help - Say Y here to add code to measure the impulse response of a Line6 - device. This is more accurate than user-space methods since it - bypasses any PCM data buffering (e.g., by ALSA or jack). This is - useful for assessing the performance of new devices, but is not - required for normal operation. - - If unsure, say N. - -endif # LINE6_USB diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile deleted file mode 100644 index ae5c374..0000000 --- a/drivers/staging/line6/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -obj-$(CONFIG_LINE6_USB) += line6usb.o - -line6usb-y := \ - audio.o \ - capture.o \ - driver.o \ - midi.o \ - midibuf.o \ - pcm.o \ - playback.o \ - pod.o \ - toneport.o \ - variax.o \ - podhd.o diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c deleted file mode 100644 index 171d80c..0000000 --- a/drivers/staging/line6/audio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include - -#include "driver.h" -#include "audio.h" - -/* - Initialize the Line6 USB audio system. -*/ -int line6_init_audio(struct usb_line6 *line6) -{ - struct snd_card *card; - int err; - - err = snd_card_new(line6->ifcdev, - SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &card); - if (err < 0) - return err; - - line6->card = card; - - strcpy(card->id, line6->properties->id); - strcpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, line6->properties->name); - /* longname is 80 chars - see asound.h */ - sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name, - dev_name(line6->ifcdev)); - return 0; -} - -/* - Register the Line6 USB audio system. -*/ -int line6_register_audio(struct usb_line6 *line6) -{ - int err; - - err = snd_card_register(line6->card); - if (err < 0) - return err; - - return 0; -} - -/* - Cleanup the Line6 USB audio system. -*/ -void line6_cleanup_audio(struct usb_line6 *line6) -{ - struct snd_card *card = line6->card; - - if (card == NULL) - return; - - snd_card_disconnect(card); - snd_card_free(card); - line6->card = NULL; -} diff --git a/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h deleted file mode 100644 index 5f8a09a..0000000 --- a/drivers/staging/line6/audio.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef AUDIO_H -#define AUDIO_H - -#include "driver.h" - -extern void line6_cleanup_audio(struct usb_line6 *); -extern int line6_init_audio(struct usb_line6 *); -extern int line6_register_audio(struct usb_line6 *); - -#endif diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c deleted file mode 100644 index f24c7c5..0000000 --- a/drivers/staging/line6/capture.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "pcm.h" -#include "pod.h" - -/* - Find a free URB and submit it. -*/ -static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) -{ - int index; - unsigned long flags; - int i, urb_size; - int ret; - struct urb *urb_in; - - spin_lock_irqsave(&line6pcm->lock_audio_in, flags); - index = - find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); - - if (index < 0 || index >= LINE6_ISO_BUFFERS) { - spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); - dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); - return -EINVAL; - } - - urb_in = line6pcm->urb_audio_in[index]; - urb_size = 0; - - for (i = 0; i < LINE6_ISO_PACKETS; ++i) { - struct usb_iso_packet_descriptor *fin = - &urb_in->iso_frame_desc[i]; - fin->offset = urb_size; - fin->length = line6pcm->max_packet_size; - urb_size += line6pcm->max_packet_size; - } - - urb_in->transfer_buffer = - line6pcm->buffer_in + - index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; - urb_in->transfer_buffer_length = urb_size; - urb_in->context = line6pcm; - - ret = usb_submit_urb(urb_in, GFP_ATOMIC); - - if (ret == 0) - set_bit(index, &line6pcm->active_urb_in); - else - dev_err(line6pcm->line6->ifcdev, - "URB in #%d submission failed (%d)\n", index, ret); - - spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); - return 0; -} - -/* - Submit all currently available capture URBs. -*/ -int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) -{ - int ret, i; - - for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { - ret = submit_audio_in_urb(line6pcm); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - Unlink all currently active capture URBs. -*/ -void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - unsigned int i; - - for (i = LINE6_ISO_BUFFERS; i--;) { - if (test_bit(i, &line6pcm->active_urb_in)) { - if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { - struct urb *u = line6pcm->urb_audio_in[i]; - - usb_unlink_urb(u); - } - } - } -} - -/* - Wait until unlinking of all currently active capture URBs has been - finished. -*/ -void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - int timeout = HZ; - unsigned int i; - int alive; - - do { - alive = 0; - for (i = LINE6_ISO_BUFFERS; i--;) { - if (test_bit(i, &line6pcm->active_urb_in)) - alive++; - } - if (!alive) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } while (--timeout > 0); - if (alive) - snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); -} - -/* - Unlink all currently active capture URBs, and wait for finishing. -*/ -void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - line6_unlink_audio_in_urbs(line6pcm); - line6_wait_clear_audio_in_urbs(line6pcm); -} - -/* - Copy data into ALSA capture buffer. -*/ -void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) -{ - struct snd_pcm_substream *substream = - get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); - struct snd_pcm_runtime *runtime = substream->runtime; - const int bytes_per_frame = line6pcm->properties->bytes_per_frame; - int frames = fsize / bytes_per_frame; - - if (runtime == NULL) - return; - - if (line6pcm->pos_in_done + frames > runtime->buffer_size) { - /* - The transferred area goes over buffer boundary, - copy two separate chunks. - */ - int len; - - len = runtime->buffer_size - line6pcm->pos_in_done; - - if (len > 0) { - memcpy(runtime->dma_area + - line6pcm->pos_in_done * bytes_per_frame, fbuf, - len * bytes_per_frame); - memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, - (frames - len) * bytes_per_frame); - } else { - /* this is somewhat paranoid */ - dev_err(line6pcm->line6->ifcdev, - "driver bug: len = %d\n", len); - } - } else { - /* copy single chunk */ - memcpy(runtime->dma_area + - line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); - } - - line6pcm->pos_in_done += frames; - if (line6pcm->pos_in_done >= runtime->buffer_size) - line6pcm->pos_in_done -= runtime->buffer_size; -} - -void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) -{ - struct snd_pcm_substream *substream = - get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); - - line6pcm->bytes_in += length; - if (line6pcm->bytes_in >= line6pcm->period_in) { - line6pcm->bytes_in %= line6pcm->period_in; - snd_pcm_period_elapsed(substream); - } -} - -void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) -{ - kfree(line6pcm->buffer_in); - line6pcm->buffer_in = NULL; -} - -/* - * Callback for completed capture URB. - */ -static void audio_in_callback(struct urb *urb) -{ - int i, index, length = 0, shutdown = 0; - unsigned long flags; - - struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; - - line6pcm->last_frame_in = urb->start_frame; - - /* find index of URB */ - for (index = 0; index < LINE6_ISO_BUFFERS; ++index) - if (urb == line6pcm->urb_audio_in[index]) - break; - - spin_lock_irqsave(&line6pcm->lock_audio_in, flags); - - for (i = 0; i < LINE6_ISO_PACKETS; ++i) { - char *fbuf; - int fsize; - struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; - - if (fin->status == -EXDEV) { - shutdown = 1; - break; - } - - fbuf = urb->transfer_buffer + fin->offset; - fsize = fin->actual_length; - - if (fsize > line6pcm->max_packet_size) { - dev_err(line6pcm->line6->ifcdev, - "driver and/or device bug: packet too large (%d > %d)\n", - fsize, line6pcm->max_packet_size); - } - - length += fsize; - - /* the following assumes LINE6_ISO_PACKETS == 1: */ - line6pcm->prev_fbuf = fbuf; - line6pcm->prev_fsize = fsize; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) -#endif - if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - &line6pcm->flags) && (fsize > 0)) - line6_capture_copy(line6pcm, fbuf, fsize); - } - - clear_bit(index, &line6pcm->active_urb_in); - - if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) - shutdown = 1; - - spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); - - if (!shutdown) { - submit_audio_in_urb(line6pcm); - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) -#endif - if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - &line6pcm->flags)) - line6_capture_check_period(line6pcm, length); - } -} - -/* open capture callback */ -static int snd_line6_capture_open(struct snd_pcm_substream *substream) -{ - int err; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - err = snd_pcm_hw_constraint_ratdens(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - (&line6pcm-> - properties->snd_line6_rates)); - if (err < 0) - return err; - - runtime->hw = line6pcm->properties->snd_line6_capture_hw; - return 0; -} - -/* close capture callback */ -static int snd_line6_capture_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* hw_params capture callback */ -static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - int ret; - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - /* -- Florian Demski [FD] */ - /* don't ask me why, but this fixes the bug on my machine */ - if (line6pcm == NULL) { - if (substream->pcm == NULL) - return -ENOMEM; - if (substream->pcm->private_data == NULL) - return -ENOMEM; - substream->private_data = substream->pcm->private_data; - line6pcm = snd_pcm_substream_chip(substream); - } - /* -- [FD] end */ - - ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); - - if (ret < 0) - return ret; - - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) { - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); - return ret; - } - - line6pcm->period_in = params_period_bytes(hw_params); - return 0; -} - -/* hw_free capture callback */ -static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); - return snd_pcm_lib_free_pages(substream); -} - -/* trigger callback */ -int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) -{ - int err; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: -#ifdef CONFIG_PM - case SNDRV_PCM_TRIGGER_RESUME: -#endif - err = line6_pcm_acquire(line6pcm, - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); - - if (err < 0) - return err; - - break; - - case SNDRV_PCM_TRIGGER_STOP: -#ifdef CONFIG_PM - case SNDRV_PCM_TRIGGER_SUSPEND: -#endif - err = line6_pcm_release(line6pcm, - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); - - if (err < 0) - return err; - - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* capture pointer callback */ -static snd_pcm_uframes_t -snd_line6_capture_pointer(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - return line6pcm->pos_in_done; -} - -/* capture operators */ -struct snd_pcm_ops snd_line6_capture_ops = { - .open = snd_line6_capture_open, - .close = snd_line6_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_line6_capture_hw_params, - .hw_free = snd_line6_capture_hw_free, - .prepare = snd_line6_prepare, - .trigger = snd_line6_trigger, - .pointer = snd_line6_capture_pointer, -}; - -int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - struct usb_line6 *line6 = line6pcm->line6; - int i; - - /* create audio URBs and fill in constant values: */ - for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { - struct urb *urb; - - /* URB for audio in: */ - urb = line6pcm->urb_audio_in[i] = - usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); - - if (urb == NULL) { - dev_err(line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - urb->dev = line6->usbdev; - urb->pipe = - usb_rcvisocpipe(line6->usbdev, - line6->properties->ep_audio_r & - USB_ENDPOINT_NUMBER_MASK); - urb->transfer_flags = URB_ISO_ASAP; - urb->start_frame = -1; - urb->number_of_packets = LINE6_ISO_PACKETS; - urb->interval = LINE6_ISO_INTERVAL; - urb->error_count = 0; - urb->complete = audio_in_callback; - } - - return 0; -} diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h deleted file mode 100644 index 4157bcb..0000000 --- a/drivers/staging/line6/capture.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef CAPTURE_H -#define CAPTURE_H - -#include - -#include "driver.h" -#include "pcm.h" - -extern struct snd_pcm_ops snd_line6_capture_ops; - -extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, - int fsize); -extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, - int length); -extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); -extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm); -extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); -extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm); -extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm - *line6pcm); -extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm); -extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); - -#endif diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c deleted file mode 100644 index fc852f6..0000000 --- a/drivers/staging/line6/driver.c +++ /dev/null @@ -1,1114 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "midi.h" -#include "playback.h" -#include "pod.h" -#include "podhd.h" -#include "revision.h" -#include "toneport.h" -#include "usbdefs.h" -#include "variax.h" - -#define DRIVER_AUTHOR "Markus Grabner " -#define DRIVER_DESC "Line6 USB Driver" -#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION - -#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) -#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) - -/* table of devices that work with this driver */ -static const struct usb_device_id line6_id_table[] = { - { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, - { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, - { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, - { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, - { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, - { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, - { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, - { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, - { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, - { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, - { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, - { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, - { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, - { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, - { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, - { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, - { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, - { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, - { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, - { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, - {} -}; - -MODULE_DEVICE_TABLE(usb, line6_id_table); - -static const struct line6_properties line6_properties_table[] = { - [LINE6_BASSPODXT] = { - .id = "BassPODxt", - .name = "BassPODxt", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_BASSPODXTLIVE] = { - .id = "BassPODxtLive", - .name = "BassPODxt Live", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_BASSPODXTPRO] = { - .id = "BassPODxtPro", - .name = "BassPODxt Pro", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_GUITARPORT] = { - .id = "GuitarPort", - .name = "GuitarPort", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_POCKETPOD] = { - .id = "PocketPOD", - .name = "Pocket POD", - .capabilities = LINE6_CAP_CONTROL, - .altsetting = 0, - .ep_ctrl_r = 0x82, - .ep_ctrl_w = 0x02, - /* no audio channel */ - }, - [LINE6_PODHD300] = { - .id = "PODHD300", - .name = "POD HD300", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODHD400] = { - .id = "PODHD400", - .name = "POD HD400", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODHD500_0] = { - .id = "PODHD500", - .name = "POD HD500", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x81, - .ep_ctrl_w = 0x01, - .ep_audio_r = 0x86, - .ep_audio_w = 0x02, - }, - [LINE6_PODHD500_1] = { - .id = "PODHD500", - .name = "POD HD500", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x81, - .ep_ctrl_w = 0x01, - .ep_audio_r = 0x86, - .ep_audio_w = 0x02, - }, - [LINE6_PODSTUDIO_GX] = { - .id = "PODStudioGX", - .name = "POD Studio GX", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODSTUDIO_UX1] = { - .id = "PODStudioUX1", - .name = "POD Studio UX1", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODSTUDIO_UX2] = { - .id = "PODStudioUX2", - .name = "POD Studio UX2", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXT] = { - .id = "PODxt", - .name = "PODxt", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXTLIVE_POD] = { - .id = "PODxtLive", - .name = "PODxt Live", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXTLIVE_VARIAX] = { - .id = "PODxtLive", - .name = "PODxt Live", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x86, - .ep_ctrl_w = 0x05, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXTPRO] = { - .id = "PODxtPro", - .name = "PODxt Pro", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_TONEPORT_GX] = { - .id = "TonePortGX", - .name = "TonePort GX", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_TONEPORT_UX1] = { - .id = "TonePortUX1", - .name = "TonePort UX1", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_TONEPORT_UX2] = { - .id = "TonePortUX2", - .name = "TonePort UX2", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_VARIAX] = { - .id = "Variax", - .name = "Variax Workbench", - .capabilities = LINE6_CAP_CONTROL, - .altsetting = 1, - .ep_ctrl_r = 0x82, - .ep_ctrl_w = 0x01, - /* no audio channel */ - } -}; - -/* - This is Line6's MIDI manufacturer ID. -*/ -const unsigned char line6_midi_id[] = { - 0x00, 0x01, 0x0c -}; - -/* - Code to request version of POD, Variax interface - (and maybe other devices). -*/ -static const char line6_request_version[] = { - 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 -}; - -/** - Class for asynchronous messages. -*/ -struct message { - struct usb_line6 *line6; - const char *buffer; - int size; - int done; -}; - -/* - Forward declarations. -*/ -static void line6_data_received(struct urb *urb); -static int line6_send_raw_message_async_part(struct message *msg, - struct urb *urb); - -/* - Start to listen on endpoint. -*/ -static int line6_start_listen(struct usb_line6 *line6) -{ - int err; - - usb_fill_int_urb(line6->urb_listen, line6->usbdev, - usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), - line6->buffer_listen, LINE6_BUFSIZE_LISTEN, - line6_data_received, line6, line6->interval); - line6->urb_listen->actual_length = 0; - err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); - return err; -} - -/* - Stop listening on endpoint. -*/ -static void line6_stop_listen(struct usb_line6 *line6) -{ - usb_kill_urb(line6->urb_listen); -} - -/* - Send raw message in pieces of wMaxPacketSize bytes. -*/ -int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, - int size) -{ - int i, done = 0; - - for (i = 0; i < size; i += line6->max_packet_size) { - int partial; - const char *frag_buf = buffer + i; - int frag_size = min(line6->max_packet_size, size - i); - int retval; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->properties->ep_ctrl_w), - (char *)frag_buf, frag_size, - &partial, LINE6_TIMEOUT * HZ); - - if (retval) { - dev_err(line6->ifcdev, - "usb_interrupt_msg failed (%d)\n", retval); - break; - } - - done += frag_size; - } - - return done; -} - -/* - Notification of completion of asynchronous request transmission. -*/ -static void line6_async_request_sent(struct urb *urb) -{ - struct message *msg = (struct message *)urb->context; - - if (msg->done >= msg->size) { - usb_free_urb(urb); - kfree(msg); - } else - line6_send_raw_message_async_part(msg, urb); -} - -/* - Asynchronously send part of a raw message. -*/ -static int line6_send_raw_message_async_part(struct message *msg, - struct urb *urb) -{ - int retval; - struct usb_line6 *line6 = msg->line6; - int done = msg->done; - int bytes = min(msg->size - done, line6->max_packet_size); - - usb_fill_int_urb(urb, line6->usbdev, - usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), - (char *)msg->buffer + done, bytes, - line6_async_request_sent, msg, line6->interval); - - msg->done += bytes; - retval = usb_submit_urb(urb, GFP_ATOMIC); - - if (retval < 0) { - dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", - __func__, retval); - usb_free_urb(urb); - kfree(msg); - return retval; - } - - return 0; -} - -/* - Setup and start timer. -*/ -void line6_start_timer(struct timer_list *timer, unsigned int msecs, - void (*function)(unsigned long), unsigned long data) -{ - setup_timer(timer, function, data); - timer->expires = jiffies + msecs * HZ / 1000; - add_timer(timer); -} - -/* - Asynchronously send raw message. -*/ -int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, - int size) -{ - struct message *msg; - struct urb *urb; - - /* create message: */ - msg = kmalloc(sizeof(struct message), GFP_ATOMIC); - if (msg == NULL) - return -ENOMEM; - - /* create URB: */ - urb = usb_alloc_urb(0, GFP_ATOMIC); - - if (urb == NULL) { - kfree(msg); - dev_err(line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - /* set message data: */ - msg->line6 = line6; - msg->buffer = buffer; - msg->size = size; - msg->done = 0; - - /* start sending: */ - return line6_send_raw_message_async_part(msg, urb); -} - -/* - Send asynchronous device version request. -*/ -int line6_version_request_async(struct usb_line6 *line6) -{ - char *buffer; - int retval; - - buffer = kmemdup(line6_request_version, - sizeof(line6_request_version), GFP_ATOMIC); - if (buffer == NULL) { - dev_err(line6->ifcdev, "Out of memory"); - return -ENOMEM; - } - - retval = line6_send_raw_message_async(line6, buffer, - sizeof(line6_request_version)); - kfree(buffer); - return retval; -} - -/* - Send sysex message in pieces of wMaxPacketSize bytes. -*/ -int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, - int size) -{ - return line6_send_raw_message(line6, buffer, - size + SYSEX_EXTRA_SIZE) - - SYSEX_EXTRA_SIZE; -} - -/* - Allocate buffer for sysex message and prepare header. - @param code sysex message code - @param size number of bytes between code and sysex end -*/ -char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, - int size) -{ - char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); - - if (!buffer) - return NULL; - - buffer[0] = LINE6_SYSEX_BEGIN; - memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); - buffer[sizeof(line6_midi_id) + 1] = code1; - buffer[sizeof(line6_midi_id) + 2] = code2; - buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; - return buffer; -} - -/* - Notification of data received from the Line6 device. -*/ -static void line6_data_received(struct urb *urb) -{ - struct usb_line6 *line6 = (struct usb_line6 *)urb->context; - struct midi_buffer *mb = &line6->line6midi->midibuf_in; - int done; - - if (urb->status == -ESHUTDOWN) - return; - - done = - line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); - - if (done < urb->actual_length) { - line6_midibuf_ignore(mb, done); - dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", - done, urb->actual_length); - } - - for (;;) { - done = - line6_midibuf_read(mb, line6->buffer_message, - LINE6_MESSAGE_MAXLEN); - - if (done == 0) - break; - - line6->message_length = done; - line6_midi_receive(line6, line6->buffer_message, done); - - if (line6->process_message) - line6->process_message(line6); - } - - line6_start_listen(line6); -} - -/* - Send channel number (i.e., switch to a different sound). -*/ -int line6_send_program(struct usb_line6 *line6, u8 value) -{ - int retval; - unsigned char *buffer; - int partial; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST; - buffer[1] = value; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->properties->ep_ctrl_w), - buffer, 2, &partial, LINE6_TIMEOUT * HZ); - - if (retval) - dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", - retval); - - kfree(buffer); - return retval; -} - -/* - Transmit Line6 control parameter. -*/ -int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) -{ - int retval; - unsigned char *buffer; - int partial; - - buffer = kmalloc(3, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST; - buffer[1] = param; - buffer[2] = value; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->properties->ep_ctrl_w), - buffer, 3, &partial, LINE6_TIMEOUT * HZ); - - if (retval) - dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", - retval); - - kfree(buffer); - return retval; -} - -/* - Read data from device. -*/ -int line6_read_data(struct usb_line6 *line6, int address, void *data, - size_t datalen) -{ - struct usb_device *usbdev = line6->usbdev; - int ret; - unsigned char len; - - /* query the serial number: */ - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - (datalen << 8) | 0x21, address, - NULL, 0, LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); - return ret; - } - - /* Wait for data length. We'll get 0xff until length arrives. */ - do { - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, &len, 1, - LINE6_TIMEOUT * HZ); - if (ret < 0) { - dev_err(line6->ifcdev, - "receive length failed (error %d)\n", ret); - return ret; - } - } while (len == 0xff); - - if (len != datalen) { - /* should be equal or something went wrong */ - dev_err(line6->ifcdev, - "length mismatch (expected %d, got %d)\n", - (int)datalen, (int)len); - return -EINVAL; - } - - /* receive the result: */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0013, 0x0000, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, "read failed (error %d)\n", ret); - return ret; - } - - return 0; -} - -/* - Write data to device. -*/ -int line6_write_data(struct usb_line6 *line6, int address, void *data, - size_t datalen) -{ - struct usb_device *usbdev = line6->usbdev; - int ret; - unsigned char status; - - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - 0x0022, address, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, - "write request failed (error %d)\n", ret); - return ret; - } - - do { - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), - 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, - &status, 1, LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, - "receiving status failed (error %d)\n", ret); - return ret; - } - } while (status == 0xff); - - if (status != 0) { - dev_err(line6->ifcdev, "write failed (error %d)\n", ret); - return -EINVAL; - } - - return 0; -} - -/* - Read Line6 device serial number. - (POD, TonePort, GuitarPort) -*/ -int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) -{ - return line6_read_data(line6, 0x80d0, serial_number, - sizeof(*serial_number)); -} - -/* - No operation (i.e., unsupported). -*/ -ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return 0; -} - -/* - Generic destructor. -*/ -static void line6_destruct(struct usb_interface *interface) -{ - struct usb_line6 *line6; - - if (interface == NULL) - return; - line6 = usb_get_intfdata(interface); - if (line6 == NULL) - return; - - /* free buffer memory first: */ - kfree(line6->buffer_message); - kfree(line6->buffer_listen); - - /* then free URBs: */ - usb_free_urb(line6->urb_listen); - - /* make sure the device isn't destructed twice: */ - usb_set_intfdata(interface, NULL); - - /* free interface data: */ - kfree(line6); -} - -/* - Probe USB device. -*/ -static int line6_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - enum line6_device_type devtype; - struct usb_device *usbdev; - struct usb_line6 *line6; - const struct line6_properties *properties; - int interface_number; - int size = 0; - int ret; - - if (interface == NULL) - return -ENODEV; - usbdev = interface_to_usbdev(interface); - if (usbdev == NULL) - return -ENODEV; - - /* we don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) { - ret = -ENODEV; - goto err_put; - } - - devtype = id->driver_info; - - /* initialize device info: */ - properties = &line6_properties_table[devtype]; - dev_info(&interface->dev, "Line6 %s found\n", properties->name); - - /* query interface number */ - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - - ret = usb_set_interface(usbdev, interface_number, - properties->altsetting); - if (ret < 0) { - dev_err(&interface->dev, "set_interface failed\n"); - goto err_put; - } - - /* initialize device data based on device: */ - switch (devtype) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_PODXT: - case LINE6_PODXTPRO: - size = sizeof(struct usb_line6_pod); - break; - - case LINE6_PODHD300: - case LINE6_PODHD400: - size = sizeof(struct usb_line6_podhd); - break; - - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - size = sizeof(struct usb_line6_podhd); - break; - - case LINE6_POCKETPOD: - size = sizeof(struct usb_line6_pod); - break; - - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - size = sizeof(struct usb_line6_toneport); - break; - - case LINE6_PODXTLIVE_POD: - size = sizeof(struct usb_line6_pod); - break; - - case LINE6_PODXTLIVE_VARIAX: - size = sizeof(struct usb_line6_variax); - break; - - case LINE6_VARIAX: - size = sizeof(struct usb_line6_variax); - break; - - default: - MISSING_CASE; - ret = -ENODEV; - goto err_put; - } - - if (size == 0) { - dev_err(&interface->dev, - "driver bug: interface data size not set\n"); - ret = -ENODEV; - goto err_put; - } - - line6 = kzalloc(size, GFP_KERNEL); - if (line6 == NULL) { - ret = -ENODEV; - goto err_put; - } - - /* store basic data: */ - line6->properties = properties; - line6->usbdev = usbdev; - line6->ifcdev = &interface->dev; - line6->type = devtype; - - /* get data from endpoint descriptor (see usb_maxpacket): */ - { - struct usb_host_endpoint *ep; - unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r); - unsigned epnum = usb_pipeendpoint(pipe); - ep = usbdev->ep_in[epnum]; - - if (ep != NULL) { - line6->interval = ep->desc.bInterval; - line6->max_packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - } else { - line6->interval = LINE6_FALLBACK_INTERVAL; - line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; - dev_err(line6->ifcdev, - "endpoint not available, using fallback values"); - } - } - - usb_set_intfdata(interface, line6); - - if (properties->capabilities & LINE6_CAP_CONTROL) { - /* initialize USB buffers: */ - line6->buffer_listen = - kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); - if (line6->buffer_listen == NULL) { - ret = -ENOMEM; - goto err_destruct; - } - - line6->buffer_message = - kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); - if (line6->buffer_message == NULL) { - ret = -ENOMEM; - goto err_destruct; - } - - line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); - - if (line6->urb_listen == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - line6_destruct(interface); - ret = -ENOMEM; - goto err_destruct; - } - - ret = line6_start_listen(line6); - if (ret < 0) { - dev_err(&interface->dev, "%s: usb_submit_urb failed\n", - __func__); - goto err_destruct; - } - } - - /* initialize device data based on device: */ - switch (devtype) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_POCKETPOD: - case LINE6_PODXT: - case LINE6_PODXTPRO: - ret = line6_pod_init(interface, line6); - break; - - case LINE6_PODHD300: - case LINE6_PODHD400: - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - ret = line6_podhd_init(interface, line6); - break; - - case LINE6_PODXTLIVE_POD: - ret = line6_pod_init(interface, line6); - break; - - case LINE6_PODXTLIVE_VARIAX: - ret = line6_variax_init(interface, line6); - break; - - case LINE6_VARIAX: - ret = line6_variax_init(interface, line6); - break; - - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - ret = line6_toneport_init(interface, line6); - break; - - default: - MISSING_CASE; - ret = -ENODEV; - } - - if (ret < 0) - goto err_destruct; - - ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, - "usb_device"); - if (ret < 0) - goto err_destruct; - - /* creation of additional special files should go here */ - - dev_info(&interface->dev, "Line6 %s now attached\n", - line6->properties->name); - - /* increment reference counters: */ - usb_get_intf(interface); - usb_get_dev(usbdev); - - return 0; - -err_destruct: - line6_destruct(interface); -err_put: - return ret; -} - -/* - Line6 device disconnected. -*/ -static void line6_disconnect(struct usb_interface *interface) -{ - struct usb_line6 *line6; - struct usb_device *usbdev; - int interface_number; - - if (interface == NULL) - return; - usbdev = interface_to_usbdev(interface); - if (usbdev == NULL) - return; - - /* removal of additional special files should go here */ - - sysfs_remove_link(&interface->dev.kobj, "usb_device"); - - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - line6 = usb_get_intfdata(interface); - - if (line6 != NULL) { - if (line6->urb_listen != NULL) - line6_stop_listen(line6); - - if (usbdev != line6->usbdev) - dev_err(line6->ifcdev, - "driver bug: inconsistent usb device\n"); - - line6->disconnect(interface); - - dev_info(&interface->dev, "Line6 %s now disconnected\n", - line6->properties->name); - } - - line6_destruct(interface); - - /* decrement reference counters: */ - usb_put_intf(interface); - usb_put_dev(usbdev); -} - -#ifdef CONFIG_PM - -/* - Suspend Line6 device. -*/ -static int line6_suspend(struct usb_interface *interface, pm_message_t message) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - struct snd_line6_pcm *line6pcm = line6->line6pcm; - - snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); - - if (line6->properties->capabilities & LINE6_CAP_CONTROL) - line6_stop_listen(line6); - - if (line6pcm != NULL) { - snd_pcm_suspend_all(line6pcm->pcm); - line6_pcm_disconnect(line6pcm); - line6pcm->flags = 0; - } - - return 0; -} - -/* - Resume Line6 device. -*/ -static int line6_resume(struct usb_interface *interface) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - - if (line6->properties->capabilities & LINE6_CAP_CONTROL) - line6_start_listen(line6); - - snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); - return 0; -} - -/* - Resume Line6 device after reset. -*/ -static int line6_reset_resume(struct usb_interface *interface) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - - switch (line6->type) { - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - line6_toneport_reset_resume((struct usb_line6_toneport *)line6); - - default: - break; - } - - return line6_resume(interface); -} - -#endif /* CONFIG_PM */ - -static struct usb_driver line6_driver = { - .name = DRIVER_NAME, - .probe = line6_probe, - .disconnect = line6_disconnect, -#ifdef CONFIG_PM - .suspend = line6_suspend, - .resume = line6_resume, - .reset_resume = line6_reset_resume, -#endif - .id_table = line6_id_table, -}; - -module_usb_driver(line6_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h deleted file mode 100644 index ad203f1..0000000 --- a/drivers/staging/line6/driver.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef DRIVER_H -#define DRIVER_H - -#include -#include -#include - -#include "midi.h" - -#define DRIVER_NAME "line6usb" - -enum line6_device_type { - LINE6_BASSPODXT, - LINE6_BASSPODXTLIVE, - LINE6_BASSPODXTPRO, - LINE6_GUITARPORT, - LINE6_POCKETPOD, - LINE6_PODHD300, - LINE6_PODHD400, - LINE6_PODHD500_0, - LINE6_PODHD500_1, - LINE6_PODSTUDIO_GX, - LINE6_PODSTUDIO_UX1, - LINE6_PODSTUDIO_UX2, - LINE6_PODXT, - LINE6_PODXTLIVE_POD, - LINE6_PODXTLIVE_VARIAX, - LINE6_PODXTPRO, - LINE6_TONEPORT_GX, - LINE6_TONEPORT_UX1, - LINE6_TONEPORT_UX2, - LINE6_VARIAX -}; - -#define LINE6_TIMEOUT 1 -#define LINE6_BUFSIZE_LISTEN 32 -#define LINE6_MESSAGE_MAXLEN 256 - -/* - Line6 MIDI control commands -*/ -#define LINE6_PARAM_CHANGE 0xb0 -#define LINE6_PROGRAM_CHANGE 0xc0 -#define LINE6_SYSEX_BEGIN 0xf0 -#define LINE6_SYSEX_END 0xf7 -#define LINE6_RESET 0xff - -/* - MIDI channel for messages initiated by the host - (and eventually echoed back by the device) -*/ -#define LINE6_CHANNEL_HOST 0x00 - -/* - MIDI channel for messages initiated by the device -*/ -#define LINE6_CHANNEL_DEVICE 0x02 - -#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */ - -#define LINE6_CHANNEL_MASK 0x0f - -#define MISSING_CASE \ - pr_err("line6usb driver bug: missing case in %s:%d\n", \ - __FILE__, __LINE__) - -#define CHECK_RETURN(x) \ -do { \ - err = x; \ - if (err < 0) \ - return err; \ -} while (0) - -#define CHECK_STARTUP_PROGRESS(x, n) \ -do { \ - if ((x) >= (n)) \ - return; \ - x = (n); \ -} while (0) - -extern const unsigned char line6_midi_id[3]; - -static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; -static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; - -/** - Common properties of Line6 devices. -*/ -struct line6_properties { - /** - Card id string (maximum 16 characters). - This can be used to address the device in ALSA programs as - "default:CARD=" - */ - const char *id; - - /** - Card short name (maximum 32 characters). - */ - const char *name; - - /** - Bit vector defining this device's capabilities in the - line6usb driver. - */ - int capabilities; - - int altsetting; - - unsigned ep_ctrl_r; - unsigned ep_ctrl_w; - unsigned ep_audio_r; - unsigned ep_audio_w; -}; - -/** - Common data shared by all Line6 devices. - Corresponds to a pair of USB endpoints. -*/ -struct usb_line6 { - /** - USB device. - */ - struct usb_device *usbdev; - - /** - Device type. - */ - enum line6_device_type type; - - /** - Properties. - */ - const struct line6_properties *properties; - - /** - Interval (ms). - */ - int interval; - - /** - Maximum size of USB packet. - */ - int max_packet_size; - - /** - Device representing the USB interface. - */ - struct device *ifcdev; - - /** - Line6 sound card data structure. - Each device has at least MIDI or PCM. - */ - struct snd_card *card; - - /** - Line6 PCM device data structure. - */ - struct snd_line6_pcm *line6pcm; - - /** - Line6 MIDI device data structure. - */ - struct snd_line6_midi *line6midi; - - /** - URB for listening to PODxt Pro control endpoint. - */ - struct urb *urb_listen; - - /** - Buffer for listening to PODxt Pro control endpoint. - */ - unsigned char *buffer_listen; - - /** - Buffer for message to be processed. - */ - unsigned char *buffer_message; - - /** - Length of message to be processed. - */ - int message_length; - - void (*process_message)(struct usb_line6 *); - void (*disconnect)(struct usb_interface *); -}; - -extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, - int code2, int size); -extern ssize_t line6_nop_read(struct device *dev, - struct device_attribute *attr, char *buf); -extern int line6_read_data(struct usb_line6 *line6, int address, void *data, - size_t datalen); -extern int line6_read_serial_number(struct usb_line6 *line6, - int *serial_number); -extern int line6_send_program(struct usb_line6 *line6, u8 value); -extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, - int size); -extern int line6_send_raw_message_async(struct usb_line6 *line6, - const char *buffer, int size); -extern int line6_send_sysex_message(struct usb_line6 *line6, - const char *buffer, int size); -extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -extern void line6_start_timer(struct timer_list *timer, unsigned int msecs, - void (*function)(unsigned long), - unsigned long data); -extern int line6_transmit_parameter(struct usb_line6 *line6, int param, - u8 value); -extern int line6_version_request_async(struct usb_line6 *line6); -extern int line6_write_data(struct usb_line6 *line6, int address, void *data, - size_t datalen); - -#endif diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c deleted file mode 100644 index c9d725a..0000000 --- a/drivers/staging/line6/midi.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include - -#include "audio.h" -#include "driver.h" -#include "midi.h" -#include "pod.h" -#include "usbdefs.h" - -#define line6_rawmidi_substream_midi(substream) \ - ((struct snd_line6_midi *)((substream)->rmidi->private_data)) - -static int send_midi_async(struct usb_line6 *line6, unsigned char *data, - int length); - -/* - Pass data received via USB to MIDI. -*/ -void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, - int length) -{ - if (line6->line6midi->substream_receive) - snd_rawmidi_receive(line6->line6midi->substream_receive, - data, length); -} - -/* - Read data from MIDI buffer and transmit them via USB. -*/ -static void line6_midi_transmit(struct snd_rawmidi_substream *substream) -{ - struct usb_line6 *line6 = - line6_rawmidi_substream_midi(substream)->line6; - struct snd_line6_midi *line6midi = line6->line6midi; - struct midi_buffer *mb = &line6midi->midibuf_out; - unsigned long flags; - unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE]; - int req, done; - - spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags); - - for (;;) { - req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); - done = snd_rawmidi_transmit_peek(substream, chunk, req); - - if (done == 0) - break; - - line6_midibuf_write(mb, chunk, done); - snd_rawmidi_transmit_ack(substream, done); - } - - for (;;) { - done = line6_midibuf_read(mb, chunk, - LINE6_FALLBACK_MAXPACKETSIZE); - - if (done == 0) - break; - - send_midi_async(line6, chunk, done); - } - - spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); -} - -/* - Notification of completion of MIDI transmission. -*/ -static void midi_sent(struct urb *urb) -{ - unsigned long flags; - int status; - int num; - struct usb_line6 *line6 = (struct usb_line6 *)urb->context; - - status = urb->status; - kfree(urb->transfer_buffer); - usb_free_urb(urb); - - if (status == -ESHUTDOWN) - return; - - spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); - num = --line6->line6midi->num_active_send_urbs; - - if (num == 0) { - line6_midi_transmit(line6->line6midi->substream_transmit); - num = line6->line6midi->num_active_send_urbs; - } - - if (num == 0) - wake_up(&line6->line6midi->send_wait); - - spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); -} - -/* - Send an asynchronous MIDI message. - Assumes that line6->line6midi->send_urb_lock is held - (i.e., this function is serialized). -*/ -static int send_midi_async(struct usb_line6 *line6, unsigned char *data, - int length) -{ - struct urb *urb; - int retval; - unsigned char *transfer_buffer; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - - if (urb == NULL) { - dev_err(line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - transfer_buffer = kmemdup(data, length, GFP_ATOMIC); - - if (transfer_buffer == NULL) { - usb_free_urb(urb); - dev_err(line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - usb_fill_int_urb(urb, line6->usbdev, - usb_sndbulkpipe(line6->usbdev, - line6->properties->ep_ctrl_w), - transfer_buffer, length, midi_sent, line6, - line6->interval); - urb->actual_length = 0; - retval = usb_submit_urb(urb, GFP_ATOMIC); - - if (retval < 0) { - dev_err(line6->ifcdev, "usb_submit_urb failed\n"); - usb_free_urb(urb); - return retval; - } - - ++line6->line6midi->num_active_send_urbs; - return 0; -} - -static int line6_midi_output_open(struct snd_rawmidi_substream *substream) -{ - return 0; -} - -static int line6_midi_output_close(struct snd_rawmidi_substream *substream) -{ - return 0; -} - -static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, - int up) -{ - unsigned long flags; - struct usb_line6 *line6 = - line6_rawmidi_substream_midi(substream)->line6; - - line6->line6midi->substream_transmit = substream; - spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); - - if (line6->line6midi->num_active_send_urbs == 0) - line6_midi_transmit(substream); - - spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); -} - -static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) -{ - struct usb_line6 *line6 = - line6_rawmidi_substream_midi(substream)->line6; - struct snd_line6_midi *midi = line6->line6midi; - - wait_event_interruptible(midi->send_wait, - midi->num_active_send_urbs == 0); -} - -static int line6_midi_input_open(struct snd_rawmidi_substream *substream) -{ - return 0; -} - -static int line6_midi_input_close(struct snd_rawmidi_substream *substream) -{ - return 0; -} - -static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, - int up) -{ - struct usb_line6 *line6 = - line6_rawmidi_substream_midi(substream)->line6; - - if (up) - line6->line6midi->substream_receive = substream; - else - line6->line6midi->substream_receive = NULL; -} - -static struct snd_rawmidi_ops line6_midi_output_ops = { - .open = line6_midi_output_open, - .close = line6_midi_output_close, - .trigger = line6_midi_output_trigger, - .drain = line6_midi_output_drain, -}; - -static struct snd_rawmidi_ops line6_midi_input_ops = { - .open = line6_midi_input_open, - .close = line6_midi_input_close, - .trigger = line6_midi_input_trigger, -}; - -/* - Cleanup the Line6 MIDI device. -*/ -static void line6_cleanup_midi(struct snd_rawmidi *rmidi) -{ -} - -/* Create a MIDI device */ -static int snd_line6_new_midi(struct snd_line6_midi *line6midi) -{ - struct snd_rawmidi *rmidi; - int err; - - err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, - &rmidi); - if (err < 0) - return err; - - rmidi->private_data = line6midi; - rmidi->private_free = line6_cleanup_midi; - strcpy(rmidi->id, line6midi->line6->properties->id); - strcpy(rmidi->name, line6midi->line6->properties->name); - - rmidi->info_flags = - SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; - - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &line6_midi_output_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &line6_midi_input_ops); - return 0; -} - -/* MIDI device destructor */ -static int snd_line6_midi_free(struct snd_device *device) -{ - struct snd_line6_midi *line6midi = device->device_data; - - line6_midibuf_destroy(&line6midi->midibuf_in); - line6_midibuf_destroy(&line6midi->midibuf_out); - return 0; -} - -/* - Initialize the Line6 MIDI subsystem. -*/ -int line6_init_midi(struct usb_line6 *line6) -{ - static struct snd_device_ops midi_ops = { - .dev_free = snd_line6_midi_free, - }; - - int err; - struct snd_line6_midi *line6midi; - - if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { - /* skip MIDI initialization and report success */ - return 0; - } - - line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); - - if (line6midi == NULL) - return -ENOMEM; - - err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); - if (err < 0) { - kfree(line6midi); - return err; - } - - err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); - if (err < 0) { - kfree(line6midi->midibuf_in.buf); - kfree(line6midi); - return err; - } - - line6midi->line6 = line6; - line6->line6midi = line6midi; - - err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, - &midi_ops); - if (err < 0) - return err; - - err = snd_line6_new_midi(line6midi); - if (err < 0) - return err; - - init_waitqueue_head(&line6midi->send_wait); - spin_lock_init(&line6midi->send_urb_lock); - spin_lock_init(&line6midi->midi_transmit_lock); - return 0; -} diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h deleted file mode 100644 index 78f903f..0000000 --- a/drivers/staging/line6/midi.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef MIDI_H -#define MIDI_H - -#include - -#include "midibuf.h" - -#define MIDI_BUFFER_SIZE 1024 - -struct snd_line6_midi { - /** - Pointer back to the Line6 driver data structure. - */ - struct usb_line6 *line6; - - /** - MIDI substream for receiving (or NULL if not active). - */ - struct snd_rawmidi_substream *substream_receive; - - /** - MIDI substream for transmitting (or NULL if not active). - */ - struct snd_rawmidi_substream *substream_transmit; - - /** - Number of currently active MIDI send URBs. - */ - int num_active_send_urbs; - - /** - Spin lock to protect updates of send_urb. - */ - spinlock_t send_urb_lock; - - /** - Spin lock to protect MIDI buffer handling. - */ - spinlock_t midi_transmit_lock; - - /** - Wait queue for MIDI transmission. - */ - wait_queue_head_t send_wait; - - /** - Buffer for incoming MIDI stream. - */ - struct midi_buffer midibuf_in; - - /** - Buffer for outgoing MIDI stream. - */ - struct midi_buffer midibuf_out; -}; - -extern int line6_init_midi(struct usb_line6 *line6); -extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, - int length); - -#endif diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c deleted file mode 100644 index 1ff8569..0000000 --- a/drivers/staging/line6/midibuf.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include - -#include "midibuf.h" - -static int midibuf_message_length(unsigned char code) -{ - int message_length; - - if (code < 0x80) - message_length = -1; - else if (code < 0xf0) { - static const int length[] = { 3, 3, 3, 3, 2, 2, 3 }; - - message_length = length[(code >> 4) - 8]; - } else { - /* - Note that according to the MIDI specification 0xf2 is - the "Song Position Pointer", but this is used by Line6 - to send sysex messages to the host. - */ - static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1, - 1, 1, 1, -1, 1, 1 - }; - message_length = length[code & 0x0f]; - } - - return message_length; -} - -static int midibuf_is_empty(struct midi_buffer *this) -{ - return (this->pos_read == this->pos_write) && !this->full; -} - -static int midibuf_is_full(struct midi_buffer *this) -{ - return this->full; -} - -void line6_midibuf_reset(struct midi_buffer *this) -{ - this->pos_read = this->pos_write = this->full = 0; - this->command_prev = -1; -} - -int line6_midibuf_init(struct midi_buffer *this, int size, int split) -{ - this->buf = kmalloc(size, GFP_KERNEL); - - if (this->buf == NULL) - return -ENOMEM; - - this->size = size; - this->split = split; - line6_midibuf_reset(this); - return 0; -} - -void line6_midibuf_status(struct midi_buffer *this) -{ - pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n", - this->size, this->split, this->pos_read, this->pos_write, - this->full, this->command_prev); -} - -int line6_midibuf_bytes_free(struct midi_buffer *this) -{ - return - midibuf_is_full(this) ? - 0 : - (this->pos_read - this->pos_write + this->size - 1) % this->size + - 1; -} - -int line6_midibuf_bytes_used(struct midi_buffer *this) -{ - return - midibuf_is_empty(this) ? - 0 : - (this->pos_write - this->pos_read + this->size - 1) % this->size + - 1; -} - -int line6_midibuf_write(struct midi_buffer *this, unsigned char *data, - int length) -{ - int bytes_free; - int length1, length2; - int skip_active_sense = 0; - - if (midibuf_is_full(this) || (length <= 0)) - return 0; - - /* skip trailing active sense */ - if (data[length - 1] == 0xfe) { - --length; - skip_active_sense = 1; - } - - bytes_free = line6_midibuf_bytes_free(this); - - if (length > bytes_free) - length = bytes_free; - - if (length > 0) { - length1 = this->size - this->pos_write; - - if (length < length1) { - /* no buffer wraparound */ - memcpy(this->buf + this->pos_write, data, length); - this->pos_write += length; - } else { - /* buffer wraparound */ - length2 = length - length1; - memcpy(this->buf + this->pos_write, data, length1); - memcpy(this->buf, data + length1, length2); - this->pos_write = length2; - } - - if (this->pos_write == this->pos_read) - this->full = 1; - } - - return length + skip_active_sense; -} - -int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, - int length) -{ - int bytes_used; - int length1, length2; - int command; - int midi_length; - int repeat = 0; - int i; - - /* we need to be able to store at least a 3 byte MIDI message */ - if (length < 3) - return -EINVAL; - - if (midibuf_is_empty(this)) - return 0; - - bytes_used = line6_midibuf_bytes_used(this); - - if (length > bytes_used) - length = bytes_used; - - length1 = this->size - this->pos_read; - - /* check MIDI command length */ - command = this->buf[this->pos_read]; - - if (command & 0x80) { - midi_length = midibuf_message_length(command); - this->command_prev = command; - } else { - if (this->command_prev > 0) { - int midi_length_prev = - midibuf_message_length(this->command_prev); - - if (midi_length_prev > 0) { - midi_length = midi_length_prev - 1; - repeat = 1; - } else - midi_length = -1; - } else - midi_length = -1; - } - - if (midi_length < 0) { - /* search for end of message */ - if (length < length1) { - /* no buffer wraparound */ - for (i = 1; i < length; ++i) - if (this->buf[this->pos_read + i] & 0x80) - break; - - midi_length = i; - } else { - /* buffer wraparound */ - length2 = length - length1; - - for (i = 1; i < length1; ++i) - if (this->buf[this->pos_read + i] & 0x80) - break; - - if (i < length1) - midi_length = i; - else { - for (i = 0; i < length2; ++i) - if (this->buf[i] & 0x80) - break; - - midi_length = length1 + i; - } - } - - if (midi_length == length) - midi_length = -1; /* end of message not found */ - } - - if (midi_length < 0) { - if (!this->split) - return 0; /* command is not yet complete */ - } else { - if (length < midi_length) - return 0; /* command is not yet complete */ - - length = midi_length; - } - - if (length < length1) { - /* no buffer wraparound */ - memcpy(data + repeat, this->buf + this->pos_read, length); - this->pos_read += length; - } else { - /* buffer wraparound */ - length2 = length - length1; - memcpy(data + repeat, this->buf + this->pos_read, length1); - memcpy(data + repeat + length1, this->buf, length2); - this->pos_read = length2; - } - - if (repeat) - data[0] = this->command_prev; - - this->full = 0; - return length + repeat; -} - -int line6_midibuf_ignore(struct midi_buffer *this, int length) -{ - int bytes_used = line6_midibuf_bytes_used(this); - - if (length > bytes_used) - length = bytes_used; - - this->pos_read = (this->pos_read + length) % this->size; - this->full = 0; - return length; -} - -int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask) -{ - int cmd = this->command_prev; - - if ((cmd >= 0x80) && (cmd < 0xf0)) - if ((mask & (1 << (cmd & 0x0f))) == 0) - return 1; - - return 0; -} - -void line6_midibuf_destroy(struct midi_buffer *this) -{ - kfree(this->buf); - this->buf = NULL; -} diff --git a/drivers/staging/line6/midibuf.h b/drivers/staging/line6/midibuf.h deleted file mode 100644 index 707482b..0000000 --- a/drivers/staging/line6/midibuf.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef MIDIBUF_H -#define MIDIBUF_H - -struct midi_buffer { - unsigned char *buf; - int size; - int split; - int pos_read, pos_write; - int full; - int command_prev; -}; - -extern int line6_midibuf_bytes_used(struct midi_buffer *mb); -extern int line6_midibuf_bytes_free(struct midi_buffer *mb); -extern void line6_midibuf_destroy(struct midi_buffer *mb); -extern int line6_midibuf_ignore(struct midi_buffer *mb, int length); -extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split); -extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data, - int length); -extern void line6_midibuf_reset(struct midi_buffer *mb); -extern int line6_midibuf_skip_message(struct midi_buffer *mb, - unsigned short mask); -extern void line6_midibuf_status(struct midi_buffer *mb); -extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data, - int length); - -#endif diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c deleted file mode 100644 index 6d4e5cd..0000000 --- a/drivers/staging/line6/pcm.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "playback.h" -#include "pod.h" - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - -static struct snd_line6_pcm *dev2pcm(struct device *dev) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6 *line6 = usb_get_intfdata(interface); - struct snd_line6_pcm *line6pcm = line6->line6pcm; - return line6pcm; -} - -/* - "read" request on "impulse_volume" special file. -*/ -static ssize_t impulse_volume_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume); -} - -/* - "write" request on "impulse_volume" special file. -*/ -static ssize_t impulse_volume_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_line6_pcm *line6pcm = dev2pcm(dev); - int value; - int ret; - - ret = kstrtoint(buf, 10, &value); - if (ret < 0) - return ret; - - line6pcm->impulse_volume = value; - - if (value > 0) - line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); - else - line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); - - return count; -} -static DEVICE_ATTR_RW(impulse_volume); - -/* - "read" request on "impulse_period" special file. -*/ -static ssize_t impulse_period_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period); -} - -/* - "write" request on "impulse_period" special file. -*/ -static ssize_t impulse_period_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int value; - int ret; - - ret = kstrtoint(buf, 10, &value); - if (ret < 0) - return ret; - - dev2pcm(dev)->impulse_period = value; - return count; -} -static DEVICE_ATTR_RW(impulse_period); - -#endif - -static bool test_flags(unsigned long flags0, unsigned long flags1, - unsigned long mask) -{ - return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); -} - -int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) -{ - unsigned long flags_old, flags_new, flags_final; - int err; - - do { - flags_old = ACCESS_ONCE(line6pcm->flags); - flags_new = flags_old | channels; - } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - - flags_final = flags_old; - - line6pcm->prev_fbuf = NULL; - - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { - /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->buffer_in) { - line6pcm->buffer_in = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->buffer_in) { - err = -ENOMEM; - goto pcm_acquire_error; - } - - flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; - } - } - - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { - /* - Waiting for completion of active URBs in the stop handler is - a bug, we therefore report an error if capturing is restarted - too soon. - */ - if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { - dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - return -EBUSY; - } - - line6pcm->count_in = 0; - line6pcm->prev_fsize = 0; - err = line6_submit_audio_in_all_urbs(line6pcm); - - if (err < 0) - goto pcm_acquire_error; - - flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; - } - - if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { - /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->buffer_out) { - line6pcm->buffer_out = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->buffer_out) { - err = -ENOMEM; - goto pcm_acquire_error; - } - - flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; - } - } - - if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { - /* - See comment above regarding PCM restart. - */ - if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { - dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - return -EBUSY; - } - - line6pcm->count_out = 0; - err = line6_submit_audio_out_all_urbs(line6pcm); - - if (err < 0) - goto pcm_acquire_error; - - flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; - } - - return 0; - -pcm_acquire_error: - /* - If not all requested resources/streams could be obtained, release - those which were successfully obtained (if any). - */ - line6_pcm_release(line6pcm, flags_final & channels); - return err; -} - -int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) -{ - unsigned long flags_old, flags_new; - - do { - flags_old = ACCESS_ONCE(line6pcm->flags); - flags_new = flags_old & ~channels; - } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) - line6_unlink_audio_in_urbs(line6pcm); - - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { - line6_wait_clear_audio_in_urbs(line6pcm); - line6_free_capture_buffer(line6pcm); - } - - if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) - line6_unlink_audio_out_urbs(line6pcm); - - if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { - line6_wait_clear_audio_out_urbs(line6pcm); - line6_free_playback_buffer(line6pcm); - } - - return 0; -} - -/* trigger callback */ -int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - struct snd_pcm_substream *s; - int err; - unsigned long flags; - - spin_lock_irqsave(&line6pcm->lock_trigger, flags); - clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); - - snd_pcm_group_for_each_entry(s, substream) { - switch (s->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - err = snd_line6_playback_trigger(line6pcm, cmd); - - if (err < 0) { - spin_unlock_irqrestore(&line6pcm->lock_trigger, - flags); - return err; - } - - break; - - case SNDRV_PCM_STREAM_CAPTURE: - err = snd_line6_capture_trigger(line6pcm, cmd); - - if (err < 0) { - spin_unlock_irqrestore(&line6pcm->lock_trigger, - flags); - return err; - } - - break; - - default: - dev_err(line6pcm->line6->ifcdev, - "Unknown stream direction %d\n", s->stream); - } - } - - spin_unlock_irqrestore(&line6pcm->lock_trigger, flags); - return 0; -} - -/* control info callback */ -static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 256; - return 0; -} - -/* control get callback */ -static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int i; - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - - for (i = 2; i--;) - ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; - - return 0; -} - -/* control put callback */ -static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int i, changed = 0; - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - - for (i = 2; i--;) - if (line6pcm->volume_playback[i] != - ucontrol->value.integer.value[i]) { - line6pcm->volume_playback[i] = - ucontrol->value.integer.value[i]; - changed = 1; - } - - return changed; -} - -/* control definition */ -static struct snd_kcontrol_new line6_control_playback = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_line6_control_playback_info, - .get = snd_line6_control_playback_get, - .put = snd_line6_control_playback_put -}; - -/* - Cleanup the PCM device. -*/ -static void line6_cleanup_pcm(struct snd_pcm *pcm) -{ - int i; - struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume); - device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period); -#endif - - for (i = LINE6_ISO_BUFFERS; i--;) { - if (line6pcm->urb_audio_out[i]) { - usb_kill_urb(line6pcm->urb_audio_out[i]); - usb_free_urb(line6pcm->urb_audio_out[i]); - } - if (line6pcm->urb_audio_in[i]) { - usb_kill_urb(line6pcm->urb_audio_in[i]); - usb_free_urb(line6pcm->urb_audio_in[i]); - } - } -} - -/* create a PCM device */ -static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) -{ - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(line6pcm->line6->card, - (char *)line6pcm->line6->properties->name, - 0, 1, 1, &pcm); - if (err < 0) - return err; - - pcm->private_data = line6pcm; - pcm->private_free = line6_cleanup_pcm; - line6pcm->pcm = pcm; - strcpy(pcm->name, line6pcm->line6->properties->name); - - /* set operators */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_line6_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); - - /* pre-allocation of buffers */ - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data - (GFP_KERNEL), 64 * 1024, - 128 * 1024); - - return 0; -} - -/* PCM device destructor */ -static int snd_line6_pcm_free(struct snd_device *device) -{ - return 0; -} - -/* - Stop substream if still running. -*/ -static void pcm_disconnect_substream(struct snd_pcm_substream *substream) -{ - if (substream->runtime && snd_pcm_running(substream)) { - snd_pcm_stream_lock_irq(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); - snd_pcm_stream_unlock_irq(substream); - } -} - -/* - Stop PCM stream. -*/ -void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) -{ - pcm_disconnect_substream(get_substream - (line6pcm, SNDRV_PCM_STREAM_CAPTURE)); - pcm_disconnect_substream(get_substream - (line6pcm, SNDRV_PCM_STREAM_PLAYBACK)); - line6_unlink_wait_clear_audio_out_urbs(line6pcm); - line6_unlink_wait_clear_audio_in_urbs(line6pcm); -} - -/* - Create and register the PCM device and mixer entries. - Create URBs for playback and capture. -*/ -int line6_init_pcm(struct usb_line6 *line6, - struct line6_pcm_properties *properties) -{ - static struct snd_device_ops pcm_ops = { - .dev_free = snd_line6_pcm_free, - }; - - int err; - unsigned ep_read = line6->properties->ep_audio_r; - unsigned ep_write = line6->properties->ep_audio_w; - struct snd_line6_pcm *line6pcm; - - if (!(line6->properties->capabilities & LINE6_CAP_PCM)) - return 0; /* skip PCM initialization and report success */ - - line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); - - if (line6pcm == NULL) - return -ENOMEM; - - line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; - line6pcm->volume_monitor = 255; - line6pcm->line6 = line6; - - /* Read and write buffers are sized identically, so choose minimum */ - line6pcm->max_packet_size = min( - usb_maxpacket(line6->usbdev, - usb_rcvisocpipe(line6->usbdev, ep_read), 0), - usb_maxpacket(line6->usbdev, - usb_sndisocpipe(line6->usbdev, ep_write), 1)); - - line6pcm->properties = properties; - line6->line6pcm = line6pcm; - - /* PCM device: */ - err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops); - if (err < 0) - return err; - - err = snd_line6_new_pcm(line6pcm); - if (err < 0) - return err; - - spin_lock_init(&line6pcm->lock_audio_out); - spin_lock_init(&line6pcm->lock_audio_in); - spin_lock_init(&line6pcm->lock_trigger); - - err = line6_create_audio_out_urbs(line6pcm); - if (err < 0) - return err; - - err = line6_create_audio_in_urbs(line6pcm); - if (err < 0) - return err; - - /* mixer: */ - err = - snd_ctl_add(line6->card, - snd_ctl_new1(&line6_control_playback, line6pcm)); - if (err < 0) - return err; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - /* impulse response test: */ - err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume); - if (err < 0) - return err; - - err = device_create_file(line6->ifcdev, &dev_attr_impulse_period); - if (err < 0) - return err; - - line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; -#endif - - return 0; -} - -/* prepare pcm callback */ -int snd_line6_prepare(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) - line6_unlink_wait_clear_audio_out_urbs(line6pcm); - - break; - - case SNDRV_PCM_STREAM_CAPTURE: - if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) - line6_unlink_wait_clear_audio_in_urbs(line6pcm); - - break; - - default: - MISSING_CASE; - } - - if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { - line6pcm->count_out = 0; - line6pcm->pos_out = 0; - line6pcm->pos_out_done = 0; - line6pcm->bytes_out = 0; - line6pcm->count_in = 0; - line6pcm->pos_in_done = 0; - line6pcm->bytes_in = 0; - } - - return 0; -} diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h deleted file mode 100644 index 7315e81..0000000 --- a/drivers/staging/line6/pcm.h +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -/* - PCM interface to POD series devices. -*/ - -#ifndef PCM_H -#define PCM_H - -#include - -#include "driver.h" -#include "usbdefs.h" - -/* number of URBs */ -#define LINE6_ISO_BUFFERS 2 - -/* - number of USB frames per URB - The Line6 Windows driver always transmits two frames per packet, but - the Linux driver performs significantly better (i.e., lower latency) - with only one frame per packet. -*/ -#define LINE6_ISO_PACKETS 1 - -/* in a "full speed" device (such as the PODxt Pro) this means 1ms */ -#define LINE6_ISO_INTERVAL 1 - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE -#define LINE6_IMPULSE_DEFAULT_PERIOD 100 -#endif - -/* - Get substream from Line6 PCM data structure -*/ -#define get_substream(line6pcm, stream) \ - (line6pcm->pcm->streams[stream].substream) - -/* - PCM mode bits. - - There are several features of the Line6 USB driver which require PCM - data to be exchanged with the device: - *) PCM playback and capture via ALSA - *) software monitoring (for devices without hardware monitoring) - *) optional impulse response measurement - However, from the device's point of view, there is just a single - capture and playback stream, which must be shared between these - subsystems. It is therefore necessary to maintain the state of the - subsystems with respect to PCM usage. We define several constants of - the form LINE6_BIT_PCM___ with the - following meanings: - *) is one of - -) ALSA: PCM playback and capture via ALSA - -) MONITOR: software monitoring - -) IMPULSE: optional impulse response measurement - *) is one of - -) PLAYBACK: audio output (from host to device) - -) CAPTURE: audio input (from device to host) - *) is one of - -) BUFFER: buffer required by PCM data stream - -) STREAM: actual PCM data stream - - The subsystems call line6_pcm_acquire() to acquire the (shared) - resources needed for a particular operation (e.g., allocate the buffer - for ALSA playback or start the capture stream for software monitoring). - When a resource is no longer needed, it is released by calling - line6_pcm_release(). Buffer allocation and stream startup are handled - separately to allow the ALSA kernel driver to perform them at - appropriate places (since the callback which starts a PCM stream is not - allowed to sleep). -*/ -enum { - /* individual bit indices: */ - LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, - LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER, - LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, - LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, - LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, - LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, - LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, -#endif - LINE6_INDEX_PAUSE_PLAYBACK, - LINE6_INDEX_PREPARED, - -#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x - - /* individual bit masks: */ - LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), - LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), - LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER), - LINE6_BIT(PCM_ALSA_CAPTURE_STREAM), - LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER), - LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), - LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), - LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), - LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), - LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), - LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), -#endif - LINE6_BIT(PAUSE_PLAYBACK), - LINE6_BIT(PREPARED), - - /* combined bit masks (by operation): */ - LINE6_BITS_PCM_ALSA_BUFFER = - LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER, - - LINE6_BITS_PCM_ALSA_STREAM = - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM, - - LINE6_BITS_PCM_MONITOR = - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BITS_PCM_IMPULSE = - LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | - LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | - LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | - LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, -#endif - - /* combined bit masks (by direction): */ - LINE6_BITS_PLAYBACK_BUFFER = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | -#endif - LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, - - LINE6_BITS_PLAYBACK_STREAM = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | -#endif - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, - - LINE6_BITS_CAPTURE_BUFFER = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | -#endif - LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, - - LINE6_BITS_CAPTURE_STREAM = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | -#endif - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | - LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, - - LINE6_BITS_STREAM = - LINE6_BITS_PLAYBACK_STREAM | - LINE6_BITS_CAPTURE_STREAM -}; - -struct line6_pcm_properties { - struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw; - struct snd_pcm_hw_constraint_ratdens snd_line6_rates; - int bytes_per_frame; -}; - -struct snd_line6_pcm { - /** - Pointer back to the Line6 driver data structure. - */ - struct usb_line6 *line6; - - /** - Properties. - */ - struct line6_pcm_properties *properties; - - /** - ALSA pcm stream - */ - struct snd_pcm *pcm; - - /** - URBs for audio playback. - */ - struct urb *urb_audio_out[LINE6_ISO_BUFFERS]; - - /** - URBs for audio capture. - */ - struct urb *urb_audio_in[LINE6_ISO_BUFFERS]; - - /** - Temporary buffer for playback. - Since the packet size is not known in advance, this buffer is - large enough to store maximum size packets. - */ - unsigned char *buffer_out; - - /** - Temporary buffer for capture. - Since the packet size is not known in advance, this buffer is - large enough to store maximum size packets. - */ - unsigned char *buffer_in; - - /** - Previously captured frame (for software monitoring). - */ - unsigned char *prev_fbuf; - - /** - Size of previously captured frame (for software monitoring). - */ - int prev_fsize; - - /** - Free frame position in the playback buffer. - */ - snd_pcm_uframes_t pos_out; - - /** - Count processed bytes for playback. - This is modulo period size (to determine when a period is - finished). - */ - unsigned bytes_out; - - /** - Counter to create desired playback sample rate. - */ - unsigned count_out; - - /** - Playback period size in bytes - */ - unsigned period_out; - - /** - Processed frame position in the playback buffer. - The contents of the output ring buffer have been consumed by - the USB subsystem (i.e., sent to the USB device) up to this - position. - */ - snd_pcm_uframes_t pos_out_done; - - /** - Count processed bytes for capture. - This is modulo period size (to determine when a period is - finished). - */ - unsigned bytes_in; - - /** - Counter to create desired capture sample rate. - */ - unsigned count_in; - - /** - Capture period size in bytes - */ - unsigned period_in; - - /** - Processed frame position in the capture buffer. - The contents of the output ring buffer have been consumed by - the USB subsystem (i.e., sent to the USB device) up to this - position. - */ - snd_pcm_uframes_t pos_in_done; - - /** - Bit mask of active playback URBs. - */ - unsigned long active_urb_out; - - /** - Maximum size of USB packet. - */ - int max_packet_size; - - /** - Bit mask of active capture URBs. - */ - unsigned long active_urb_in; - - /** - Bit mask of playback URBs currently being unlinked. - */ - unsigned long unlink_urb_out; - - /** - Bit mask of capture URBs currently being unlinked. - */ - unsigned long unlink_urb_in; - - /** - Spin lock to protect updates of the playback buffer positions (not - contents!) - */ - spinlock_t lock_audio_out; - - /** - Spin lock to protect updates of the capture buffer positions (not - contents!) - */ - spinlock_t lock_audio_in; - - /** - Spin lock to protect trigger. - */ - spinlock_t lock_trigger; - - /** - PCM playback volume (left and right). - */ - int volume_playback[2]; - - /** - PCM monitor volume. - */ - int volume_monitor; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - /** - Volume of impulse response test signal (if zero, test is disabled). - */ - int impulse_volume; - - /** - Period of impulse response test signal. - */ - int impulse_period; - - /** - Counter for impulse response test signal. - */ - int impulse_count; -#endif - - /** - Several status bits (see LINE6_BIT_*). - */ - unsigned long flags; - - int last_frame_in, last_frame_out; -}; - -extern int line6_init_pcm(struct usb_line6 *line6, - struct line6_pcm_properties *properties); -extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); -extern int snd_line6_prepare(struct snd_pcm_substream *substream); -extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); -extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels); -extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels); - -#endif diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c deleted file mode 100644 index da2e3b8..0000000 --- a/drivers/staging/line6/playback.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "pcm.h" -#include "pod.h" -#include "playback.h" - -/* - Software stereo volume control. -*/ -static void change_volume(struct urb *urb_out, int volume[], - int bytes_per_frame) -{ - int chn = 0; - - if (volume[0] == 256 && volume[1] == 256) - return; /* maximum volume - no change */ - - if (bytes_per_frame == 4) { - short *p, *buf_end; - - p = (short *)urb_out->transfer_buffer; - buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); - - for (; p < buf_end; ++p) { - *p = (*p * volume[chn & 1]) >> 8; - ++chn; - } - } else if (bytes_per_frame == 6) { - unsigned char *p, *buf_end; - - p = (unsigned char *)urb_out->transfer_buffer; - buf_end = p + urb_out->transfer_buffer_length; - - for (; p < buf_end; p += 3) { - int val; - - val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); - val = (val * volume[chn & 1]) >> 8; - p[0] = val; - p[1] = val >> 8; - p[2] = val >> 16; - ++chn; - } - } -} - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - -/* - Create signal for impulse response test. -*/ -static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, - struct urb *urb_out, int bytes_per_frame) -{ - int frames = urb_out->transfer_buffer_length / bytes_per_frame; - - if (bytes_per_frame == 4) { - int i; - short *pi = (short *)line6pcm->prev_fbuf; - short *po = (short *)urb_out->transfer_buffer; - - for (i = 0; i < frames; ++i) { - po[0] = pi[0]; - po[1] = 0; - pi += 2; - po += 2; - } - } else if (bytes_per_frame == 6) { - int i, j; - unsigned char *pi = line6pcm->prev_fbuf; - unsigned char *po = urb_out->transfer_buffer; - - for (i = 0; i < frames; ++i) { - for (j = 0; j < bytes_per_frame / 2; ++j) - po[j] = pi[j]; - - for (; j < bytes_per_frame; ++j) - po[j] = 0; - - pi += bytes_per_frame; - po += bytes_per_frame; - } - } - if (--line6pcm->impulse_count <= 0) { - ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame - - 1] = - line6pcm->impulse_volume; - line6pcm->impulse_count = line6pcm->impulse_period; - } -} - -#endif - -/* - Add signal to buffer for software monitoring. -*/ -static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, - int volume, int bytes_per_frame) -{ - if (volume == 0) - return; /* zero volume - no change */ - - if (bytes_per_frame == 4) { - short *pi, *po, *buf_end; - - pi = (short *)signal; - po = (short *)urb_out->transfer_buffer; - buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); - - for (; po < buf_end; ++pi, ++po) - *po += (*pi * volume) >> 8; - } - - /* - We don't need to handle devices with 6 bytes per frame here - since they all support hardware monitoring. - */ -} - -/* - Find a free URB, prepare audio data, and submit URB. -*/ -static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) -{ - int index; - unsigned long flags; - int i, urb_size, urb_frames; - int ret; - const int bytes_per_frame = line6pcm->properties->bytes_per_frame; - const int frame_increment = - line6pcm->properties->snd_line6_rates.rats[0].num_min; - const int frame_factor = - line6pcm->properties->snd_line6_rates.rats[0].den * - (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); - struct urb *urb_out; - - spin_lock_irqsave(&line6pcm->lock_audio_out, flags); - index = - find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS); - - if (index < 0 || index >= LINE6_ISO_BUFFERS) { - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); - dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); - return -EINVAL; - } - - urb_out = line6pcm->urb_audio_out[index]; - urb_size = 0; - - for (i = 0; i < LINE6_ISO_PACKETS; ++i) { - /* compute frame size for given sampling rate */ - int fsize = 0; - struct usb_iso_packet_descriptor *fout = - &urb_out->iso_frame_desc[i]; - - if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) - fsize = line6pcm->prev_fsize; - - if (fsize == 0) { - int n; - - line6pcm->count_out += frame_increment; - n = line6pcm->count_out / frame_factor; - line6pcm->count_out -= n * frame_factor; - fsize = n * bytes_per_frame; - } - - fout->offset = urb_size; - fout->length = fsize; - urb_size += fsize; - } - - if (urb_size == 0) { - /* can't determine URB size */ - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); - dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); - return -EINVAL; - } - - urb_frames = urb_size / bytes_per_frame; - urb_out->transfer_buffer = - line6pcm->buffer_out + - index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; - urb_out->transfer_buffer_length = urb_size; - urb_out->context = line6pcm; - - if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) && - !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) { - struct snd_pcm_runtime *runtime = - get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; - - if (line6pcm->pos_out + urb_frames > runtime->buffer_size) { - /* - The transferred area goes over buffer boundary, - copy the data to the temp buffer. - */ - int len; - - len = runtime->buffer_size - line6pcm->pos_out; - - if (len > 0) { - memcpy(urb_out->transfer_buffer, - runtime->dma_area + - line6pcm->pos_out * bytes_per_frame, - len * bytes_per_frame); - memcpy(urb_out->transfer_buffer + - len * bytes_per_frame, runtime->dma_area, - (urb_frames - len) * bytes_per_frame); - } else - dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", - len); - } else { - memcpy(urb_out->transfer_buffer, - runtime->dma_area + - line6pcm->pos_out * bytes_per_frame, - urb_out->transfer_buffer_length); - } - - line6pcm->pos_out += urb_frames; - if (line6pcm->pos_out >= runtime->buffer_size) - line6pcm->pos_out -= runtime->buffer_size; - } else { - memset(urb_out->transfer_buffer, 0, - urb_out->transfer_buffer_length); - } - - change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); - - if (line6pcm->prev_fbuf != NULL) { -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { - create_impulse_test_signal(line6pcm, urb_out, - bytes_per_frame); - if (line6pcm->flags & - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) { - line6_capture_copy(line6pcm, - urb_out->transfer_buffer, - urb_out-> - transfer_buffer_length); - line6_capture_check_period(line6pcm, - urb_out->transfer_buffer_length); - } - } else { -#endif - if (! - (line6pcm->line6-> - properties->capabilities & LINE6_CAP_HWMON) - && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) - && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)) - add_monitor_signal(urb_out, line6pcm->prev_fbuf, - line6pcm->volume_monitor, - bytes_per_frame); -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - } -#endif - } - - ret = usb_submit_urb(urb_out, GFP_ATOMIC); - - if (ret == 0) - set_bit(index, &line6pcm->active_urb_out); - else - dev_err(line6pcm->line6->ifcdev, - "URB out #%d submission failed (%d)\n", index, ret); - - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); - return 0; -} - -/* - Submit all currently available playback URBs. -*/ -int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) -{ - int ret, i; - - for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { - ret = submit_audio_out_urb(line6pcm); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - Unlink all currently active playback URBs. -*/ -void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - unsigned int i; - - for (i = LINE6_ISO_BUFFERS; i--;) { - if (test_bit(i, &line6pcm->active_urb_out)) { - if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { - struct urb *u = line6pcm->urb_audio_out[i]; - - usb_unlink_urb(u); - } - } - } -} - -/* - Wait until unlinking of all currently active playback URBs has been - finished. -*/ -void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - int timeout = HZ; - unsigned int i; - int alive; - - do { - alive = 0; - for (i = LINE6_ISO_BUFFERS; i--;) { - if (test_bit(i, &line6pcm->active_urb_out)) - alive++; - } - if (!alive) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } while (--timeout > 0); - if (alive) - snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); -} - -/* - Unlink all currently active playback URBs, and wait for finishing. -*/ -void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - line6_unlink_audio_out_urbs(line6pcm); - line6_wait_clear_audio_out_urbs(line6pcm); -} - -void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) -{ - kfree(line6pcm->buffer_out); - line6pcm->buffer_out = NULL; -} - -/* - Callback for completed playback URB. -*/ -static void audio_out_callback(struct urb *urb) -{ - int i, index, length = 0, shutdown = 0; - unsigned long flags; - struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; - struct snd_pcm_substream *substream = - get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); - -#if USE_CLEAR_BUFFER_WORKAROUND - memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); -#endif - - line6pcm->last_frame_out = urb->start_frame; - - /* find index of URB */ - for (index = LINE6_ISO_BUFFERS; index--;) - if (urb == line6pcm->urb_audio_out[index]) - break; - - if (index < 0) - return; /* URB has been unlinked asynchronously */ - - for (i = LINE6_ISO_PACKETS; i--;) - length += urb->iso_frame_desc[i].length; - - spin_lock_irqsave(&line6pcm->lock_audio_out, flags); - - if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { - struct snd_pcm_runtime *runtime = substream->runtime; - - line6pcm->pos_out_done += - length / line6pcm->properties->bytes_per_frame; - - if (line6pcm->pos_out_done >= runtime->buffer_size) - line6pcm->pos_out_done -= runtime->buffer_size; - } - - clear_bit(index, &line6pcm->active_urb_out); - - for (i = LINE6_ISO_PACKETS; i--;) - if (urb->iso_frame_desc[i].status == -EXDEV) { - shutdown = 1; - break; - } - - if (test_and_clear_bit(index, &line6pcm->unlink_urb_out)) - shutdown = 1; - - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); - - if (!shutdown) { - submit_audio_out_urb(line6pcm); - - if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, - &line6pcm->flags)) { - line6pcm->bytes_out += length; - if (line6pcm->bytes_out >= line6pcm->period_out) { - line6pcm->bytes_out %= line6pcm->period_out; - snd_pcm_period_elapsed(substream); - } - } - } -} - -/* open playback callback */ -static int snd_line6_playback_open(struct snd_pcm_substream *substream) -{ - int err; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - (&line6pcm-> - properties->snd_line6_rates)); - if (err < 0) - return err; - - runtime->hw = line6pcm->properties->snd_line6_playback_hw; - return 0; -} - -/* close playback callback */ -static int snd_line6_playback_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* hw_params playback callback */ -static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - int ret; - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - /* -- Florian Demski [FD] */ - /* don't ask me why, but this fixes the bug on my machine */ - if (line6pcm == NULL) { - if (substream->pcm == NULL) - return -ENOMEM; - if (substream->pcm->private_data == NULL) - return -ENOMEM; - substream->private_data = substream->pcm->private_data; - line6pcm = snd_pcm_substream_chip(substream); - } - /* -- [FD] end */ - - ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); - - if (ret < 0) - return ret; - - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) { - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); - return ret; - } - - line6pcm->period_out = params_period_bytes(hw_params); - return 0; -} - -/* hw_free playback callback */ -static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); - return snd_pcm_lib_free_pages(substream); -} - -/* trigger playback callback */ -int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) -{ - int err; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: -#ifdef CONFIG_PM - case SNDRV_PCM_TRIGGER_RESUME: -#endif - err = line6_pcm_acquire(line6pcm, - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); - - if (err < 0) - return err; - - break; - - case SNDRV_PCM_TRIGGER_STOP: -#ifdef CONFIG_PM - case SNDRV_PCM_TRIGGER_SUSPEND: -#endif - err = line6_pcm_release(line6pcm, - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); - - if (err < 0) - return err; - - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* playback pointer callback */ -static snd_pcm_uframes_t -snd_line6_playback_pointer(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - return line6pcm->pos_out_done; -} - -/* playback operators */ -struct snd_pcm_ops snd_line6_playback_ops = { - .open = snd_line6_playback_open, - .close = snd_line6_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_line6_playback_hw_params, - .hw_free = snd_line6_playback_hw_free, - .prepare = snd_line6_prepare, - .trigger = snd_line6_trigger, - .pointer = snd_line6_playback_pointer, -}; - -int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - struct usb_line6 *line6 = line6pcm->line6; - int i; - - /* create audio URBs and fill in constant values: */ - for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { - struct urb *urb; - - /* URB for audio out: */ - urb = line6pcm->urb_audio_out[i] = - usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); - - if (urb == NULL) { - dev_err(line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - urb->dev = line6->usbdev; - urb->pipe = - usb_sndisocpipe(line6->usbdev, - line6->properties->ep_audio_w & - USB_ENDPOINT_NUMBER_MASK); - urb->transfer_flags = URB_ISO_ASAP; - urb->start_frame = -1; - urb->number_of_packets = LINE6_ISO_PACKETS; - urb->interval = LINE6_ISO_INTERVAL; - urb->error_count = 0; - urb->complete = audio_out_callback; - } - - return 0; -} diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h deleted file mode 100644 index 743bd6f..0000000 --- a/drivers/staging/line6/playback.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef PLAYBACK_H -#define PLAYBACK_H - -#include - -#include "driver.h" - -/* - * When the TonePort is used with jack in full duplex mode and the outputs are - * not connected, the software monitor produces an ugly noise since everything - * written to the output buffer (i.e., the input signal) will be repeated in - * the next period (sounds like a delay effect). As a workaround, the output - * buffer is cleared after the data have been read, but there must be a better - * solution. Until one is found, this workaround can be used to fix the - * problem. - */ -#define USE_CLEAR_BUFFER_WORKAROUND 1 - -extern struct snd_pcm_ops snd_line6_playback_ops; - -extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); -extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm); -extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); -extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm); -extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm - *line6pcm); -extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm); -extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); - -#endif diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c deleted file mode 100644 index 85a4363..0000000 --- a/drivers/staging/line6/pod.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "playback.h" -#include "pod.h" - -#define POD_SYSEX_CODE 3 -#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ - -/* *INDENT-OFF* */ - -enum { - POD_SYSEX_SAVE = 0x24, - POD_SYSEX_SYSTEM = 0x56, - POD_SYSEX_SYSTEMREQ = 0x57, - /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ - POD_SYSEX_STORE = 0x71, - POD_SYSEX_FINISH = 0x72, - POD_SYSEX_DUMPMEM = 0x73, - POD_SYSEX_DUMP = 0x74, - POD_SYSEX_DUMPREQ = 0x75 - - /* dumps entire internal memory of PODxt Pro */ - /* POD_SYSEX_DUMPMEM2 = 0x76 */ -}; - -enum { - POD_MONITOR_LEVEL = 0x04, - POD_SYSTEM_INVALID = 0x10000 -}; - -/* *INDENT-ON* */ - -enum { - POD_DUMP_MEMORY = 2 -}; - -enum { - POD_BUSY_READ, - POD_BUSY_WRITE, - POD_CHANNEL_DIRTY, - POD_SAVE_PRESSED, - POD_BUSY_MIDISEND -}; - -static struct snd_ratden pod_ratden = { - .num_min = 78125, - .num_max = 78125, - .num_step = 1, - .den = 2 -}; - -static struct line6_pcm_properties pod_pcm_properties = { - .snd_line6_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S24_3LE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = 39062, - .rate_max = 39063, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S24_3LE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = 39062, - .rate_max = 39063, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_rates = { - .nrats = 1, - .rats = &pod_ratden}, - .bytes_per_frame = POD_BYTES_PER_FRAME -}; - -static const char pod_version_header[] = { - 0xf2, 0x7e, 0x7f, 0x06, 0x02 -}; - -/* forward declarations: */ -static void pod_startup2(unsigned long data); -static void pod_startup3(struct usb_line6_pod *pod); - -static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, - int size) -{ - return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, - size); -} - -/* - Process a completely received message. -*/ -static void line6_pod_process_message(struct usb_line6 *line6) -{ - struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; - const unsigned char *buf = pod->line6.buffer_message; - - if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { - pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; - pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | - (int) buf[10]; - pod_startup3(pod); - return; - } - - /* Only look for sysex messages from this device */ - if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && - buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { - return; - } - if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) - return; - - if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) { - short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | - ((int)buf[9] << 4) | (int)buf[10]; - pod->monitor_level = value; - } -} - -/* - Send system parameter (from integer). -*/ -static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, - int code) -{ - char *sysex; - static const int size = 5; - - sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); - if (!sysex) - return -ENOMEM; - sysex[SYSEX_DATA_OFS] = code; - sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; - sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; - sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; - sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; - line6_send_sysex_message(&pod->line6, sysex, size); - kfree(sysex); - return 0; -} - -/* - "read" request on "serial_number" special file. -*/ -static ssize_t serial_number_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_pod *pod = usb_get_intfdata(interface); - - return sprintf(buf, "%d\n", pod->serial_number); -} - -/* - "read" request on "firmware_version" special file. -*/ -static ssize_t firmware_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_pod *pod = usb_get_intfdata(interface); - - return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, - pod->firmware_version % 100); -} - -/* - "read" request on "device_id" special file. -*/ -static ssize_t device_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_pod *pod = usb_get_intfdata(interface); - - return sprintf(buf, "%d\n", pod->device_id); -} - -/* - POD startup procedure. - This is a sequence of functions with special requirements (e.g., must - not run immediately after initialization, must not run in interrupt - context). After the last one has finished, the device is ready to use. -*/ - -static void pod_startup1(struct usb_line6_pod *pod) -{ - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); - - /* delay startup procedure: */ - line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, - (unsigned long)pod); -} - -static void pod_startup2(unsigned long data) -{ - struct usb_line6_pod *pod = (struct usb_line6_pod *)data; - struct usb_line6 *line6 = &pod->line6; - - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); - - /* request firmware version: */ - line6_version_request_async(line6); -} - -static void pod_startup3(struct usb_line6_pod *pod) -{ - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); - - /* schedule work for global work queue: */ - schedule_work(&pod->startup_work); -} - -static void pod_startup4(struct work_struct *work) -{ - struct usb_line6_pod *pod = - container_of(work, struct usb_line6_pod, startup_work); - struct usb_line6 *line6 = &pod->line6; - - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); - - /* serial number: */ - line6_read_serial_number(&pod->line6, &pod->serial_number); - - /* ALSA audio interface: */ - line6_register_audio(line6); -} - -/* POD special files: */ -static DEVICE_ATTR_RO(device_id); -static DEVICE_ATTR_RO(firmware_version); -static DEVICE_ATTR_RO(serial_number); - -/* control info callback */ -static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 65535; - return 0; -} - -/* control get callback */ -static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; - - ucontrol->value.integer.value[0] = pod->monitor_level; - return 0; -} - -/* control put callback */ -static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; - - if (ucontrol->value.integer.value[0] == pod->monitor_level) - return 0; - - pod->monitor_level = ucontrol->value.integer.value[0]; - pod_set_system_param_int(pod, ucontrol->value.integer.value[0], - POD_MONITOR_LEVEL); - return 1; -} - -/* control definition */ -static struct snd_kcontrol_new pod_control_monitor = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Monitor Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_pod_control_monitor_info, - .get = snd_pod_control_monitor_get, - .put = snd_pod_control_monitor_put -}; - -/* - POD destructor. -*/ -static void pod_destruct(struct usb_interface *interface) -{ - struct usb_line6_pod *pod = usb_get_intfdata(interface); - - if (pod == NULL) - return; - line6_cleanup_audio(&pod->line6); - - del_timer(&pod->startup_timer); - cancel_work_sync(&pod->startup_work); -} - -/* - POD device disconnected. -*/ -static void line6_pod_disconnect(struct usb_interface *interface) -{ - struct usb_line6_pod *pod; - - if (interface == NULL) - return; - pod = usb_get_intfdata(interface); - - if (pod != NULL) { - struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; - struct device *dev = &interface->dev; - - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - - if (dev != NULL) { - /* remove sysfs entries: */ - device_remove_file(dev, &dev_attr_device_id); - device_remove_file(dev, &dev_attr_firmware_version); - device_remove_file(dev, &dev_attr_serial_number); - } - } - - pod_destruct(interface); -} - -/* - Create sysfs entries. -*/ -static int pod_create_files2(struct device *dev) -{ - int err; - - CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); - CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); - CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); - return 0; -} - -/* - Try to init POD device. -*/ -static int pod_try_init(struct usb_interface *interface, - struct usb_line6 *line6) -{ - int err; - struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; - - line6->process_message = line6_pod_process_message; - line6->disconnect = line6_pod_disconnect; - - init_timer(&pod->startup_timer); - INIT_WORK(&pod->startup_work, pod_startup4); - - if ((interface == NULL) || (pod == NULL)) - return -ENODEV; - - /* create sysfs entries: */ - err = pod_create_files2(&interface->dev); - if (err < 0) - return err; - - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - - /* initialize MIDI subsystem: */ - err = line6_init_midi(line6); - if (err < 0) - return err; - - /* initialize PCM subsystem: */ - err = line6_init_pcm(line6, &pod_pcm_properties); - if (err < 0) - return err; - - /* register monitor control: */ - err = snd_ctl_add(line6->card, - snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); - if (err < 0) - return err; - - /* - When the sound card is registered at this point, the PODxt Live - displays "Invalid Code Error 07", so we do it later in the event - handler. - */ - - if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { - pod->monitor_level = POD_SYSTEM_INVALID; - - /* initiate startup procedure: */ - pod_startup1(pod); - } - - return 0; -} - -/* - Init POD device (and clean up in case of failure). -*/ -int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) -{ - int err = pod_try_init(interface, line6); - - if (err < 0) - pod_destruct(interface); - - return err; -} diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h deleted file mode 100644 index 87a8f0f..0000000 --- a/drivers/staging/line6/pod.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef POD_H -#define POD_H - -#include -#include -#include - -#include - -#include "driver.h" - -/* - Locate name in binary program dump -*/ -#define POD_NAME_OFFSET 0 -#define POD_NAME_LENGTH 16 - -/* - Other constants -*/ -#define POD_CONTROL_SIZE 0x80 -#define POD_BUFSIZE_DUMPREQ 7 -#define POD_STARTUP_DELAY 1000 - -/* - Stages of POD startup procedure -*/ -enum { - POD_STARTUP_INIT = 1, - POD_STARTUP_VERSIONREQ, - POD_STARTUP_WORKQUEUE, - POD_STARTUP_SETUP, - POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 -}; - -struct usb_line6_pod { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Instrument monitor level. - */ - int monitor_level; - - /** - Timer for device initializaton. - */ - struct timer_list startup_timer; - - /** - Work handler for device initializaton. - */ - struct work_struct startup_work; - - /** - Current progress in startup procedure. - */ - int startup_progress; - - /** - Serial number of device. - */ - int serial_number; - - /** - Firmware version (x 100). - */ - int firmware_version; - - /** - Device ID. - */ - int device_id; -}; - -extern int line6_pod_init(struct usb_interface *interface, - struct usb_line6 *line6); - -#endif diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c deleted file mode 100644 index 27c5402..0000000 --- a/drivers/staging/line6/podhd.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Line6 Pod HD - * - * Copyright (C) 2011 Stefan Hajnoczi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include - -#include "audio.h" -#include "driver.h" -#include "pcm.h" -#include "podhd.h" - -#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ - -static struct snd_ratden podhd_ratden = { - .num_min = 48000, - .num_max = 48000, - .num_step = 1, - .den = 1, -}; - -static struct line6_pcm_properties podhd_pcm_properties = { - .snd_line6_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S24_3LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S24_3LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_rates = { - .nrats = 1, - .rats = &podhd_ratden}, - .bytes_per_frame = PODHD_BYTES_PER_FRAME -}; - -/* - POD HD destructor. -*/ -static void podhd_destruct(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd = usb_get_intfdata(interface); - - if (podhd == NULL) - return; - line6_cleanup_audio(&podhd->line6); -} - -/* - POD HD device disconnected. -*/ -static void line6_podhd_disconnect(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd; - - if (interface == NULL) - return; - podhd = usb_get_intfdata(interface); - - if (podhd != NULL) { - struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; - - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - } - - podhd_destruct(interface); -} - -/* - Try to init POD HD device. -*/ -static int podhd_try_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd) -{ - int err; - struct usb_line6 *line6 = &podhd->line6; - - if ((interface == NULL) || (podhd == NULL)) - return -ENODEV; - - line6->disconnect = line6_podhd_disconnect; - - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - - /* initialize MIDI subsystem: */ - err = line6_init_midi(line6); - if (err < 0) - return err; - - /* initialize PCM subsystem: */ - err = line6_init_pcm(line6, &podhd_pcm_properties); - if (err < 0) - return err; - - /* register USB audio system: */ - err = line6_register_audio(line6); - return err; -} - -/* - Init POD HD device (and clean up in case of failure). -*/ -int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) -{ - struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; - int err = podhd_try_init(interface, podhd); - - if (err < 0) - podhd_destruct(interface); - - return err; -} diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h deleted file mode 100644 index a14f711..0000000 --- a/drivers/staging/line6/podhd.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Line6 Pod HD - * - * Copyright (C) 2011 Stefan Hajnoczi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef PODHD_H -#define PODHD_H - -#include - -#include "driver.h" - -struct usb_line6_podhd { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; -}; - -extern int line6_podhd_init(struct usb_interface *interface, - struct usb_line6 *line6); - -#endif /* PODHD_H */ diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h deleted file mode 100644 index b4eee2b..0000000 --- a/drivers/staging/line6/revision.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef DRIVER_REVISION -/* current subversion revision */ -#define DRIVER_REVISION " (904)" -#endif diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c deleted file mode 100644 index aae78d8..0000000 --- a/drivers/staging/line6/toneport.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * Emil Myhrman (emil.myhrman@gmail.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "playback.h" -#include "toneport.h" - -static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); - -#define TONEPORT_PCM_DELAY 1 - -static struct snd_ratden toneport_ratden = { - .num_min = 44100, - .num_max = 44100, - .num_step = 1, - .den = 1 -}; - -static struct line6_pcm_properties toneport_pcm_properties = { - .snd_line6_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = 44100, - .rate_max = 44100, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = 44100, - .rate_max = 44100, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_rates = { - .nrats = 1, - .rats = &toneport_ratden}, - .bytes_per_frame = 4 -}; - -/* - For the led on Guitarport. - Brightness goes from 0x00 to 0x26. Set a value above this to have led - blink. - (void cmd_0x02(byte red, byte green) -*/ -static int led_red = 0x00; -static int led_green = 0x26; - -static const struct { - const char *name; - int code; -} toneport_source_info[] = { - {"Microphone", 0x0a01}, - {"Line", 0x0801}, - {"Instrument", 0x0b01}, - {"Inst & Mic", 0x0901} -}; - -static bool toneport_has_led(enum line6_device_type type) -{ - return - (type == LINE6_GUITARPORT) || - (type == LINE6_TONEPORT_GX); - /* add your device here if you are missing support for the LEDs */ -} - -static void toneport_update_led(struct device *dev) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_toneport *tp = usb_get_intfdata(interface); - struct usb_line6 *line6; - - if (!tp) - return; - - line6 = &tp->line6; - if (line6) - toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002, - led_green); -} - -static ssize_t toneport_set_led_red(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int retval; - - retval = kstrtoint(buf, 10, &led_red); - if (retval) - return retval; - - toneport_update_led(dev); - return count; -} - -static ssize_t toneport_set_led_green(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int retval; - - retval = kstrtoint(buf, 10, &led_green); - if (retval) - return retval; - - toneport_update_led(dev); - return count; -} - -static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, - toneport_set_led_red); -static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, - toneport_set_led_green); - -static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) -{ - int ret; - - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(&usbdev->dev, "send failed (error %d)\n", ret); - return ret; - } - - return 0; -} - -/* monitor info callback */ -static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 256; - return 0; -} - -/* monitor get callback */ -static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = line6pcm->volume_monitor; - return 0; -} - -/* monitor put callback */ -static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - - if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) - return 0; - - line6pcm->volume_monitor = ucontrol->value.integer.value[0]; - - if (line6pcm->volume_monitor > 0) - line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); - else - line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); - - return 1; -} - -/* source info callback */ -static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - const int size = ARRAY_SIZE(toneport_source_info); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = size; - - if (uinfo->value.enumerated.item >= size) - uinfo->value.enumerated.item = size - 1; - - strcpy(uinfo->value.enumerated.name, - toneport_source_info[uinfo->value.enumerated.item].name); - - return 0; -} - -/* source get callback */ -static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - struct usb_line6_toneport *toneport = - (struct usb_line6_toneport *)line6pcm->line6; - ucontrol->value.enumerated.item[0] = toneport->source; - return 0; -} - -/* source put callback */ -static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - struct usb_line6_toneport *toneport = - (struct usb_line6_toneport *)line6pcm->line6; - unsigned int source; - - source = ucontrol->value.enumerated.item[0]; - if (source >= ARRAY_SIZE(toneport_source_info)) - return -EINVAL; - if (source == toneport->source) - return 0; - - toneport->source = source; - toneport_send_cmd(toneport->line6.usbdev, - toneport_source_info[source].code, 0x0000); - return 1; -} - -static void toneport_start_pcm(unsigned long arg) -{ - struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; - struct usb_line6 *line6 = &toneport->line6; - - line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); -} - -/* control definition */ -static struct snd_kcontrol_new toneport_control_monitor = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Monitor Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_toneport_monitor_info, - .get = snd_toneport_monitor_get, - .put = snd_toneport_monitor_put -}; - -/* source selector definition */ -static struct snd_kcontrol_new toneport_control_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Capture Source", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_toneport_source_info, - .get = snd_toneport_source_get, - .put = snd_toneport_source_put -}; - -/* - Toneport destructor. -*/ -static void toneport_destruct(struct usb_interface *interface) -{ - struct usb_line6_toneport *toneport = usb_get_intfdata(interface); - - if (toneport == NULL) - return; - line6_cleanup_audio(&toneport->line6); -} - -/* - Setup Toneport device. -*/ -static void toneport_setup(struct usb_line6_toneport *toneport) -{ - int ticks; - struct usb_line6 *line6 = &toneport->line6; - struct usb_device *usbdev = line6->usbdev; - - /* sync time on device with host: */ - ticks = (int)get_seconds(); - line6_write_data(line6, 0x80c6, &ticks, 4); - - /* enable device: */ - toneport_send_cmd(usbdev, 0x0301, 0x0000); - - /* initialize source select: */ - switch (line6->type) { - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - toneport_send_cmd(usbdev, - toneport_source_info[toneport->source].code, - 0x0000); - default: - break; - } - - if (toneport_has_led(line6->type)) - toneport_update_led(&usbdev->dev); -} - -/* - Toneport device disconnected. -*/ -static void line6_toneport_disconnect(struct usb_interface *interface) -{ - struct usb_line6_toneport *toneport; - u16 idProduct; - - if (interface == NULL) - return; - - toneport = usb_get_intfdata(interface); - del_timer_sync(&toneport->timer); - idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); - - if (toneport_has_led(idProduct)) { - device_remove_file(&interface->dev, &dev_attr_led_red); - device_remove_file(&interface->dev, &dev_attr_led_green); - } - - if (toneport != NULL) { - struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; - - if (line6pcm != NULL) { - line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); - line6_pcm_disconnect(line6pcm); - } - } - - toneport_destruct(interface); -} - - -/* - Try to init Toneport device. -*/ -static int toneport_try_init(struct usb_interface *interface, - struct usb_line6 *line6) -{ - int err; - struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; - - if ((interface == NULL) || (toneport == NULL)) - return -ENODEV; - - line6->disconnect = line6_toneport_disconnect; - - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - - /* initialize PCM subsystem: */ - err = line6_init_pcm(line6, &toneport_pcm_properties); - if (err < 0) - return err; - - /* register monitor control: */ - err = snd_ctl_add(line6->card, - snd_ctl_new1(&toneport_control_monitor, - line6->line6pcm)); - if (err < 0) - return err; - - /* register source select control: */ - switch (line6->type) { - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - err = - snd_ctl_add(line6->card, - snd_ctl_new1(&toneport_control_source, - line6->line6pcm)); - if (err < 0) - return err; - - default: - break; - } - - /* register audio system: */ - err = line6_register_audio(line6); - if (err < 0) - return err; - - line6_read_serial_number(line6, &toneport->serial_number); - line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); - - if (toneport_has_led(line6->type)) { - CHECK_RETURN(device_create_file - (&interface->dev, &dev_attr_led_red)); - CHECK_RETURN(device_create_file - (&interface->dev, &dev_attr_led_green)); - } - - toneport_setup(toneport); - - init_timer(&toneport->timer); - toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ; - toneport->timer.function = toneport_start_pcm; - toneport->timer.data = (unsigned long)toneport; - add_timer(&toneport->timer); - - return 0; -} - -/* - Init Toneport device (and clean up in case of failure). -*/ -int line6_toneport_init(struct usb_interface *interface, - struct usb_line6 *line6) -{ - int err = toneport_try_init(interface, line6); - - if (err < 0) - toneport_destruct(interface); - - return err; -} - -/* - Resume Toneport device after reset. -*/ -void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) -{ - toneport_setup(toneport); -} diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h deleted file mode 100644 index 8cb1442..0000000 --- a/drivers/staging/line6/toneport.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef TONEPORT_H -#define TONEPORT_H - -#include -#include - -#include "driver.h" - -struct usb_line6_toneport { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Source selector. - */ - int source; - - /** - Serial number of device. - */ - int serial_number; - - /** - Firmware version (x 100). - */ - int firmware_version; - - /** - Timer for delayed PCM startup. - */ - struct timer_list timer; -}; - -extern int line6_toneport_init(struct usb_interface *interface, - struct usb_line6 *line6); -extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); - -#endif diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h deleted file mode 100644 index f4d080e..0000000 --- a/drivers/staging/line6/usbdefs.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef USBDEFS_H -#define USBDEFS_H - -#define USB_INTERVALS_PER_SECOND 1000 - -/* device supports settings parameter via USB */ -#define LINE6_CAP_CONTROL (1 << 0) -/* device supports PCM input/output via USB */ -#define LINE6_CAP_PCM (1 << 1) -/* device support hardware monitoring */ -#define LINE6_CAP_HWMON (1 << 2) - -#define LINE6_FALLBACK_INTERVAL 10 -#define LINE6_FALLBACK_MAXPACKETSIZE 16 - -#endif diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c deleted file mode 100644 index b4a41b0..0000000 --- a/drivers/staging/line6/variax.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include - -#include "audio.h" -#include "driver.h" -#include "variax.h" - -#define VARIAX_OFFSET_ACTIVATE 7 - -/* - This message is sent by the device during initialization and identifies - the connected guitar version. -*/ -static const char variax_init_version[] = { - 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, - 0x07, 0x00, 0x00, 0x00 -}; - -/* - This message is the last one sent by the device during initialization. -*/ -static const char variax_init_done[] = { - 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b -}; - -static const char variax_activate[] = { - 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, - 0xf7 -}; - -/* forward declarations: */ -static void variax_startup2(unsigned long data); -static void variax_startup4(unsigned long data); -static void variax_startup5(unsigned long data); - -static void variax_activate_async(struct usb_line6_variax *variax, int a) -{ - variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; - line6_send_raw_message_async(&variax->line6, variax->buffer_activate, - sizeof(variax_activate)); -} - -/* - Variax startup procedure. - This is a sequence of functions with special requirements (e.g., must - not run immediately after initialization, must not run in interrupt - context). After the last one has finished, the device is ready to use. -*/ - -static void variax_startup1(struct usb_line6_variax *variax) -{ - CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); - - /* delay startup procedure: */ - line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2, (unsigned long)variax); -} - -static void variax_startup2(unsigned long data) -{ - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; - struct usb_line6 *line6 = &variax->line6; - - /* schedule another startup procedure until startup is complete: */ - if (variax->startup_progress >= VARIAX_STARTUP_LAST) - return; - - variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; - line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2, (unsigned long)variax); - - /* request firmware version: */ - line6_version_request_async(line6); -} - -static void variax_startup3(struct usb_line6_variax *variax) -{ - CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); - - /* delay startup procedure: */ - line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, - variax_startup4, (unsigned long)variax); -} - -static void variax_startup4(unsigned long data) -{ - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; - - CHECK_STARTUP_PROGRESS(variax->startup_progress, - VARIAX_STARTUP_ACTIVATE); - - /* activate device: */ - variax_activate_async(variax, 1); - line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, - variax_startup5, (unsigned long)variax); -} - -static void variax_startup5(unsigned long data) -{ - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; - - CHECK_STARTUP_PROGRESS(variax->startup_progress, - VARIAX_STARTUP_WORKQUEUE); - - /* schedule work for global work queue: */ - schedule_work(&variax->startup_work); -} - -static void variax_startup6(struct work_struct *work) -{ - struct usb_line6_variax *variax = - container_of(work, struct usb_line6_variax, startup_work); - - CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); - - /* ALSA audio interface: */ - line6_register_audio(&variax->line6); -} - -/* - Process a completely received message. -*/ -static void line6_variax_process_message(struct usb_line6 *line6) -{ - struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; - const unsigned char *buf = variax->line6.buffer_message; - - switch (buf[0]) { - case LINE6_RESET: - dev_info(variax->line6.ifcdev, "VARIAX reset\n"); - break; - - case LINE6_SYSEX_BEGIN: - if (memcmp(buf + 1, variax_init_version + 1, - sizeof(variax_init_version) - 1) == 0) { - variax_startup3(variax); - } else if (memcmp(buf + 1, variax_init_done + 1, - sizeof(variax_init_done) - 1) == 0) { - /* notify of complete initialization: */ - variax_startup4((unsigned long)variax); - } - break; - } -} - -/* - Variax destructor. -*/ -static void variax_destruct(struct usb_interface *interface) -{ - struct usb_line6_variax *variax = usb_get_intfdata(interface); - - if (variax == NULL) - return; - line6_cleanup_audio(&variax->line6); - - del_timer(&variax->startup_timer1); - del_timer(&variax->startup_timer2); - cancel_work_sync(&variax->startup_work); - - kfree(variax->buffer_activate); -} - -/* - Workbench device disconnected. -*/ -static void line6_variax_disconnect(struct usb_interface *interface) -{ - if (interface == NULL) - return; - - variax_destruct(interface); -} - -/* - Try to init workbench device. -*/ -static int variax_try_init(struct usb_interface *interface, - struct usb_line6 *line6) -{ - struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; - int err; - - line6->process_message = line6_variax_process_message; - line6->disconnect = line6_variax_disconnect; - - init_timer(&variax->startup_timer1); - init_timer(&variax->startup_timer2); - INIT_WORK(&variax->startup_work, variax_startup6); - - if ((interface == NULL) || (variax == NULL)) - return -ENODEV; - - /* initialize USB buffers: */ - variax->buffer_activate = kmemdup(variax_activate, - sizeof(variax_activate), GFP_KERNEL); - - if (variax->buffer_activate == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - return -ENOMEM; - } - - /* initialize audio system: */ - err = line6_init_audio(&variax->line6); - if (err < 0) - return err; - - /* initialize MIDI subsystem: */ - err = line6_init_midi(&variax->line6); - if (err < 0) - return err; - - /* initiate startup procedure: */ - variax_startup1(variax); - return 0; -} - -/* - Init workbench device (and clean up in case of failure). -*/ -int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) -{ - int err = variax_try_init(interface, line6); - - if (err < 0) - variax_destruct(interface); - - return err; -} diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h deleted file mode 100644 index dfb94e5..0000000 --- a/drivers/staging/line6/variax.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef VARIAX_H -#define VARIAX_H - -#include -#include -#include -#include - -#include "driver.h" - -#define VARIAX_STARTUP_DELAY1 1000 -#define VARIAX_STARTUP_DELAY3 100 -#define VARIAX_STARTUP_DELAY4 100 - -/* - Stages of Variax startup procedure -*/ -enum { - VARIAX_STARTUP_INIT = 1, - VARIAX_STARTUP_VERSIONREQ, - VARIAX_STARTUP_WAIT, - VARIAX_STARTUP_ACTIVATE, - VARIAX_STARTUP_WORKQUEUE, - VARIAX_STARTUP_SETUP, - VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 -}; - -struct usb_line6_variax { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Buffer for activation code. - */ - unsigned char *buffer_activate; - - /** - Handler for device initializaton. - */ - struct work_struct startup_work; - - /** - Timers for device initializaton. - */ - struct timer_list startup_timer1; - struct timer_list startup_timer2; - - /** - Current progress in startup procedure. - */ - int startup_progress; -}; - -extern int line6_variax_init(struct usb_interface *interface, - struct usb_line6 *line6); - -#endif diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index d393153..a452ad7 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -160,5 +160,7 @@ config SND_BCD2000 To compile this driver as a module, choose M here: the module will be called snd-bcd2000. +source "sound/usb/line6/Kconfig" + endif # SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index bcee406..54045b7 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ +obj-$(CONFIG_LINE6_USB) += line6/ diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig new file mode 100644 index 0000000..4f1219b --- /dev/null +++ b/sound/usb/line6/Kconfig @@ -0,0 +1,38 @@ +menuconfig LINE6_USB + tristate "Line6 USB support" + depends on USB && SND + select SND_RAWMIDI + select SND_PCM + help + This is a driver for the guitar amp, cab, and effects modeller + PODxt Pro by Line6 (and similar devices), supporting the + following features: + * Reading/writing individual parameters + * Reading/writing complete channel, effects setup, and amp + setup data + * Channel switching + * Virtual MIDI interface + * Tuner access + * Playback/capture/mixer device for any ALSA-compatible PCM + audio application + * Signal routing (record clean/processed guitar signal, + re-amping) + + Preliminary support for the Variax Workbench and TonePort + devices is included. + +if LINE6_USB + +config LINE6_USB_IMPULSE_RESPONSE + bool "measure impulse response" + default n + help + Say Y here to add code to measure the impulse response of a Line6 + device. This is more accurate than user-space methods since it + bypasses any PCM data buffering (e.g., by ALSA or jack). This is + useful for assessing the performance of new devices, but is not + required for normal operation. + + If unsure, say N. + +endif # LINE6_USB diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile new file mode 100644 index 0000000..ae5c374 --- /dev/null +++ b/sound/usb/line6/Makefile @@ -0,0 +1,14 @@ +obj-$(CONFIG_LINE6_USB) += line6usb.o + +line6usb-y := \ + audio.o \ + capture.o \ + driver.o \ + midi.o \ + midibuf.o \ + pcm.o \ + playback.o \ + pod.o \ + toneport.o \ + variax.o \ + podhd.o diff --git a/sound/usb/line6/audio.c b/sound/usb/line6/audio.c new file mode 100644 index 0000000..171d80c --- /dev/null +++ b/sound/usb/line6/audio.c @@ -0,0 +1,71 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include + +#include "driver.h" +#include "audio.h" + +/* + Initialize the Line6 USB audio system. +*/ +int line6_init_audio(struct usb_line6 *line6) +{ + struct snd_card *card; + int err; + + err = snd_card_new(line6->ifcdev, + SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); + if (err < 0) + return err; + + line6->card = card; + + strcpy(card->id, line6->properties->id); + strcpy(card->driver, DRIVER_NAME); + strcpy(card->shortname, line6->properties->name); + /* longname is 80 chars - see asound.h */ + sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name, + dev_name(line6->ifcdev)); + return 0; +} + +/* + Register the Line6 USB audio system. +*/ +int line6_register_audio(struct usb_line6 *line6) +{ + int err; + + err = snd_card_register(line6->card); + if (err < 0) + return err; + + return 0; +} + +/* + Cleanup the Line6 USB audio system. +*/ +void line6_cleanup_audio(struct usb_line6 *line6) +{ + struct snd_card *card = line6->card; + + if (card == NULL) + return; + + snd_card_disconnect(card); + snd_card_free(card); + line6->card = NULL; +} diff --git a/sound/usb/line6/audio.h b/sound/usb/line6/audio.h new file mode 100644 index 0000000..5f8a09a --- /dev/null +++ b/sound/usb/line6/audio.h @@ -0,0 +1,21 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef AUDIO_H +#define AUDIO_H + +#include "driver.h" + +extern void line6_cleanup_audio(struct usb_line6 *); +extern int line6_init_audio(struct usb_line6 *); +extern int line6_register_audio(struct usb_line6 *); + +#endif diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c new file mode 100644 index 0000000..f24c7c5 --- /dev/null +++ b/sound/usb/line6/capture.c @@ -0,0 +1,433 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include +#include + +#include "audio.h" +#include "capture.h" +#include "driver.h" +#include "pcm.h" +#include "pod.h" + +/* + Find a free URB and submit it. +*/ +static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) +{ + int index; + unsigned long flags; + int i, urb_size; + int ret; + struct urb *urb_in; + + spin_lock_irqsave(&line6pcm->lock_audio_in, flags); + index = + find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); + + if (index < 0 || index >= LINE6_ISO_BUFFERS) { + spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); + dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); + return -EINVAL; + } + + urb_in = line6pcm->urb_audio_in[index]; + urb_size = 0; + + for (i = 0; i < LINE6_ISO_PACKETS; ++i) { + struct usb_iso_packet_descriptor *fin = + &urb_in->iso_frame_desc[i]; + fin->offset = urb_size; + fin->length = line6pcm->max_packet_size; + urb_size += line6pcm->max_packet_size; + } + + urb_in->transfer_buffer = + line6pcm->buffer_in + + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; + urb_in->transfer_buffer_length = urb_size; + urb_in->context = line6pcm; + + ret = usb_submit_urb(urb_in, GFP_ATOMIC); + + if (ret == 0) + set_bit(index, &line6pcm->active_urb_in); + else + dev_err(line6pcm->line6->ifcdev, + "URB in #%d submission failed (%d)\n", index, ret); + + spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); + return 0; +} + +/* + Submit all currently available capture URBs. +*/ +int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) +{ + int ret, i; + + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + ret = submit_audio_in_urb(line6pcm); + if (ret < 0) + return ret; + } + + return 0; +} + +/* + Unlink all currently active capture URBs. +*/ +void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) +{ + unsigned int i; + + for (i = LINE6_ISO_BUFFERS; i--;) { + if (test_bit(i, &line6pcm->active_urb_in)) { + if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { + struct urb *u = line6pcm->urb_audio_in[i]; + + usb_unlink_urb(u); + } + } + } +} + +/* + Wait until unlinking of all currently active capture URBs has been + finished. +*/ +void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) +{ + int timeout = HZ; + unsigned int i; + int alive; + + do { + alive = 0; + for (i = LINE6_ISO_BUFFERS; i--;) { + if (test_bit(i, &line6pcm->active_urb_in)) + alive++; + } + if (!alive) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } while (--timeout > 0); + if (alive) + snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); +} + +/* + Unlink all currently active capture URBs, and wait for finishing. +*/ +void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) +{ + line6_unlink_audio_in_urbs(line6pcm); + line6_wait_clear_audio_in_urbs(line6pcm); +} + +/* + Copy data into ALSA capture buffer. +*/ +void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) +{ + struct snd_pcm_substream *substream = + get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); + struct snd_pcm_runtime *runtime = substream->runtime; + const int bytes_per_frame = line6pcm->properties->bytes_per_frame; + int frames = fsize / bytes_per_frame; + + if (runtime == NULL) + return; + + if (line6pcm->pos_in_done + frames > runtime->buffer_size) { + /* + The transferred area goes over buffer boundary, + copy two separate chunks. + */ + int len; + + len = runtime->buffer_size - line6pcm->pos_in_done; + + if (len > 0) { + memcpy(runtime->dma_area + + line6pcm->pos_in_done * bytes_per_frame, fbuf, + len * bytes_per_frame); + memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, + (frames - len) * bytes_per_frame); + } else { + /* this is somewhat paranoid */ + dev_err(line6pcm->line6->ifcdev, + "driver bug: len = %d\n", len); + } + } else { + /* copy single chunk */ + memcpy(runtime->dma_area + + line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); + } + + line6pcm->pos_in_done += frames; + if (line6pcm->pos_in_done >= runtime->buffer_size) + line6pcm->pos_in_done -= runtime->buffer_size; +} + +void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) +{ + struct snd_pcm_substream *substream = + get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); + + line6pcm->bytes_in += length; + if (line6pcm->bytes_in >= line6pcm->period_in) { + line6pcm->bytes_in %= line6pcm->period_in; + snd_pcm_period_elapsed(substream); + } +} + +void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) +{ + kfree(line6pcm->buffer_in); + line6pcm->buffer_in = NULL; +} + +/* + * Callback for completed capture URB. + */ +static void audio_in_callback(struct urb *urb) +{ + int i, index, length = 0, shutdown = 0; + unsigned long flags; + + struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; + + line6pcm->last_frame_in = urb->start_frame; + + /* find index of URB */ + for (index = 0; index < LINE6_ISO_BUFFERS; ++index) + if (urb == line6pcm->urb_audio_in[index]) + break; + + spin_lock_irqsave(&line6pcm->lock_audio_in, flags); + + for (i = 0; i < LINE6_ISO_PACKETS; ++i) { + char *fbuf; + int fsize; + struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; + + if (fin->status == -EXDEV) { + shutdown = 1; + break; + } + + fbuf = urb->transfer_buffer + fin->offset; + fsize = fin->actual_length; + + if (fsize > line6pcm->max_packet_size) { + dev_err(line6pcm->line6->ifcdev, + "driver and/or device bug: packet too large (%d > %d)\n", + fsize, line6pcm->max_packet_size); + } + + length += fsize; + + /* the following assumes LINE6_ISO_PACKETS == 1: */ + line6pcm->prev_fbuf = fbuf; + line6pcm->prev_fsize = fsize; + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) +#endif + if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, + &line6pcm->flags) && (fsize > 0)) + line6_capture_copy(line6pcm, fbuf, fsize); + } + + clear_bit(index, &line6pcm->active_urb_in); + + if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) + shutdown = 1; + + spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); + + if (!shutdown) { + submit_audio_in_urb(line6pcm); + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) +#endif + if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, + &line6pcm->flags)) + line6_capture_check_period(line6pcm, length); + } +} + +/* open capture callback */ +static int snd_line6_capture_open(struct snd_pcm_substream *substream) +{ + int err; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + err = snd_pcm_hw_constraint_ratdens(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + (&line6pcm-> + properties->snd_line6_rates)); + if (err < 0) + return err; + + runtime->hw = line6pcm->properties->snd_line6_capture_hw; + return 0; +} + +/* close capture callback */ +static int snd_line6_capture_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* hw_params capture callback */ +static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int ret; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + /* -- Florian Demski [FD] */ + /* don't ask me why, but this fixes the bug on my machine */ + if (line6pcm == NULL) { + if (substream->pcm == NULL) + return -ENOMEM; + if (substream->pcm->private_data == NULL) + return -ENOMEM; + substream->private_data = substream->pcm->private_data; + line6pcm = snd_pcm_substream_chip(substream); + } + /* -- [FD] end */ + + ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); + + if (ret < 0) + return ret; + + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) { + line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); + return ret; + } + + line6pcm->period_in = params_period_bytes(hw_params); + return 0; +} + +/* hw_free capture callback */ +static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); + return snd_pcm_lib_free_pages(substream); +} + +/* trigger callback */ +int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) +{ + int err; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: +#ifdef CONFIG_PM + case SNDRV_PCM_TRIGGER_RESUME: +#endif + err = line6_pcm_acquire(line6pcm, + LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); + + if (err < 0) + return err; + + break; + + case SNDRV_PCM_TRIGGER_STOP: +#ifdef CONFIG_PM + case SNDRV_PCM_TRIGGER_SUSPEND: +#endif + err = line6_pcm_release(line6pcm, + LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); + + if (err < 0) + return err; + + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* capture pointer callback */ +static snd_pcm_uframes_t +snd_line6_capture_pointer(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + return line6pcm->pos_in_done; +} + +/* capture operators */ +struct snd_pcm_ops snd_line6_capture_ops = { + .open = snd_line6_capture_open, + .close = snd_line6_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_line6_capture_hw_params, + .hw_free = snd_line6_capture_hw_free, + .prepare = snd_line6_prepare, + .trigger = snd_line6_trigger, + .pointer = snd_line6_capture_pointer, +}; + +int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) +{ + struct usb_line6 *line6 = line6pcm->line6; + int i; + + /* create audio URBs and fill in constant values: */ + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + struct urb *urb; + + /* URB for audio in: */ + urb = line6pcm->urb_audio_in[i] = + usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); + + if (urb == NULL) { + dev_err(line6->ifcdev, "Out of memory\n"); + return -ENOMEM; + } + + urb->dev = line6->usbdev; + urb->pipe = + usb_rcvisocpipe(line6->usbdev, + line6->properties->ep_audio_r & + USB_ENDPOINT_NUMBER_MASK); + urb->transfer_flags = URB_ISO_ASAP; + urb->start_frame = -1; + urb->number_of_packets = LINE6_ISO_PACKETS; + urb->interval = LINE6_ISO_INTERVAL; + urb->error_count = 0; + urb->complete = audio_in_callback; + } + + return 0; +} diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h new file mode 100644 index 0000000..4157bcb --- /dev/null +++ b/sound/usb/line6/capture.h @@ -0,0 +1,35 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef CAPTURE_H +#define CAPTURE_H + +#include + +#include "driver.h" +#include "pcm.h" + +extern struct snd_pcm_ops snd_line6_capture_ops; + +extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, + int fsize); +extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, + int length); +extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm); +extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm + *line6pcm); +extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm); +extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); + +#endif diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c new file mode 100644 index 0000000..fc852f6 --- /dev/null +++ b/sound/usb/line6/driver.c @@ -0,0 +1,1114 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include +#include + +#include "audio.h" +#include "capture.h" +#include "driver.h" +#include "midi.h" +#include "playback.h" +#include "pod.h" +#include "podhd.h" +#include "revision.h" +#include "toneport.h" +#include "usbdefs.h" +#include "variax.h" + +#define DRIVER_AUTHOR "Markus Grabner " +#define DRIVER_DESC "Line6 USB Driver" +#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION + +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id line6_id_table[] = { + { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, + { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, + { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, + { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, + { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, + { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, + { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, + { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, + { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, + { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, + { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, + { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, + { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, + { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, + { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, + { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, + { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, + { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, + { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, + { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, + {} +}; + +MODULE_DEVICE_TABLE(usb, line6_id_table); + +static const struct line6_properties line6_properties_table[] = { + [LINE6_BASSPODXT] = { + .id = "BassPODxt", + .name = "BassPODxt", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_BASSPODXTLIVE] = { + .id = "BassPODxtLive", + .name = "BassPODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_BASSPODXTPRO] = { + .id = "BassPODxtPro", + .name = "BassPODxt Pro", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_GUITARPORT] = { + .id = "GuitarPort", + .name = "GuitarPort", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_POCKETPOD] = { + .id = "PocketPOD", + .name = "Pocket POD", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 0, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x02, + /* no audio channel */ + }, + [LINE6_PODHD300] = { + .id = "PODHD300", + .name = "POD HD300", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODHD400] = { + .id = "PODHD400", + .name = "POD HD400", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODHD500_0] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, + [LINE6_PODHD500_1] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, + [LINE6_PODSTUDIO_GX] = { + .id = "PODStudioGX", + .name = "POD Studio GX", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_UX1] = { + .id = "PODStudioUX1", + .name = "POD Studio UX1", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_UX2] = { + .id = "PODStudioUX2", + .name = "POD Studio UX2", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXT] = { + .id = "PODxt", + .name = "PODxt", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTLIVE_POD] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTLIVE_VARIAX] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x86, + .ep_ctrl_w = 0x05, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTPRO] = { + .id = "PODxtPro", + .name = "PODxt Pro", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_GX] = { + .id = "TonePortGX", + .name = "TonePort GX", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_UX1] = { + .id = "TonePortUX1", + .name = "TonePort UX1", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_UX2] = { + .id = "TonePortUX2", + .name = "TonePort UX2", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_VARIAX] = { + .id = "Variax", + .name = "Variax Workbench", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 1, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x01, + /* no audio channel */ + } +}; + +/* + This is Line6's MIDI manufacturer ID. +*/ +const unsigned char line6_midi_id[] = { + 0x00, 0x01, 0x0c +}; + +/* + Code to request version of POD, Variax interface + (and maybe other devices). +*/ +static const char line6_request_version[] = { + 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 +}; + +/** + Class for asynchronous messages. +*/ +struct message { + struct usb_line6 *line6; + const char *buffer; + int size; + int done; +}; + +/* + Forward declarations. +*/ +static void line6_data_received(struct urb *urb); +static int line6_send_raw_message_async_part(struct message *msg, + struct urb *urb); + +/* + Start to listen on endpoint. +*/ +static int line6_start_listen(struct usb_line6 *line6) +{ + int err; + + usb_fill_int_urb(line6->urb_listen, line6->usbdev, + usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), + line6->buffer_listen, LINE6_BUFSIZE_LISTEN, + line6_data_received, line6, line6->interval); + line6->urb_listen->actual_length = 0; + err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); + return err; +} + +/* + Stop listening on endpoint. +*/ +static void line6_stop_listen(struct usb_line6 *line6) +{ + usb_kill_urb(line6->urb_listen); +} + +/* + Send raw message in pieces of wMaxPacketSize bytes. +*/ +int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, + int size) +{ + int i, done = 0; + + for (i = 0; i < size; i += line6->max_packet_size) { + int partial; + const char *frag_buf = buffer + i; + int frag_size = min(line6->max_packet_size, size - i); + int retval; + + retval = usb_interrupt_msg(line6->usbdev, + usb_sndintpipe(line6->usbdev, + line6->properties->ep_ctrl_w), + (char *)frag_buf, frag_size, + &partial, LINE6_TIMEOUT * HZ); + + if (retval) { + dev_err(line6->ifcdev, + "usb_interrupt_msg failed (%d)\n", retval); + break; + } + + done += frag_size; + } + + return done; +} + +/* + Notification of completion of asynchronous request transmission. +*/ +static void line6_async_request_sent(struct urb *urb) +{ + struct message *msg = (struct message *)urb->context; + + if (msg->done >= msg->size) { + usb_free_urb(urb); + kfree(msg); + } else + line6_send_raw_message_async_part(msg, urb); +} + +/* + Asynchronously send part of a raw message. +*/ +static int line6_send_raw_message_async_part(struct message *msg, + struct urb *urb) +{ + int retval; + struct usb_line6 *line6 = msg->line6; + int done = msg->done; + int bytes = min(msg->size - done, line6->max_packet_size); + + usb_fill_int_urb(urb, line6->usbdev, + usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), + (char *)msg->buffer + done, bytes, + line6_async_request_sent, msg, line6->interval); + + msg->done += bytes; + retval = usb_submit_urb(urb, GFP_ATOMIC); + + if (retval < 0) { + dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", + __func__, retval); + usb_free_urb(urb); + kfree(msg); + return retval; + } + + return 0; +} + +/* + Setup and start timer. +*/ +void line6_start_timer(struct timer_list *timer, unsigned int msecs, + void (*function)(unsigned long), unsigned long data) +{ + setup_timer(timer, function, data); + timer->expires = jiffies + msecs * HZ / 1000; + add_timer(timer); +} + +/* + Asynchronously send raw message. +*/ +int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, + int size) +{ + struct message *msg; + struct urb *urb; + + /* create message: */ + msg = kmalloc(sizeof(struct message), GFP_ATOMIC); + if (msg == NULL) + return -ENOMEM; + + /* create URB: */ + urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (urb == NULL) { + kfree(msg); + dev_err(line6->ifcdev, "Out of memory\n"); + return -ENOMEM; + } + + /* set message data: */ + msg->line6 = line6; + msg->buffer = buffer; + msg->size = size; + msg->done = 0; + + /* start sending: */ + return line6_send_raw_message_async_part(msg, urb); +} + +/* + Send asynchronous device version request. +*/ +int line6_version_request_async(struct usb_line6 *line6) +{ + char *buffer; + int retval; + + buffer = kmemdup(line6_request_version, + sizeof(line6_request_version), GFP_ATOMIC); + if (buffer == NULL) { + dev_err(line6->ifcdev, "Out of memory"); + return -ENOMEM; + } + + retval = line6_send_raw_message_async(line6, buffer, + sizeof(line6_request_version)); + kfree(buffer); + return retval; +} + +/* + Send sysex message in pieces of wMaxPacketSize bytes. +*/ +int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, + int size) +{ + return line6_send_raw_message(line6, buffer, + size + SYSEX_EXTRA_SIZE) - + SYSEX_EXTRA_SIZE; +} + +/* + Allocate buffer for sysex message and prepare header. + @param code sysex message code + @param size number of bytes between code and sysex end +*/ +char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, + int size) +{ + char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); + + if (!buffer) + return NULL; + + buffer[0] = LINE6_SYSEX_BEGIN; + memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); + buffer[sizeof(line6_midi_id) + 1] = code1; + buffer[sizeof(line6_midi_id) + 2] = code2; + buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; + return buffer; +} + +/* + Notification of data received from the Line6 device. +*/ +static void line6_data_received(struct urb *urb) +{ + struct usb_line6 *line6 = (struct usb_line6 *)urb->context; + struct midi_buffer *mb = &line6->line6midi->midibuf_in; + int done; + + if (urb->status == -ESHUTDOWN) + return; + + done = + line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); + + if (done < urb->actual_length) { + line6_midibuf_ignore(mb, done); + dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", + done, urb->actual_length); + } + + for (;;) { + done = + line6_midibuf_read(mb, line6->buffer_message, + LINE6_MESSAGE_MAXLEN); + + if (done == 0) + break; + + line6->message_length = done; + line6_midi_receive(line6, line6->buffer_message, done); + + if (line6->process_message) + line6->process_message(line6); + } + + line6_start_listen(line6); +} + +/* + Send channel number (i.e., switch to a different sound). +*/ +int line6_send_program(struct usb_line6 *line6, u8 value) +{ + int retval; + unsigned char *buffer; + int partial; + + buffer = kmalloc(2, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST; + buffer[1] = value; + + retval = usb_interrupt_msg(line6->usbdev, + usb_sndintpipe(line6->usbdev, + line6->properties->ep_ctrl_w), + buffer, 2, &partial, LINE6_TIMEOUT * HZ); + + if (retval) + dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", + retval); + + kfree(buffer); + return retval; +} + +/* + Transmit Line6 control parameter. +*/ +int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) +{ + int retval; + unsigned char *buffer; + int partial; + + buffer = kmalloc(3, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST; + buffer[1] = param; + buffer[2] = value; + + retval = usb_interrupt_msg(line6->usbdev, + usb_sndintpipe(line6->usbdev, + line6->properties->ep_ctrl_w), + buffer, 3, &partial, LINE6_TIMEOUT * HZ); + + if (retval) + dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", + retval); + + kfree(buffer); + return retval; +} + +/* + Read data from device. +*/ +int line6_read_data(struct usb_line6 *line6, int address, void *data, + size_t datalen) +{ + struct usb_device *usbdev = line6->usbdev; + int ret; + unsigned char len; + + /* query the serial number: */ + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + (datalen << 8) | 0x21, address, + NULL, 0, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); + return ret; + } + + /* Wait for data length. We'll get 0xff until length arrives. */ + do { + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, + 0x0012, 0x0000, &len, 1, + LINE6_TIMEOUT * HZ); + if (ret < 0) { + dev_err(line6->ifcdev, + "receive length failed (error %d)\n", ret); + return ret; + } + } while (len == 0xff); + + if (len != datalen) { + /* should be equal or something went wrong */ + dev_err(line6->ifcdev, + "length mismatch (expected %d, got %d)\n", + (int)datalen, (int)len); + return -EINVAL; + } + + /* receive the result: */ + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0013, 0x0000, data, datalen, + LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, "read failed (error %d)\n", ret); + return ret; + } + + return 0; +} + +/* + Write data to device. +*/ +int line6_write_data(struct usb_line6 *line6, int address, void *data, + size_t datalen) +{ + struct usb_device *usbdev = line6->usbdev; + int ret; + unsigned char status; + + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x0022, address, data, datalen, + LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, + "write request failed (error %d)\n", ret); + return ret; + } + + do { + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), + 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, + 0x0012, 0x0000, + &status, 1, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, + "receiving status failed (error %d)\n", ret); + return ret; + } + } while (status == 0xff); + + if (status != 0) { + dev_err(line6->ifcdev, "write failed (error %d)\n", ret); + return -EINVAL; + } + + return 0; +} + +/* + Read Line6 device serial number. + (POD, TonePort, GuitarPort) +*/ +int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) +{ + return line6_read_data(line6, 0x80d0, serial_number, + sizeof(*serial_number)); +} + +/* + No operation (i.e., unsupported). +*/ +ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return 0; +} + +/* + Generic destructor. +*/ +static void line6_destruct(struct usb_interface *interface) +{ + struct usb_line6 *line6; + + if (interface == NULL) + return; + line6 = usb_get_intfdata(interface); + if (line6 == NULL) + return; + + /* free buffer memory first: */ + kfree(line6->buffer_message); + kfree(line6->buffer_listen); + + /* then free URBs: */ + usb_free_urb(line6->urb_listen); + + /* make sure the device isn't destructed twice: */ + usb_set_intfdata(interface, NULL); + + /* free interface data: */ + kfree(line6); +} + +/* + Probe USB device. +*/ +static int line6_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + enum line6_device_type devtype; + struct usb_device *usbdev; + struct usb_line6 *line6; + const struct line6_properties *properties; + int interface_number; + int size = 0; + int ret; + + if (interface == NULL) + return -ENODEV; + usbdev = interface_to_usbdev(interface); + if (usbdev == NULL) + return -ENODEV; + + /* we don't handle multiple configurations */ + if (usbdev->descriptor.bNumConfigurations != 1) { + ret = -ENODEV; + goto err_put; + } + + devtype = id->driver_info; + + /* initialize device info: */ + properties = &line6_properties_table[devtype]; + dev_info(&interface->dev, "Line6 %s found\n", properties->name); + + /* query interface number */ + interface_number = interface->cur_altsetting->desc.bInterfaceNumber; + + ret = usb_set_interface(usbdev, interface_number, + properties->altsetting); + if (ret < 0) { + dev_err(&interface->dev, "set_interface failed\n"); + goto err_put; + } + + /* initialize device data based on device: */ + switch (devtype) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_PODXT: + case LINE6_PODXTPRO: + size = sizeof(struct usb_line6_pod); + break; + + case LINE6_PODHD300: + case LINE6_PODHD400: + size = sizeof(struct usb_line6_podhd); + break; + + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: + size = sizeof(struct usb_line6_podhd); + break; + + case LINE6_POCKETPOD: + size = sizeof(struct usb_line6_pod); + break; + + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: + size = sizeof(struct usb_line6_toneport); + break; + + case LINE6_PODXTLIVE_POD: + size = sizeof(struct usb_line6_pod); + break; + + case LINE6_PODXTLIVE_VARIAX: + size = sizeof(struct usb_line6_variax); + break; + + case LINE6_VARIAX: + size = sizeof(struct usb_line6_variax); + break; + + default: + MISSING_CASE; + ret = -ENODEV; + goto err_put; + } + + if (size == 0) { + dev_err(&interface->dev, + "driver bug: interface data size not set\n"); + ret = -ENODEV; + goto err_put; + } + + line6 = kzalloc(size, GFP_KERNEL); + if (line6 == NULL) { + ret = -ENODEV; + goto err_put; + } + + /* store basic data: */ + line6->properties = properties; + line6->usbdev = usbdev; + line6->ifcdev = &interface->dev; + line6->type = devtype; + + /* get data from endpoint descriptor (see usb_maxpacket): */ + { + struct usb_host_endpoint *ep; + unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r); + unsigned epnum = usb_pipeendpoint(pipe); + ep = usbdev->ep_in[epnum]; + + if (ep != NULL) { + line6->interval = ep->desc.bInterval; + line6->max_packet_size = + le16_to_cpu(ep->desc.wMaxPacketSize); + } else { + line6->interval = LINE6_FALLBACK_INTERVAL; + line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; + dev_err(line6->ifcdev, + "endpoint not available, using fallback values"); + } + } + + usb_set_intfdata(interface, line6); + + if (properties->capabilities & LINE6_CAP_CONTROL) { + /* initialize USB buffers: */ + line6->buffer_listen = + kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); + if (line6->buffer_listen == NULL) { + ret = -ENOMEM; + goto err_destruct; + } + + line6->buffer_message = + kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); + if (line6->buffer_message == NULL) { + ret = -ENOMEM; + goto err_destruct; + } + + line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); + + if (line6->urb_listen == NULL) { + dev_err(&interface->dev, "Out of memory\n"); + line6_destruct(interface); + ret = -ENOMEM; + goto err_destruct; + } + + ret = line6_start_listen(line6); + if (ret < 0) { + dev_err(&interface->dev, "%s: usb_submit_urb failed\n", + __func__); + goto err_destruct; + } + } + + /* initialize device data based on device: */ + switch (devtype) { + case LINE6_BASSPODXT: + case LINE6_BASSPODXTLIVE: + case LINE6_BASSPODXTPRO: + case LINE6_POCKETPOD: + case LINE6_PODXT: + case LINE6_PODXTPRO: + ret = line6_pod_init(interface, line6); + break; + + case LINE6_PODHD300: + case LINE6_PODHD400: + case LINE6_PODHD500_0: + case LINE6_PODHD500_1: + ret = line6_podhd_init(interface, line6); + break; + + case LINE6_PODXTLIVE_POD: + ret = line6_pod_init(interface, line6); + break; + + case LINE6_PODXTLIVE_VARIAX: + ret = line6_variax_init(interface, line6); + break; + + case LINE6_VARIAX: + ret = line6_variax_init(interface, line6); + break; + + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: + ret = line6_toneport_init(interface, line6); + break; + + default: + MISSING_CASE; + ret = -ENODEV; + } + + if (ret < 0) + goto err_destruct; + + ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, + "usb_device"); + if (ret < 0) + goto err_destruct; + + /* creation of additional special files should go here */ + + dev_info(&interface->dev, "Line6 %s now attached\n", + line6->properties->name); + + /* increment reference counters: */ + usb_get_intf(interface); + usb_get_dev(usbdev); + + return 0; + +err_destruct: + line6_destruct(interface); +err_put: + return ret; +} + +/* + Line6 device disconnected. +*/ +static void line6_disconnect(struct usb_interface *interface) +{ + struct usb_line6 *line6; + struct usb_device *usbdev; + int interface_number; + + if (interface == NULL) + return; + usbdev = interface_to_usbdev(interface); + if (usbdev == NULL) + return; + + /* removal of additional special files should go here */ + + sysfs_remove_link(&interface->dev.kobj, "usb_device"); + + interface_number = interface->cur_altsetting->desc.bInterfaceNumber; + line6 = usb_get_intfdata(interface); + + if (line6 != NULL) { + if (line6->urb_listen != NULL) + line6_stop_listen(line6); + + if (usbdev != line6->usbdev) + dev_err(line6->ifcdev, + "driver bug: inconsistent usb device\n"); + + line6->disconnect(interface); + + dev_info(&interface->dev, "Line6 %s now disconnected\n", + line6->properties->name); + } + + line6_destruct(interface); + + /* decrement reference counters: */ + usb_put_intf(interface); + usb_put_dev(usbdev); +} + +#ifdef CONFIG_PM + +/* + Suspend Line6 device. +*/ +static int line6_suspend(struct usb_interface *interface, pm_message_t message) +{ + struct usb_line6 *line6 = usb_get_intfdata(interface); + struct snd_line6_pcm *line6pcm = line6->line6pcm; + + snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); + + if (line6->properties->capabilities & LINE6_CAP_CONTROL) + line6_stop_listen(line6); + + if (line6pcm != NULL) { + snd_pcm_suspend_all(line6pcm->pcm); + line6_pcm_disconnect(line6pcm); + line6pcm->flags = 0; + } + + return 0; +} + +/* + Resume Line6 device. +*/ +static int line6_resume(struct usb_interface *interface) +{ + struct usb_line6 *line6 = usb_get_intfdata(interface); + + if (line6->properties->capabilities & LINE6_CAP_CONTROL) + line6_start_listen(line6); + + snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); + return 0; +} + +/* + Resume Line6 device after reset. +*/ +static int line6_reset_resume(struct usb_interface *interface) +{ + struct usb_line6 *line6 = usb_get_intfdata(interface); + + switch (line6->type) { + case LINE6_PODSTUDIO_GX: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + case LINE6_TONEPORT_GX: + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_GUITARPORT: + line6_toneport_reset_resume((struct usb_line6_toneport *)line6); + + default: + break; + } + + return line6_resume(interface); +} + +#endif /* CONFIG_PM */ + +static struct usb_driver line6_driver = { + .name = DRIVER_NAME, + .probe = line6_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_reset_resume, +#endif + .id_table = line6_id_table, +}; + +module_usb_driver(line6_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h new file mode 100644 index 0000000..ad203f1 --- /dev/null +++ b/sound/usb/line6/driver.h @@ -0,0 +1,228 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef DRIVER_H +#define DRIVER_H + +#include +#include +#include + +#include "midi.h" + +#define DRIVER_NAME "line6usb" + +enum line6_device_type { + LINE6_BASSPODXT, + LINE6_BASSPODXTLIVE, + LINE6_BASSPODXTPRO, + LINE6_GUITARPORT, + LINE6_POCKETPOD, + LINE6_PODHD300, + LINE6_PODHD400, + LINE6_PODHD500_0, + LINE6_PODHD500_1, + LINE6_PODSTUDIO_GX, + LINE6_PODSTUDIO_UX1, + LINE6_PODSTUDIO_UX2, + LINE6_PODXT, + LINE6_PODXTLIVE_POD, + LINE6_PODXTLIVE_VARIAX, + LINE6_PODXTPRO, + LINE6_TONEPORT_GX, + LINE6_TONEPORT_UX1, + LINE6_TONEPORT_UX2, + LINE6_VARIAX +}; + +#define LINE6_TIMEOUT 1 +#define LINE6_BUFSIZE_LISTEN 32 +#define LINE6_MESSAGE_MAXLEN 256 + +/* + Line6 MIDI control commands +*/ +#define LINE6_PARAM_CHANGE 0xb0 +#define LINE6_PROGRAM_CHANGE 0xc0 +#define LINE6_SYSEX_BEGIN 0xf0 +#define LINE6_SYSEX_END 0xf7 +#define LINE6_RESET 0xff + +/* + MIDI channel for messages initiated by the host + (and eventually echoed back by the device) +*/ +#define LINE6_CHANNEL_HOST 0x00 + +/* + MIDI channel for messages initiated by the device +*/ +#define LINE6_CHANNEL_DEVICE 0x02 + +#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */ + +#define LINE6_CHANNEL_MASK 0x0f + +#define MISSING_CASE \ + pr_err("line6usb driver bug: missing case in %s:%d\n", \ + __FILE__, __LINE__) + +#define CHECK_RETURN(x) \ +do { \ + err = x; \ + if (err < 0) \ + return err; \ +} while (0) + +#define CHECK_STARTUP_PROGRESS(x, n) \ +do { \ + if ((x) >= (n)) \ + return; \ + x = (n); \ +} while (0) + +extern const unsigned char line6_midi_id[3]; + +static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; +static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; + +/** + Common properties of Line6 devices. +*/ +struct line6_properties { + /** + Card id string (maximum 16 characters). + This can be used to address the device in ALSA programs as + "default:CARD=" + */ + const char *id; + + /** + Card short name (maximum 32 characters). + */ + const char *name; + + /** + Bit vector defining this device's capabilities in the + line6usb driver. + */ + int capabilities; + + int altsetting; + + unsigned ep_ctrl_r; + unsigned ep_ctrl_w; + unsigned ep_audio_r; + unsigned ep_audio_w; +}; + +/** + Common data shared by all Line6 devices. + Corresponds to a pair of USB endpoints. +*/ +struct usb_line6 { + /** + USB device. + */ + struct usb_device *usbdev; + + /** + Device type. + */ + enum line6_device_type type; + + /** + Properties. + */ + const struct line6_properties *properties; + + /** + Interval (ms). + */ + int interval; + + /** + Maximum size of USB packet. + */ + int max_packet_size; + + /** + Device representing the USB interface. + */ + struct device *ifcdev; + + /** + Line6 sound card data structure. + Each device has at least MIDI or PCM. + */ + struct snd_card *card; + + /** + Line6 PCM device data structure. + */ + struct snd_line6_pcm *line6pcm; + + /** + Line6 MIDI device data structure. + */ + struct snd_line6_midi *line6midi; + + /** + URB for listening to PODxt Pro control endpoint. + */ + struct urb *urb_listen; + + /** + Buffer for listening to PODxt Pro control endpoint. + */ + unsigned char *buffer_listen; + + /** + Buffer for message to be processed. + */ + unsigned char *buffer_message; + + /** + Length of message to be processed. + */ + int message_length; + + void (*process_message)(struct usb_line6 *); + void (*disconnect)(struct usb_interface *); +}; + +extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, + int code2, int size); +extern ssize_t line6_nop_read(struct device *dev, + struct device_attribute *attr, char *buf); +extern int line6_read_data(struct usb_line6 *line6, int address, void *data, + size_t datalen); +extern int line6_read_serial_number(struct usb_line6 *line6, + int *serial_number); +extern int line6_send_program(struct usb_line6 *line6, u8 value); +extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, + int size); +extern int line6_send_raw_message_async(struct usb_line6 *line6, + const char *buffer, int size); +extern int line6_send_sysex_message(struct usb_line6 *line6, + const char *buffer, int size); +extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +extern void line6_start_timer(struct timer_list *timer, unsigned int msecs, + void (*function)(unsigned long), + unsigned long data); +extern int line6_transmit_parameter(struct usb_line6 *line6, int param, + u8 value); +extern int line6_version_request_async(struct usb_line6 *line6); +extern int line6_write_data(struct usb_line6 *line6, int address, void *data, + size_t datalen); + +#endif diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c new file mode 100644 index 0000000..c9d725a --- /dev/null +++ b/sound/usb/line6/midi.c @@ -0,0 +1,321 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include +#include + +#include "audio.h" +#include "driver.h" +#include "midi.h" +#include "pod.h" +#include "usbdefs.h" + +#define line6_rawmidi_substream_midi(substream) \ + ((struct snd_line6_midi *)((substream)->rmidi->private_data)) + +static int send_midi_async(struct usb_line6 *line6, unsigned char *data, + int length); + +/* + Pass data received via USB to MIDI. +*/ +void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, + int length) +{ + if (line6->line6midi->substream_receive) + snd_rawmidi_receive(line6->line6midi->substream_receive, + data, length); +} + +/* + Read data from MIDI buffer and transmit them via USB. +*/ +static void line6_midi_transmit(struct snd_rawmidi_substream *substream) +{ + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + struct snd_line6_midi *line6midi = line6->line6midi; + struct midi_buffer *mb = &line6midi->midibuf_out; + unsigned long flags; + unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE]; + int req, done; + + spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags); + + for (;;) { + req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); + done = snd_rawmidi_transmit_peek(substream, chunk, req); + + if (done == 0) + break; + + line6_midibuf_write(mb, chunk, done); + snd_rawmidi_transmit_ack(substream, done); + } + + for (;;) { + done = line6_midibuf_read(mb, chunk, + LINE6_FALLBACK_MAXPACKETSIZE); + + if (done == 0) + break; + + send_midi_async(line6, chunk, done); + } + + spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); +} + +/* + Notification of completion of MIDI transmission. +*/ +static void midi_sent(struct urb *urb) +{ + unsigned long flags; + int status; + int num; + struct usb_line6 *line6 = (struct usb_line6 *)urb->context; + + status = urb->status; + kfree(urb->transfer_buffer); + usb_free_urb(urb); + + if (status == -ESHUTDOWN) + return; + + spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); + num = --line6->line6midi->num_active_send_urbs; + + if (num == 0) { + line6_midi_transmit(line6->line6midi->substream_transmit); + num = line6->line6midi->num_active_send_urbs; + } + + if (num == 0) + wake_up(&line6->line6midi->send_wait); + + spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); +} + +/* + Send an asynchronous MIDI message. + Assumes that line6->line6midi->send_urb_lock is held + (i.e., this function is serialized). +*/ +static int send_midi_async(struct usb_line6 *line6, unsigned char *data, + int length) +{ + struct urb *urb; + int retval; + unsigned char *transfer_buffer; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (urb == NULL) { + dev_err(line6->ifcdev, "Out of memory\n"); + return -ENOMEM; + } + + transfer_buffer = kmemdup(data, length, GFP_ATOMIC); + + if (transfer_buffer == NULL) { + usb_free_urb(urb); + dev_err(line6->ifcdev, "Out of memory\n"); + return -ENOMEM; + } + + usb_fill_int_urb(urb, line6->usbdev, + usb_sndbulkpipe(line6->usbdev, + line6->properties->ep_ctrl_w), + transfer_buffer, length, midi_sent, line6, + line6->interval); + urb->actual_length = 0; + retval = usb_submit_urb(urb, GFP_ATOMIC); + + if (retval < 0) { + dev_err(line6->ifcdev, "usb_submit_urb failed\n"); + usb_free_urb(urb); + return retval; + } + + ++line6->line6midi->num_active_send_urbs; + return 0; +} + +static int line6_midi_output_open(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static int line6_midi_output_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + unsigned long flags; + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + + line6->line6midi->substream_transmit = substream; + spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); + + if (line6->line6midi->num_active_send_urbs == 0) + line6_midi_transmit(substream); + + spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); +} + +static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) +{ + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + struct snd_line6_midi *midi = line6->line6midi; + + wait_event_interruptible(midi->send_wait, + midi->num_active_send_urbs == 0); +} + +static int line6_midi_input_open(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static int line6_midi_input_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + + if (up) + line6->line6midi->substream_receive = substream; + else + line6->line6midi->substream_receive = NULL; +} + +static struct snd_rawmidi_ops line6_midi_output_ops = { + .open = line6_midi_output_open, + .close = line6_midi_output_close, + .trigger = line6_midi_output_trigger, + .drain = line6_midi_output_drain, +}; + +static struct snd_rawmidi_ops line6_midi_input_ops = { + .open = line6_midi_input_open, + .close = line6_midi_input_close, + .trigger = line6_midi_input_trigger, +}; + +/* + Cleanup the Line6 MIDI device. +*/ +static void line6_cleanup_midi(struct snd_rawmidi *rmidi) +{ +} + +/* Create a MIDI device */ +static int snd_line6_new_midi(struct snd_line6_midi *line6midi) +{ + struct snd_rawmidi *rmidi; + int err; + + err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, + &rmidi); + if (err < 0) + return err; + + rmidi->private_data = line6midi; + rmidi->private_free = line6_cleanup_midi; + strcpy(rmidi->id, line6midi->line6->properties->id); + strcpy(rmidi->name, line6midi->line6->properties->name); + + rmidi->info_flags = + SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &line6_midi_output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &line6_midi_input_ops); + return 0; +} + +/* MIDI device destructor */ +static int snd_line6_midi_free(struct snd_device *device) +{ + struct snd_line6_midi *line6midi = device->device_data; + + line6_midibuf_destroy(&line6midi->midibuf_in); + line6_midibuf_destroy(&line6midi->midibuf_out); + return 0; +} + +/* + Initialize the Line6 MIDI subsystem. +*/ +int line6_init_midi(struct usb_line6 *line6) +{ + static struct snd_device_ops midi_ops = { + .dev_free = snd_line6_midi_free, + }; + + int err; + struct snd_line6_midi *line6midi; + + if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { + /* skip MIDI initialization and report success */ + return 0; + } + + line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); + + if (line6midi == NULL) + return -ENOMEM; + + err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); + if (err < 0) { + kfree(line6midi); + return err; + } + + err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); + if (err < 0) { + kfree(line6midi->midibuf_in.buf); + kfree(line6midi); + return err; + } + + line6midi->line6 = line6; + line6->line6midi = line6midi; + + err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, + &midi_ops); + if (err < 0) + return err; + + err = snd_line6_new_midi(line6midi); + if (err < 0) + return err; + + init_waitqueue_head(&line6midi->send_wait); + spin_lock_init(&line6midi->send_urb_lock); + spin_lock_init(&line6midi->midi_transmit_lock); + return 0; +} diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h new file mode 100644 index 0000000..78f903f --- /dev/null +++ b/sound/usb/line6/midi.h @@ -0,0 +1,72 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef MIDI_H +#define MIDI_H + +#include + +#include "midibuf.h" + +#define MIDI_BUFFER_SIZE 1024 + +struct snd_line6_midi { + /** + Pointer back to the Line6 driver data structure. + */ + struct usb_line6 *line6; + + /** + MIDI substream for receiving (or NULL if not active). + */ + struct snd_rawmidi_substream *substream_receive; + + /** + MIDI substream for transmitting (or NULL if not active). + */ + struct snd_rawmidi_substream *substream_transmit; + + /** + Number of currently active MIDI send URBs. + */ + int num_active_send_urbs; + + /** + Spin lock to protect updates of send_urb. + */ + spinlock_t send_urb_lock; + + /** + Spin lock to protect MIDI buffer handling. + */ + spinlock_t midi_transmit_lock; + + /** + Wait queue for MIDI transmission. + */ + wait_queue_head_t send_wait; + + /** + Buffer for incoming MIDI stream. + */ + struct midi_buffer midibuf_in; + + /** + Buffer for outgoing MIDI stream. + */ + struct midi_buffer midibuf_out; +}; + +extern int line6_init_midi(struct usb_line6 *line6); +extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, + int length); + +#endif diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c new file mode 100644 index 0000000..1ff8569 --- /dev/null +++ b/sound/usb/line6/midibuf.c @@ -0,0 +1,270 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include + +#include "midibuf.h" + +static int midibuf_message_length(unsigned char code) +{ + int message_length; + + if (code < 0x80) + message_length = -1; + else if (code < 0xf0) { + static const int length[] = { 3, 3, 3, 3, 2, 2, 3 }; + + message_length = length[(code >> 4) - 8]; + } else { + /* + Note that according to the MIDI specification 0xf2 is + the "Song Position Pointer", but this is used by Line6 + to send sysex messages to the host. + */ + static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1, + 1, 1, 1, -1, 1, 1 + }; + message_length = length[code & 0x0f]; + } + + return message_length; +} + +static int midibuf_is_empty(struct midi_buffer *this) +{ + return (this->pos_read == this->pos_write) && !this->full; +} + +static int midibuf_is_full(struct midi_buffer *this) +{ + return this->full; +} + +void line6_midibuf_reset(struct midi_buffer *this) +{ + this->pos_read = this->pos_write = this->full = 0; + this->command_prev = -1; +} + +int line6_midibuf_init(struct midi_buffer *this, int size, int split) +{ + this->buf = kmalloc(size, GFP_KERNEL); + + if (this->buf == NULL) + return -ENOMEM; + + this->size = size; + this->split = split; + line6_midibuf_reset(this); + return 0; +} + +void line6_midibuf_status(struct midi_buffer *this) +{ + pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n", + this->size, this->split, this->pos_read, this->pos_write, + this->full, this->command_prev); +} + +int line6_midibuf_bytes_free(struct midi_buffer *this) +{ + return + midibuf_is_full(this) ? + 0 : + (this->pos_read - this->pos_write + this->size - 1) % this->size + + 1; +} + +int line6_midibuf_bytes_used(struct midi_buffer *this) +{ + return + midibuf_is_empty(this) ? + 0 : + (this->pos_write - this->pos_read + this->size - 1) % this->size + + 1; +} + +int line6_midibuf_write(struct midi_buffer *this, unsigned char *data, + int length) +{ + int bytes_free; + int length1, length2; + int skip_active_sense = 0; + + if (midibuf_is_full(this) || (length <= 0)) + return 0; + + /* skip trailing active sense */ + if (data[length - 1] == 0xfe) { + --length; + skip_active_sense = 1; + } + + bytes_free = line6_midibuf_bytes_free(this); + + if (length > bytes_free) + length = bytes_free; + + if (length > 0) { + length1 = this->size - this->pos_write; + + if (length < length1) { + /* no buffer wraparound */ + memcpy(this->buf + this->pos_write, data, length); + this->pos_write += length; + } else { + /* buffer wraparound */ + length2 = length - length1; + memcpy(this->buf + this->pos_write, data, length1); + memcpy(this->buf, data + length1, length2); + this->pos_write = length2; + } + + if (this->pos_write == this->pos_read) + this->full = 1; + } + + return length + skip_active_sense; +} + +int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, + int length) +{ + int bytes_used; + int length1, length2; + int command; + int midi_length; + int repeat = 0; + int i; + + /* we need to be able to store at least a 3 byte MIDI message */ + if (length < 3) + return -EINVAL; + + if (midibuf_is_empty(this)) + return 0; + + bytes_used = line6_midibuf_bytes_used(this); + + if (length > bytes_used) + length = bytes_used; + + length1 = this->size - this->pos_read; + + /* check MIDI command length */ + command = this->buf[this->pos_read]; + + if (command & 0x80) { + midi_length = midibuf_message_length(command); + this->command_prev = command; + } else { + if (this->command_prev > 0) { + int midi_length_prev = + midibuf_message_length(this->command_prev); + + if (midi_length_prev > 0) { + midi_length = midi_length_prev - 1; + repeat = 1; + } else + midi_length = -1; + } else + midi_length = -1; + } + + if (midi_length < 0) { + /* search for end of message */ + if (length < length1) { + /* no buffer wraparound */ + for (i = 1; i < length; ++i) + if (this->buf[this->pos_read + i] & 0x80) + break; + + midi_length = i; + } else { + /* buffer wraparound */ + length2 = length - length1; + + for (i = 1; i < length1; ++i) + if (this->buf[this->pos_read + i] & 0x80) + break; + + if (i < length1) + midi_length = i; + else { + for (i = 0; i < length2; ++i) + if (this->buf[i] & 0x80) + break; + + midi_length = length1 + i; + } + } + + if (midi_length == length) + midi_length = -1; /* end of message not found */ + } + + if (midi_length < 0) { + if (!this->split) + return 0; /* command is not yet complete */ + } else { + if (length < midi_length) + return 0; /* command is not yet complete */ + + length = midi_length; + } + + if (length < length1) { + /* no buffer wraparound */ + memcpy(data + repeat, this->buf + this->pos_read, length); + this->pos_read += length; + } else { + /* buffer wraparound */ + length2 = length - length1; + memcpy(data + repeat, this->buf + this->pos_read, length1); + memcpy(data + repeat + length1, this->buf, length2); + this->pos_read = length2; + } + + if (repeat) + data[0] = this->command_prev; + + this->full = 0; + return length + repeat; +} + +int line6_midibuf_ignore(struct midi_buffer *this, int length) +{ + int bytes_used = line6_midibuf_bytes_used(this); + + if (length > bytes_used) + length = bytes_used; + + this->pos_read = (this->pos_read + length) % this->size; + this->full = 0; + return length; +} + +int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask) +{ + int cmd = this->command_prev; + + if ((cmd >= 0x80) && (cmd < 0xf0)) + if ((mask & (1 << (cmd & 0x0f))) == 0) + return 1; + + return 0; +} + +void line6_midibuf_destroy(struct midi_buffer *this) +{ + kfree(this->buf); + this->buf = NULL; +} diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h new file mode 100644 index 0000000..707482b --- /dev/null +++ b/sound/usb/line6/midibuf.h @@ -0,0 +1,38 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef MIDIBUF_H +#define MIDIBUF_H + +struct midi_buffer { + unsigned char *buf; + int size; + int split; + int pos_read, pos_write; + int full; + int command_prev; +}; + +extern int line6_midibuf_bytes_used(struct midi_buffer *mb); +extern int line6_midibuf_bytes_free(struct midi_buffer *mb); +extern void line6_midibuf_destroy(struct midi_buffer *mb); +extern int line6_midibuf_ignore(struct midi_buffer *mb, int length); +extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split); +extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data, + int length); +extern void line6_midibuf_reset(struct midi_buffer *mb); +extern int line6_midibuf_skip_message(struct midi_buffer *mb, + unsigned short mask); +extern void line6_midibuf_status(struct midi_buffer *mb); +extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data, + int length); + +#endif diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c new file mode 100644 index 0000000..6d4e5cd --- /dev/null +++ b/sound/usb/line6/pcm.c @@ -0,0 +1,527 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include +#include +#include + +#include "audio.h" +#include "capture.h" +#include "driver.h" +#include "playback.h" +#include "pod.h" + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + +static struct snd_line6_pcm *dev2pcm(struct device *dev) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6 *line6 = usb_get_intfdata(interface); + struct snd_line6_pcm *line6pcm = line6->line6pcm; + return line6pcm; +} + +/* + "read" request on "impulse_volume" special file. +*/ +static ssize_t impulse_volume_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume); +} + +/* + "write" request on "impulse_volume" special file. +*/ +static ssize_t impulse_volume_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_line6_pcm *line6pcm = dev2pcm(dev); + int value; + int ret; + + ret = kstrtoint(buf, 10, &value); + if (ret < 0) + return ret; + + line6pcm->impulse_volume = value; + + if (value > 0) + line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); + else + line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); + + return count; +} +static DEVICE_ATTR_RW(impulse_volume); + +/* + "read" request on "impulse_period" special file. +*/ +static ssize_t impulse_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period); +} + +/* + "write" request on "impulse_period" special file. +*/ +static ssize_t impulse_period_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int value; + int ret; + + ret = kstrtoint(buf, 10, &value); + if (ret < 0) + return ret; + + dev2pcm(dev)->impulse_period = value; + return count; +} +static DEVICE_ATTR_RW(impulse_period); + +#endif + +static bool test_flags(unsigned long flags0, unsigned long flags1, + unsigned long mask) +{ + return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); +} + +int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) +{ + unsigned long flags_old, flags_new, flags_final; + int err; + + do { + flags_old = ACCESS_ONCE(line6pcm->flags); + flags_new = flags_old | channels; + } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); + + flags_final = flags_old; + + line6pcm->prev_fbuf = NULL; + + if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { + /* Invoked multiple times in a row so allocate once only */ + if (!line6pcm->buffer_in) { + line6pcm->buffer_in = + kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + if (!line6pcm->buffer_in) { + err = -ENOMEM; + goto pcm_acquire_error; + } + + flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; + } + } + + if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { + /* + Waiting for completion of active URBs in the stop handler is + a bug, we therefore report an error if capturing is restarted + too soon. + */ + if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { + dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); + return -EBUSY; + } + + line6pcm->count_in = 0; + line6pcm->prev_fsize = 0; + err = line6_submit_audio_in_all_urbs(line6pcm); + + if (err < 0) + goto pcm_acquire_error; + + flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; + } + + if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { + /* Invoked multiple times in a row so allocate once only */ + if (!line6pcm->buffer_out) { + line6pcm->buffer_out = + kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + if (!line6pcm->buffer_out) { + err = -ENOMEM; + goto pcm_acquire_error; + } + + flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; + } + } + + if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { + /* + See comment above regarding PCM restart. + */ + if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { + dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); + return -EBUSY; + } + + line6pcm->count_out = 0; + err = line6_submit_audio_out_all_urbs(line6pcm); + + if (err < 0) + goto pcm_acquire_error; + + flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; + } + + return 0; + +pcm_acquire_error: + /* + If not all requested resources/streams could be obtained, release + those which were successfully obtained (if any). + */ + line6_pcm_release(line6pcm, flags_final & channels); + return err; +} + +int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) +{ + unsigned long flags_old, flags_new; + + do { + flags_old = ACCESS_ONCE(line6pcm->flags); + flags_new = flags_old & ~channels; + } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); + + if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) + line6_unlink_audio_in_urbs(line6pcm); + + if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { + line6_wait_clear_audio_in_urbs(line6pcm); + line6_free_capture_buffer(line6pcm); + } + + if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) + line6_unlink_audio_out_urbs(line6pcm); + + if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { + line6_wait_clear_audio_out_urbs(line6pcm); + line6_free_playback_buffer(line6pcm); + } + + return 0; +} + +/* trigger callback */ +int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct snd_pcm_substream *s; + int err; + unsigned long flags; + + spin_lock_irqsave(&line6pcm->lock_trigger, flags); + clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); + + snd_pcm_group_for_each_entry(s, substream) { + switch (s->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + err = snd_line6_playback_trigger(line6pcm, cmd); + + if (err < 0) { + spin_unlock_irqrestore(&line6pcm->lock_trigger, + flags); + return err; + } + + break; + + case SNDRV_PCM_STREAM_CAPTURE: + err = snd_line6_capture_trigger(line6pcm, cmd); + + if (err < 0) { + spin_unlock_irqrestore(&line6pcm->lock_trigger, + flags); + return err; + } + + break; + + default: + dev_err(line6pcm->line6->ifcdev, + "Unknown stream direction %d\n", s->stream); + } + } + + spin_unlock_irqrestore(&line6pcm->lock_trigger, flags); + return 0; +} + +/* control info callback */ +static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 256; + return 0; +} + +/* control get callback */ +static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i; + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + for (i = 2; i--;) + ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; + + return 0; +} + +/* control put callback */ +static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i, changed = 0; + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + for (i = 2; i--;) + if (line6pcm->volume_playback[i] != + ucontrol->value.integer.value[i]) { + line6pcm->volume_playback[i] = + ucontrol->value.integer.value[i]; + changed = 1; + } + + return changed; +} + +/* control definition */ +static struct snd_kcontrol_new line6_control_playback = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_line6_control_playback_info, + .get = snd_line6_control_playback_get, + .put = snd_line6_control_playback_put +}; + +/* + Cleanup the PCM device. +*/ +static void line6_cleanup_pcm(struct snd_pcm *pcm) +{ + int i; + struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume); + device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period); +#endif + + for (i = LINE6_ISO_BUFFERS; i--;) { + if (line6pcm->urb_audio_out[i]) { + usb_kill_urb(line6pcm->urb_audio_out[i]); + usb_free_urb(line6pcm->urb_audio_out[i]); + } + if (line6pcm->urb_audio_in[i]) { + usb_kill_urb(line6pcm->urb_audio_in[i]); + usb_free_urb(line6pcm->urb_audio_in[i]); + } + } +} + +/* create a PCM device */ +static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) +{ + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(line6pcm->line6->card, + (char *)line6pcm->line6->properties->name, + 0, 1, 1, &pcm); + if (err < 0) + return err; + + pcm->private_data = line6pcm; + pcm->private_free = line6_cleanup_pcm; + line6pcm->pcm = pcm; + strcpy(pcm->name, line6pcm->line6->properties->name); + + /* set operators */ + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_line6_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); + + /* pre-allocation of buffers */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data + (GFP_KERNEL), 64 * 1024, + 128 * 1024); + + return 0; +} + +/* PCM device destructor */ +static int snd_line6_pcm_free(struct snd_device *device) +{ + return 0; +} + +/* + Stop substream if still running. +*/ +static void pcm_disconnect_substream(struct snd_pcm_substream *substream) +{ + if (substream->runtime && snd_pcm_running(substream)) { + snd_pcm_stream_lock_irq(substream); + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + snd_pcm_stream_unlock_irq(substream); + } +} + +/* + Stop PCM stream. +*/ +void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) +{ + pcm_disconnect_substream(get_substream + (line6pcm, SNDRV_PCM_STREAM_CAPTURE)); + pcm_disconnect_substream(get_substream + (line6pcm, SNDRV_PCM_STREAM_PLAYBACK)); + line6_unlink_wait_clear_audio_out_urbs(line6pcm); + line6_unlink_wait_clear_audio_in_urbs(line6pcm); +} + +/* + Create and register the PCM device and mixer entries. + Create URBs for playback and capture. +*/ +int line6_init_pcm(struct usb_line6 *line6, + struct line6_pcm_properties *properties) +{ + static struct snd_device_ops pcm_ops = { + .dev_free = snd_line6_pcm_free, + }; + + int err; + unsigned ep_read = line6->properties->ep_audio_r; + unsigned ep_write = line6->properties->ep_audio_w; + struct snd_line6_pcm *line6pcm; + + if (!(line6->properties->capabilities & LINE6_CAP_PCM)) + return 0; /* skip PCM initialization and report success */ + + line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); + + if (line6pcm == NULL) + return -ENOMEM; + + line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; + line6pcm->volume_monitor = 255; + line6pcm->line6 = line6; + + /* Read and write buffers are sized identically, so choose minimum */ + line6pcm->max_packet_size = min( + usb_maxpacket(line6->usbdev, + usb_rcvisocpipe(line6->usbdev, ep_read), 0), + usb_maxpacket(line6->usbdev, + usb_sndisocpipe(line6->usbdev, ep_write), 1)); + + line6pcm->properties = properties; + line6->line6pcm = line6pcm; + + /* PCM device: */ + err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops); + if (err < 0) + return err; + + err = snd_line6_new_pcm(line6pcm); + if (err < 0) + return err; + + spin_lock_init(&line6pcm->lock_audio_out); + spin_lock_init(&line6pcm->lock_audio_in); + spin_lock_init(&line6pcm->lock_trigger); + + err = line6_create_audio_out_urbs(line6pcm); + if (err < 0) + return err; + + err = line6_create_audio_in_urbs(line6pcm); + if (err < 0) + return err; + + /* mixer: */ + err = + snd_ctl_add(line6->card, + snd_ctl_new1(&line6_control_playback, line6pcm)); + if (err < 0) + return err; + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + /* impulse response test: */ + err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume); + if (err < 0) + return err; + + err = device_create_file(line6->ifcdev, &dev_attr_impulse_period); + if (err < 0) + return err; + + line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; +#endif + + return 0; +} + +/* prepare pcm callback */ +int snd_line6_prepare(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) + line6_unlink_wait_clear_audio_out_urbs(line6pcm); + + break; + + case SNDRV_PCM_STREAM_CAPTURE: + if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) + line6_unlink_wait_clear_audio_in_urbs(line6pcm); + + break; + + default: + MISSING_CASE; + } + + if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { + line6pcm->count_out = 0; + line6pcm->pos_out = 0; + line6pcm->pos_out_done = 0; + line6pcm->bytes_out = 0; + line6pcm->count_in = 0; + line6pcm->pos_in_done = 0; + line6pcm->bytes_in = 0; + } + + return 0; +} diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h new file mode 100644 index 0000000..7315e81 --- /dev/null +++ b/sound/usb/line6/pcm.h @@ -0,0 +1,374 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +/* + PCM interface to POD series devices. +*/ + +#ifndef PCM_H +#define PCM_H + +#include + +#include "driver.h" +#include "usbdefs.h" + +/* number of URBs */ +#define LINE6_ISO_BUFFERS 2 + +/* + number of USB frames per URB + The Line6 Windows driver always transmits two frames per packet, but + the Linux driver performs significantly better (i.e., lower latency) + with only one frame per packet. +*/ +#define LINE6_ISO_PACKETS 1 + +/* in a "full speed" device (such as the PODxt Pro) this means 1ms */ +#define LINE6_ISO_INTERVAL 1 + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE +#define LINE6_IMPULSE_DEFAULT_PERIOD 100 +#endif + +/* + Get substream from Line6 PCM data structure +*/ +#define get_substream(line6pcm, stream) \ + (line6pcm->pcm->streams[stream].substream) + +/* + PCM mode bits. + + There are several features of the Line6 USB driver which require PCM + data to be exchanged with the device: + *) PCM playback and capture via ALSA + *) software monitoring (for devices without hardware monitoring) + *) optional impulse response measurement + However, from the device's point of view, there is just a single + capture and playback stream, which must be shared between these + subsystems. It is therefore necessary to maintain the state of the + subsystems with respect to PCM usage. We define several constants of + the form LINE6_BIT_PCM___ with the + following meanings: + *) is one of + -) ALSA: PCM playback and capture via ALSA + -) MONITOR: software monitoring + -) IMPULSE: optional impulse response measurement + *) is one of + -) PLAYBACK: audio output (from host to device) + -) CAPTURE: audio input (from device to host) + *) is one of + -) BUFFER: buffer required by PCM data stream + -) STREAM: actual PCM data stream + + The subsystems call line6_pcm_acquire() to acquire the (shared) + resources needed for a particular operation (e.g., allocate the buffer + for ALSA playback or start the capture stream for software monitoring). + When a resource is no longer needed, it is released by calling + line6_pcm_release(). Buffer allocation and stream startup are handled + separately to allow the ALSA kernel driver to perform them at + appropriate places (since the callback which starts a PCM stream is not + allowed to sleep). +*/ +enum { + /* individual bit indices: */ + LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER, + LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, + LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER, + LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, + LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER, + LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, + LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, + LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, + LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, + LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, + LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, +#endif + LINE6_INDEX_PAUSE_PLAYBACK, + LINE6_INDEX_PREPARED, + +#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x + + /* individual bit masks: */ + LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), + LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), + LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER), + LINE6_BIT(PCM_ALSA_CAPTURE_STREAM), + LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER), + LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), + LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), + LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), + LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), + LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), + LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), +#endif + LINE6_BIT(PAUSE_PLAYBACK), + LINE6_BIT(PREPARED), + + /* combined bit masks (by operation): */ + LINE6_BITS_PCM_ALSA_BUFFER = + LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | + LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER, + + LINE6_BITS_PCM_ALSA_STREAM = + LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | + LINE6_BIT_PCM_ALSA_CAPTURE_STREAM, + + LINE6_BITS_PCM_MONITOR = + LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER | + LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM | + LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | + LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_BITS_PCM_IMPULSE = + LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | + LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | + LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | + LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, +#endif + + /* combined bit masks (by direction): */ + LINE6_BITS_PLAYBACK_BUFFER = +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | +#endif + LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | + LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, + + LINE6_BITS_PLAYBACK_STREAM = +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | +#endif + LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | + LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, + + LINE6_BITS_CAPTURE_BUFFER = +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | +#endif + LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | + LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, + + LINE6_BITS_CAPTURE_STREAM = +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | +#endif + LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | + LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, + + LINE6_BITS_STREAM = + LINE6_BITS_PLAYBACK_STREAM | + LINE6_BITS_CAPTURE_STREAM +}; + +struct line6_pcm_properties { + struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw; + struct snd_pcm_hw_constraint_ratdens snd_line6_rates; + int bytes_per_frame; +}; + +struct snd_line6_pcm { + /** + Pointer back to the Line6 driver data structure. + */ + struct usb_line6 *line6; + + /** + Properties. + */ + struct line6_pcm_properties *properties; + + /** + ALSA pcm stream + */ + struct snd_pcm *pcm; + + /** + URBs for audio playback. + */ + struct urb *urb_audio_out[LINE6_ISO_BUFFERS]; + + /** + URBs for audio capture. + */ + struct urb *urb_audio_in[LINE6_ISO_BUFFERS]; + + /** + Temporary buffer for playback. + Since the packet size is not known in advance, this buffer is + large enough to store maximum size packets. + */ + unsigned char *buffer_out; + + /** + Temporary buffer for capture. + Since the packet size is not known in advance, this buffer is + large enough to store maximum size packets. + */ + unsigned char *buffer_in; + + /** + Previously captured frame (for software monitoring). + */ + unsigned char *prev_fbuf; + + /** + Size of previously captured frame (for software monitoring). + */ + int prev_fsize; + + /** + Free frame position in the playback buffer. + */ + snd_pcm_uframes_t pos_out; + + /** + Count processed bytes for playback. + This is modulo period size (to determine when a period is + finished). + */ + unsigned bytes_out; + + /** + Counter to create desired playback sample rate. + */ + unsigned count_out; + + /** + Playback period size in bytes + */ + unsigned period_out; + + /** + Processed frame position in the playback buffer. + The contents of the output ring buffer have been consumed by + the USB subsystem (i.e., sent to the USB device) up to this + position. + */ + snd_pcm_uframes_t pos_out_done; + + /** + Count processed bytes for capture. + This is modulo period size (to determine when a period is + finished). + */ + unsigned bytes_in; + + /** + Counter to create desired capture sample rate. + */ + unsigned count_in; + + /** + Capture period size in bytes + */ + unsigned period_in; + + /** + Processed frame position in the capture buffer. + The contents of the output ring buffer have been consumed by + the USB subsystem (i.e., sent to the USB device) up to this + position. + */ + snd_pcm_uframes_t pos_in_done; + + /** + Bit mask of active playback URBs. + */ + unsigned long active_urb_out; + + /** + Maximum size of USB packet. + */ + int max_packet_size; + + /** + Bit mask of active capture URBs. + */ + unsigned long active_urb_in; + + /** + Bit mask of playback URBs currently being unlinked. + */ + unsigned long unlink_urb_out; + + /** + Bit mask of capture URBs currently being unlinked. + */ + unsigned long unlink_urb_in; + + /** + Spin lock to protect updates of the playback buffer positions (not + contents!) + */ + spinlock_t lock_audio_out; + + /** + Spin lock to protect updates of the capture buffer positions (not + contents!) + */ + spinlock_t lock_audio_in; + + /** + Spin lock to protect trigger. + */ + spinlock_t lock_trigger; + + /** + PCM playback volume (left and right). + */ + int volume_playback[2]; + + /** + PCM monitor volume. + */ + int volume_monitor; + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + /** + Volume of impulse response test signal (if zero, test is disabled). + */ + int impulse_volume; + + /** + Period of impulse response test signal. + */ + int impulse_period; + + /** + Counter for impulse response test signal. + */ + int impulse_count; +#endif + + /** + Several status bits (see LINE6_BIT_*). + */ + unsigned long flags; + + int last_frame_in, last_frame_out; +}; + +extern int line6_init_pcm(struct usb_line6 *line6, + struct line6_pcm_properties *properties); +extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); +extern int snd_line6_prepare(struct snd_pcm_substream *substream); +extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); +extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels); +extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels); + +#endif diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c new file mode 100644 index 0000000..da2e3b8 --- /dev/null +++ b/sound/usb/line6/playback.c @@ -0,0 +1,593 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include +#include + +#include "audio.h" +#include "capture.h" +#include "driver.h" +#include "pcm.h" +#include "pod.h" +#include "playback.h" + +/* + Software stereo volume control. +*/ +static void change_volume(struct urb *urb_out, int volume[], + int bytes_per_frame) +{ + int chn = 0; + + if (volume[0] == 256 && volume[1] == 256) + return; /* maximum volume - no change */ + + if (bytes_per_frame == 4) { + short *p, *buf_end; + + p = (short *)urb_out->transfer_buffer; + buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); + + for (; p < buf_end; ++p) { + *p = (*p * volume[chn & 1]) >> 8; + ++chn; + } + } else if (bytes_per_frame == 6) { + unsigned char *p, *buf_end; + + p = (unsigned char *)urb_out->transfer_buffer; + buf_end = p + urb_out->transfer_buffer_length; + + for (; p < buf_end; p += 3) { + int val; + + val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); + val = (val * volume[chn & 1]) >> 8; + p[0] = val; + p[1] = val >> 8; + p[2] = val >> 16; + ++chn; + } + } +} + +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + +/* + Create signal for impulse response test. +*/ +static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, + struct urb *urb_out, int bytes_per_frame) +{ + int frames = urb_out->transfer_buffer_length / bytes_per_frame; + + if (bytes_per_frame == 4) { + int i; + short *pi = (short *)line6pcm->prev_fbuf; + short *po = (short *)urb_out->transfer_buffer; + + for (i = 0; i < frames; ++i) { + po[0] = pi[0]; + po[1] = 0; + pi += 2; + po += 2; + } + } else if (bytes_per_frame == 6) { + int i, j; + unsigned char *pi = line6pcm->prev_fbuf; + unsigned char *po = urb_out->transfer_buffer; + + for (i = 0; i < frames; ++i) { + for (j = 0; j < bytes_per_frame / 2; ++j) + po[j] = pi[j]; + + for (; j < bytes_per_frame; ++j) + po[j] = 0; + + pi += bytes_per_frame; + po += bytes_per_frame; + } + } + if (--line6pcm->impulse_count <= 0) { + ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame - + 1] = + line6pcm->impulse_volume; + line6pcm->impulse_count = line6pcm->impulse_period; + } +} + +#endif + +/* + Add signal to buffer for software monitoring. +*/ +static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, + int volume, int bytes_per_frame) +{ + if (volume == 0) + return; /* zero volume - no change */ + + if (bytes_per_frame == 4) { + short *pi, *po, *buf_end; + + pi = (short *)signal; + po = (short *)urb_out->transfer_buffer; + buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); + + for (; po < buf_end; ++pi, ++po) + *po += (*pi * volume) >> 8; + } + + /* + We don't need to handle devices with 6 bytes per frame here + since they all support hardware monitoring. + */ +} + +/* + Find a free URB, prepare audio data, and submit URB. +*/ +static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) +{ + int index; + unsigned long flags; + int i, urb_size, urb_frames; + int ret; + const int bytes_per_frame = line6pcm->properties->bytes_per_frame; + const int frame_increment = + line6pcm->properties->snd_line6_rates.rats[0].num_min; + const int frame_factor = + line6pcm->properties->snd_line6_rates.rats[0].den * + (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); + struct urb *urb_out; + + spin_lock_irqsave(&line6pcm->lock_audio_out, flags); + index = + find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS); + + if (index < 0 || index >= LINE6_ISO_BUFFERS) { + spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); + return -EINVAL; + } + + urb_out = line6pcm->urb_audio_out[index]; + urb_size = 0; + + for (i = 0; i < LINE6_ISO_PACKETS; ++i) { + /* compute frame size for given sampling rate */ + int fsize = 0; + struct usb_iso_packet_descriptor *fout = + &urb_out->iso_frame_desc[i]; + + if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) + fsize = line6pcm->prev_fsize; + + if (fsize == 0) { + int n; + + line6pcm->count_out += frame_increment; + n = line6pcm->count_out / frame_factor; + line6pcm->count_out -= n * frame_factor; + fsize = n * bytes_per_frame; + } + + fout->offset = urb_size; + fout->length = fsize; + urb_size += fsize; + } + + if (urb_size == 0) { + /* can't determine URB size */ + spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); + return -EINVAL; + } + + urb_frames = urb_size / bytes_per_frame; + urb_out->transfer_buffer = + line6pcm->buffer_out + + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; + urb_out->transfer_buffer_length = urb_size; + urb_out->context = line6pcm; + + if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) && + !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) { + struct snd_pcm_runtime *runtime = + get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; + + if (line6pcm->pos_out + urb_frames > runtime->buffer_size) { + /* + The transferred area goes over buffer boundary, + copy the data to the temp buffer. + */ + int len; + + len = runtime->buffer_size - line6pcm->pos_out; + + if (len > 0) { + memcpy(urb_out->transfer_buffer, + runtime->dma_area + + line6pcm->pos_out * bytes_per_frame, + len * bytes_per_frame); + memcpy(urb_out->transfer_buffer + + len * bytes_per_frame, runtime->dma_area, + (urb_frames - len) * bytes_per_frame); + } else + dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", + len); + } else { + memcpy(urb_out->transfer_buffer, + runtime->dma_area + + line6pcm->pos_out * bytes_per_frame, + urb_out->transfer_buffer_length); + } + + line6pcm->pos_out += urb_frames; + if (line6pcm->pos_out >= runtime->buffer_size) + line6pcm->pos_out -= runtime->buffer_size; + } else { + memset(urb_out->transfer_buffer, 0, + urb_out->transfer_buffer_length); + } + + change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); + + if (line6pcm->prev_fbuf != NULL) { +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { + create_impulse_test_signal(line6pcm, urb_out, + bytes_per_frame); + if (line6pcm->flags & + LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) { + line6_capture_copy(line6pcm, + urb_out->transfer_buffer, + urb_out-> + transfer_buffer_length); + line6_capture_check_period(line6pcm, + urb_out->transfer_buffer_length); + } + } else { +#endif + if (! + (line6pcm->line6-> + properties->capabilities & LINE6_CAP_HWMON) + && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) + && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)) + add_monitor_signal(urb_out, line6pcm->prev_fbuf, + line6pcm->volume_monitor, + bytes_per_frame); +#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE + } +#endif + } + + ret = usb_submit_urb(urb_out, GFP_ATOMIC); + + if (ret == 0) + set_bit(index, &line6pcm->active_urb_out); + else + dev_err(line6pcm->line6->ifcdev, + "URB out #%d submission failed (%d)\n", index, ret); + + spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + return 0; +} + +/* + Submit all currently available playback URBs. +*/ +int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) +{ + int ret, i; + + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + ret = submit_audio_out_urb(line6pcm); + if (ret < 0) + return ret; + } + + return 0; +} + +/* + Unlink all currently active playback URBs. +*/ +void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) +{ + unsigned int i; + + for (i = LINE6_ISO_BUFFERS; i--;) { + if (test_bit(i, &line6pcm->active_urb_out)) { + if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { + struct urb *u = line6pcm->urb_audio_out[i]; + + usb_unlink_urb(u); + } + } + } +} + +/* + Wait until unlinking of all currently active playback URBs has been + finished. +*/ +void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) +{ + int timeout = HZ; + unsigned int i; + int alive; + + do { + alive = 0; + for (i = LINE6_ISO_BUFFERS; i--;) { + if (test_bit(i, &line6pcm->active_urb_out)) + alive++; + } + if (!alive) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } while (--timeout > 0); + if (alive) + snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); +} + +/* + Unlink all currently active playback URBs, and wait for finishing. +*/ +void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) +{ + line6_unlink_audio_out_urbs(line6pcm); + line6_wait_clear_audio_out_urbs(line6pcm); +} + +void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) +{ + kfree(line6pcm->buffer_out); + line6pcm->buffer_out = NULL; +} + +/* + Callback for completed playback URB. +*/ +static void audio_out_callback(struct urb *urb) +{ + int i, index, length = 0, shutdown = 0; + unsigned long flags; + struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; + struct snd_pcm_substream *substream = + get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); + +#if USE_CLEAR_BUFFER_WORKAROUND + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); +#endif + + line6pcm->last_frame_out = urb->start_frame; + + /* find index of URB */ + for (index = LINE6_ISO_BUFFERS; index--;) + if (urb == line6pcm->urb_audio_out[index]) + break; + + if (index < 0) + return; /* URB has been unlinked asynchronously */ + + for (i = LINE6_ISO_PACKETS; i--;) + length += urb->iso_frame_desc[i].length; + + spin_lock_irqsave(&line6pcm->lock_audio_out, flags); + + if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { + struct snd_pcm_runtime *runtime = substream->runtime; + + line6pcm->pos_out_done += + length / line6pcm->properties->bytes_per_frame; + + if (line6pcm->pos_out_done >= runtime->buffer_size) + line6pcm->pos_out_done -= runtime->buffer_size; + } + + clear_bit(index, &line6pcm->active_urb_out); + + for (i = LINE6_ISO_PACKETS; i--;) + if (urb->iso_frame_desc[i].status == -EXDEV) { + shutdown = 1; + break; + } + + if (test_and_clear_bit(index, &line6pcm->unlink_urb_out)) + shutdown = 1; + + spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + + if (!shutdown) { + submit_audio_out_urb(line6pcm); + + if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, + &line6pcm->flags)) { + line6pcm->bytes_out += length; + if (line6pcm->bytes_out >= line6pcm->period_out) { + line6pcm->bytes_out %= line6pcm->period_out; + snd_pcm_period_elapsed(substream); + } + } + } +} + +/* open playback callback */ +static int snd_line6_playback_open(struct snd_pcm_substream *substream) +{ + int err; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + (&line6pcm-> + properties->snd_line6_rates)); + if (err < 0) + return err; + + runtime->hw = line6pcm->properties->snd_line6_playback_hw; + return 0; +} + +/* close playback callback */ +static int snd_line6_playback_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* hw_params playback callback */ +static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int ret; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + /* -- Florian Demski [FD] */ + /* don't ask me why, but this fixes the bug on my machine */ + if (line6pcm == NULL) { + if (substream->pcm == NULL) + return -ENOMEM; + if (substream->pcm->private_data == NULL) + return -ENOMEM; + substream->private_data = substream->pcm->private_data; + line6pcm = snd_pcm_substream_chip(substream); + } + /* -- [FD] end */ + + ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); + + if (ret < 0) + return ret; + + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) { + line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); + return ret; + } + + line6pcm->period_out = params_period_bytes(hw_params); + return 0; +} + +/* hw_free playback callback */ +static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); + return snd_pcm_lib_free_pages(substream); +} + +/* trigger playback callback */ +int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) +{ + int err; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: +#ifdef CONFIG_PM + case SNDRV_PCM_TRIGGER_RESUME: +#endif + err = line6_pcm_acquire(line6pcm, + LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); + + if (err < 0) + return err; + + break; + + case SNDRV_PCM_TRIGGER_STOP: +#ifdef CONFIG_PM + case SNDRV_PCM_TRIGGER_SUSPEND: +#endif + err = line6_pcm_release(line6pcm, + LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); + + if (err < 0) + return err; + + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* playback pointer callback */ +static snd_pcm_uframes_t +snd_line6_playback_pointer(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + return line6pcm->pos_out_done; +} + +/* playback operators */ +struct snd_pcm_ops snd_line6_playback_ops = { + .open = snd_line6_playback_open, + .close = snd_line6_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_line6_playback_hw_params, + .hw_free = snd_line6_playback_hw_free, + .prepare = snd_line6_prepare, + .trigger = snd_line6_trigger, + .pointer = snd_line6_playback_pointer, +}; + +int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) +{ + struct usb_line6 *line6 = line6pcm->line6; + int i; + + /* create audio URBs and fill in constant values: */ + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + struct urb *urb; + + /* URB for audio out: */ + urb = line6pcm->urb_audio_out[i] = + usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); + + if (urb == NULL) { + dev_err(line6->ifcdev, "Out of memory\n"); + return -ENOMEM; + } + + urb->dev = line6->usbdev; + urb->pipe = + usb_sndisocpipe(line6->usbdev, + line6->properties->ep_audio_w & + USB_ENDPOINT_NUMBER_MASK); + urb->transfer_flags = URB_ISO_ASAP; + urb->start_frame = -1; + urb->number_of_packets = LINE6_ISO_PACKETS; + urb->interval = LINE6_ISO_INTERVAL; + urb->error_count = 0; + urb->complete = audio_out_callback; + } + + return 0; +} diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h new file mode 100644 index 0000000..743bd6f --- /dev/null +++ b/sound/usb/line6/playback.h @@ -0,0 +1,41 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef PLAYBACK_H +#define PLAYBACK_H + +#include + +#include "driver.h" + +/* + * When the TonePort is used with jack in full duplex mode and the outputs are + * not connected, the software monitor produces an ugly noise since everything + * written to the output buffer (i.e., the input signal) will be repeated in + * the next period (sounds like a delay effect). As a workaround, the output + * buffer is cleared after the data have been read, but there must be a better + * solution. Until one is found, this workaround can be used to fix the + * problem. + */ +#define USE_CLEAR_BUFFER_WORKAROUND 1 + +extern struct snd_pcm_ops snd_line6_playback_ops; + +extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm); +extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm + *line6pcm); +extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm); +extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); + +#endif diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c new file mode 100644 index 0000000..85a4363 --- /dev/null +++ b/sound/usb/line6/pod.c @@ -0,0 +1,453 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include +#include + +#include "audio.h" +#include "capture.h" +#include "driver.h" +#include "playback.h" +#include "pod.h" + +#define POD_SYSEX_CODE 3 +#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ + +/* *INDENT-OFF* */ + +enum { + POD_SYSEX_SAVE = 0x24, + POD_SYSEX_SYSTEM = 0x56, + POD_SYSEX_SYSTEMREQ = 0x57, + /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ + POD_SYSEX_STORE = 0x71, + POD_SYSEX_FINISH = 0x72, + POD_SYSEX_DUMPMEM = 0x73, + POD_SYSEX_DUMP = 0x74, + POD_SYSEX_DUMPREQ = 0x75 + + /* dumps entire internal memory of PODxt Pro */ + /* POD_SYSEX_DUMPMEM2 = 0x76 */ +}; + +enum { + POD_MONITOR_LEVEL = 0x04, + POD_SYSTEM_INVALID = 0x10000 +}; + +/* *INDENT-ON* */ + +enum { + POD_DUMP_MEMORY = 2 +}; + +enum { + POD_BUSY_READ, + POD_BUSY_WRITE, + POD_CHANNEL_DIRTY, + POD_SAVE_PRESSED, + POD_BUSY_MIDISEND +}; + +static struct snd_ratden pod_ratden = { + .num_min = 78125, + .num_max = 78125, + .num_step = 1, + .den = 2 +}; + +static struct line6_pcm_properties pod_pcm_properties = { + .snd_line6_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 39062, + .rate_max = 39063, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 39062, + .rate_max = 39063, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_rates = { + .nrats = 1, + .rats = &pod_ratden}, + .bytes_per_frame = POD_BYTES_PER_FRAME +}; + +static const char pod_version_header[] = { + 0xf2, 0x7e, 0x7f, 0x06, 0x02 +}; + +/* forward declarations: */ +static void pod_startup2(unsigned long data); +static void pod_startup3(struct usb_line6_pod *pod); + +static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, + int size) +{ + return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, + size); +} + +/* + Process a completely received message. +*/ +static void line6_pod_process_message(struct usb_line6 *line6) +{ + struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; + const unsigned char *buf = pod->line6.buffer_message; + + if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { + pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; + pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | + (int) buf[10]; + pod_startup3(pod); + return; + } + + /* Only look for sysex messages from this device */ + if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && + buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { + return; + } + if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) + return; + + if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) { + short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | + ((int)buf[9] << 4) | (int)buf[10]; + pod->monitor_level = value; + } +} + +/* + Send system parameter (from integer). +*/ +static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, + int code) +{ + char *sysex; + static const int size = 5; + + sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); + if (!sysex) + return -ENOMEM; + sysex[SYSEX_DATA_OFS] = code; + sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; + sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; + sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; + sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; + line6_send_sysex_message(&pod->line6, sysex, size); + kfree(sysex); + return 0; +} + +/* + "read" request on "serial_number" special file. +*/ +static ssize_t serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + return sprintf(buf, "%d\n", pod->serial_number); +} + +/* + "read" request on "firmware_version" special file. +*/ +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, + pod->firmware_version % 100); +} + +/* + "read" request on "device_id" special file. +*/ +static ssize_t device_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + return sprintf(buf, "%d\n", pod->device_id); +} + +/* + POD startup procedure. + This is a sequence of functions with special requirements (e.g., must + not run immediately after initialization, must not run in interrupt + context). After the last one has finished, the device is ready to use. +*/ + +static void pod_startup1(struct usb_line6_pod *pod) +{ + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); + + /* delay startup procedure: */ + line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, + (unsigned long)pod); +} + +static void pod_startup2(unsigned long data) +{ + struct usb_line6_pod *pod = (struct usb_line6_pod *)data; + struct usb_line6 *line6 = &pod->line6; + + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); + + /* request firmware version: */ + line6_version_request_async(line6); +} + +static void pod_startup3(struct usb_line6_pod *pod) +{ + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); + + /* schedule work for global work queue: */ + schedule_work(&pod->startup_work); +} + +static void pod_startup4(struct work_struct *work) +{ + struct usb_line6_pod *pod = + container_of(work, struct usb_line6_pod, startup_work); + struct usb_line6 *line6 = &pod->line6; + + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); + + /* serial number: */ + line6_read_serial_number(&pod->line6, &pod->serial_number); + + /* ALSA audio interface: */ + line6_register_audio(line6); +} + +/* POD special files: */ +static DEVICE_ATTR_RO(device_id); +static DEVICE_ATTR_RO(firmware_version); +static DEVICE_ATTR_RO(serial_number); + +/* control info callback */ +static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 65535; + return 0; +} + +/* control get callback */ +static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; + + ucontrol->value.integer.value[0] = pod->monitor_level; + return 0; +} + +/* control put callback */ +static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; + + if (ucontrol->value.integer.value[0] == pod->monitor_level) + return 0; + + pod->monitor_level = ucontrol->value.integer.value[0]; + pod_set_system_param_int(pod, ucontrol->value.integer.value[0], + POD_MONITOR_LEVEL); + return 1; +} + +/* control definition */ +static struct snd_kcontrol_new pod_control_monitor = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitor Playback Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_pod_control_monitor_info, + .get = snd_pod_control_monitor_get, + .put = snd_pod_control_monitor_put +}; + +/* + POD destructor. +*/ +static void pod_destruct(struct usb_interface *interface) +{ + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + if (pod == NULL) + return; + line6_cleanup_audio(&pod->line6); + + del_timer(&pod->startup_timer); + cancel_work_sync(&pod->startup_work); +} + +/* + POD device disconnected. +*/ +static void line6_pod_disconnect(struct usb_interface *interface) +{ + struct usb_line6_pod *pod; + + if (interface == NULL) + return; + pod = usb_get_intfdata(interface); + + if (pod != NULL) { + struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; + struct device *dev = &interface->dev; + + if (line6pcm != NULL) + line6_pcm_disconnect(line6pcm); + + if (dev != NULL) { + /* remove sysfs entries: */ + device_remove_file(dev, &dev_attr_device_id); + device_remove_file(dev, &dev_attr_firmware_version); + device_remove_file(dev, &dev_attr_serial_number); + } + } + + pod_destruct(interface); +} + +/* + Create sysfs entries. +*/ +static int pod_create_files2(struct device *dev) +{ + int err; + + CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); + CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); + CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); + return 0; +} + +/* + Try to init POD device. +*/ +static int pod_try_init(struct usb_interface *interface, + struct usb_line6 *line6) +{ + int err; + struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; + + line6->process_message = line6_pod_process_message; + line6->disconnect = line6_pod_disconnect; + + init_timer(&pod->startup_timer); + INIT_WORK(&pod->startup_work, pod_startup4); + + if ((interface == NULL) || (pod == NULL)) + return -ENODEV; + + /* create sysfs entries: */ + err = pod_create_files2(&interface->dev); + if (err < 0) + return err; + + /* initialize audio system: */ + err = line6_init_audio(line6); + if (err < 0) + return err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &pod_pcm_properties); + if (err < 0) + return err; + + /* register monitor control: */ + err = snd_ctl_add(line6->card, + snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); + if (err < 0) + return err; + + /* + When the sound card is registered at this point, the PODxt Live + displays "Invalid Code Error 07", so we do it later in the event + handler. + */ + + if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { + pod->monitor_level = POD_SYSTEM_INVALID; + + /* initiate startup procedure: */ + pod_startup1(pod); + } + + return 0; +} + +/* + Init POD device (and clean up in case of failure). +*/ +int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) +{ + int err = pod_try_init(interface, line6); + + if (err < 0) + pod_destruct(interface); + + return err; +} diff --git a/sound/usb/line6/pod.h b/sound/usb/line6/pod.h new file mode 100644 index 0000000..87a8f0f --- /dev/null +++ b/sound/usb/line6/pod.h @@ -0,0 +1,92 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef POD_H +#define POD_H + +#include +#include +#include + +#include + +#include "driver.h" + +/* + Locate name in binary program dump +*/ +#define POD_NAME_OFFSET 0 +#define POD_NAME_LENGTH 16 + +/* + Other constants +*/ +#define POD_CONTROL_SIZE 0x80 +#define POD_BUFSIZE_DUMPREQ 7 +#define POD_STARTUP_DELAY 1000 + +/* + Stages of POD startup procedure +*/ +enum { + POD_STARTUP_INIT = 1, + POD_STARTUP_VERSIONREQ, + POD_STARTUP_WORKQUEUE, + POD_STARTUP_SETUP, + POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 +}; + +struct usb_line6_pod { + /** + Generic Line6 USB data. + */ + struct usb_line6 line6; + + /** + Instrument monitor level. + */ + int monitor_level; + + /** + Timer for device initializaton. + */ + struct timer_list startup_timer; + + /** + Work handler for device initializaton. + */ + struct work_struct startup_work; + + /** + Current progress in startup procedure. + */ + int startup_progress; + + /** + Serial number of device. + */ + int serial_number; + + /** + Firmware version (x 100). + */ + int firmware_version; + + /** + Device ID. + */ + int device_id; +}; + +extern int line6_pod_init(struct usb_interface *interface, + struct usb_line6 *line6); + +#endif diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c new file mode 100644 index 0000000..27c5402 --- /dev/null +++ b/sound/usb/line6/podhd.c @@ -0,0 +1,156 @@ +/* + * Line6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include + +#include "audio.h" +#include "driver.h" +#include "pcm.h" +#include "podhd.h" + +#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ + +static struct snd_ratden podhd_ratden = { + .num_min = 48000, + .num_max = 48000, + .num_step = 1, + .den = 1, +}; + +static struct line6_pcm_properties podhd_pcm_properties = { + .snd_line6_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_rates = { + .nrats = 1, + .rats = &podhd_ratden}, + .bytes_per_frame = PODHD_BYTES_PER_FRAME +}; + +/* + POD HD destructor. +*/ +static void podhd_destruct(struct usb_interface *interface) +{ + struct usb_line6_podhd *podhd = usb_get_intfdata(interface); + + if (podhd == NULL) + return; + line6_cleanup_audio(&podhd->line6); +} + +/* + POD HD device disconnected. +*/ +static void line6_podhd_disconnect(struct usb_interface *interface) +{ + struct usb_line6_podhd *podhd; + + if (interface == NULL) + return; + podhd = usb_get_intfdata(interface); + + if (podhd != NULL) { + struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; + + if (line6pcm != NULL) + line6_pcm_disconnect(line6pcm); + } + + podhd_destruct(interface); +} + +/* + Try to init POD HD device. +*/ +static int podhd_try_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd) +{ + int err; + struct usb_line6 *line6 = &podhd->line6; + + if ((interface == NULL) || (podhd == NULL)) + return -ENODEV; + + line6->disconnect = line6_podhd_disconnect; + + /* initialize audio system: */ + err = line6_init_audio(line6); + if (err < 0) + return err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &podhd_pcm_properties); + if (err < 0) + return err; + + /* register USB audio system: */ + err = line6_register_audio(line6); + return err; +} + +/* + Init POD HD device (and clean up in case of failure). +*/ +int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) +{ + struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; + int err = podhd_try_init(interface, podhd); + + if (err < 0) + podhd_destruct(interface); + + return err; +} diff --git a/sound/usb/line6/podhd.h b/sound/usb/line6/podhd.h new file mode 100644 index 0000000..a14f711 --- /dev/null +++ b/sound/usb/line6/podhd.h @@ -0,0 +1,29 @@ +/* + * Line6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef PODHD_H +#define PODHD_H + +#include + +#include "driver.h" + +struct usb_line6_podhd { + /** + Generic Line6 USB data. + */ + struct usb_line6 line6; +}; + +extern int line6_podhd_init(struct usb_interface *interface, + struct usb_line6 *line6); + +#endif /* PODHD_H */ diff --git a/sound/usb/line6/revision.h b/sound/usb/line6/revision.h new file mode 100644 index 0000000..b4eee2b --- /dev/null +++ b/sound/usb/line6/revision.h @@ -0,0 +1,4 @@ +#ifndef DRIVER_REVISION +/* current subversion revision */ +#define DRIVER_REVISION " (904)" +#endif diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c new file mode 100644 index 0000000..aae78d8 --- /dev/null +++ b/sound/usb/line6/toneport.c @@ -0,0 +1,465 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * Emil Myhrman (emil.myhrman@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#include + +#include "audio.h" +#include "capture.h" +#include "driver.h" +#include "playback.h" +#include "toneport.h" + +static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); + +#define TONEPORT_PCM_DELAY 1 + +static struct snd_ratden toneport_ratden = { + .num_min = 44100, + .num_max = 44100, + .num_step = 1, + .den = 1 +}; + +static struct line6_pcm_properties toneport_pcm_properties = { + .snd_line6_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 44100, + .rate_max = 44100, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 44100, + .rate_max = 44100, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_rates = { + .nrats = 1, + .rats = &toneport_ratden}, + .bytes_per_frame = 4 +}; + +/* + For the led on Guitarport. + Brightness goes from 0x00 to 0x26. Set a value above this to have led + blink. + (void cmd_0x02(byte red, byte green) +*/ +static int led_red = 0x00; +static int led_green = 0x26; + +static const struct { + const char *name; + int code; +} toneport_source_info[] = { + {"Microphone", 0x0a01}, + {"Line", 0x0801}, + {"Instrument", 0x0b01}, + {"Inst & Mic", 0x0901} +}; + +static bool toneport_has_led(enum line6_device_type type) +{ + return + (type == LINE6_GUITARPORT) || + (type == LINE6_TONEPORT_GX); + /* add your device here if you are missing support for the LEDs */ +} + +static void toneport_update_led(struct device *dev) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_toneport *tp = usb_get_intfdata(interface); + struct usb_line6 *line6; + + if (!tp) + return; + + line6 = &tp->line6; + if (line6) + toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002, + led_green); +} + +static ssize_t toneport_set_led_red(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + + retval = kstrtoint(buf, 10, &led_red); + if (retval) + return retval; + + toneport_update_led(dev); + return count; +} + +static ssize_t toneport_set_led_green(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + + retval = kstrtoint(buf, 10, &led_green); + if (retval) + return retval; + + toneport_update_led(dev); + return count; +} + +static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, + toneport_set_led_red); +static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, + toneport_set_led_green); + +static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) +{ + int ret; + + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(&usbdev->dev, "send failed (error %d)\n", ret); + return ret; + } + + return 0; +} + +/* monitor info callback */ +static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 256; + return 0; +} + +/* monitor get callback */ +static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = line6pcm->volume_monitor; + return 0; +} + +/* monitor put callback */ +static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) + return 0; + + line6pcm->volume_monitor = ucontrol->value.integer.value[0]; + + if (line6pcm->volume_monitor > 0) + line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); + else + line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); + + return 1; +} + +/* source info callback */ +static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + const int size = ARRAY_SIZE(toneport_source_info); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = size; + + if (uinfo->value.enumerated.item >= size) + uinfo->value.enumerated.item = size - 1; + + strcpy(uinfo->value.enumerated.name, + toneport_source_info[uinfo->value.enumerated.item].name); + + return 0; +} + +/* source get callback */ +static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_toneport *toneport = + (struct usb_line6_toneport *)line6pcm->line6; + ucontrol->value.enumerated.item[0] = toneport->source; + return 0; +} + +/* source put callback */ +static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_toneport *toneport = + (struct usb_line6_toneport *)line6pcm->line6; + unsigned int source; + + source = ucontrol->value.enumerated.item[0]; + if (source >= ARRAY_SIZE(toneport_source_info)) + return -EINVAL; + if (source == toneport->source) + return 0; + + toneport->source = source; + toneport_send_cmd(toneport->line6.usbdev, + toneport_source_info[source].code, 0x0000); + return 1; +} + +static void toneport_start_pcm(unsigned long arg) +{ + struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; + struct usb_line6 *line6 = &toneport->line6; + + line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); +} + +/* control definition */ +static struct snd_kcontrol_new toneport_control_monitor = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitor Playback Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_toneport_monitor_info, + .get = snd_toneport_monitor_get, + .put = snd_toneport_monitor_put +}; + +/* source selector definition */ +static struct snd_kcontrol_new toneport_control_source = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Capture Source", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_toneport_source_info, + .get = snd_toneport_source_get, + .put = snd_toneport_source_put +}; + +/* + Toneport destructor. +*/ +static void toneport_destruct(struct usb_interface *interface) +{ + struct usb_line6_toneport *toneport = usb_get_intfdata(interface); + + if (toneport == NULL) + return; + line6_cleanup_audio(&toneport->line6); +} + +/* + Setup Toneport device. +*/ +static void toneport_setup(struct usb_line6_toneport *toneport) +{ + int ticks; + struct usb_line6 *line6 = &toneport->line6; + struct usb_device *usbdev = line6->usbdev; + + /* sync time on device with host: */ + ticks = (int)get_seconds(); + line6_write_data(line6, 0x80c6, &ticks, 4); + + /* enable device: */ + toneport_send_cmd(usbdev, 0x0301, 0x0000); + + /* initialize source select: */ + switch (line6->type) { + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + toneport_send_cmd(usbdev, + toneport_source_info[toneport->source].code, + 0x0000); + default: + break; + } + + if (toneport_has_led(line6->type)) + toneport_update_led(&usbdev->dev); +} + +/* + Toneport device disconnected. +*/ +static void line6_toneport_disconnect(struct usb_interface *interface) +{ + struct usb_line6_toneport *toneport; + u16 idProduct; + + if (interface == NULL) + return; + + toneport = usb_get_intfdata(interface); + del_timer_sync(&toneport->timer); + idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); + + if (toneport_has_led(idProduct)) { + device_remove_file(&interface->dev, &dev_attr_led_red); + device_remove_file(&interface->dev, &dev_attr_led_green); + } + + if (toneport != NULL) { + struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; + + if (line6pcm != NULL) { + line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); + line6_pcm_disconnect(line6pcm); + } + } + + toneport_destruct(interface); +} + + +/* + Try to init Toneport device. +*/ +static int toneport_try_init(struct usb_interface *interface, + struct usb_line6 *line6) +{ + int err; + struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; + + if ((interface == NULL) || (toneport == NULL)) + return -ENODEV; + + line6->disconnect = line6_toneport_disconnect; + + /* initialize audio system: */ + err = line6_init_audio(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &toneport_pcm_properties); + if (err < 0) + return err; + + /* register monitor control: */ + err = snd_ctl_add(line6->card, + snd_ctl_new1(&toneport_control_monitor, + line6->line6pcm)); + if (err < 0) + return err; + + /* register source select control: */ + switch (line6->type) { + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + err = + snd_ctl_add(line6->card, + snd_ctl_new1(&toneport_control_source, + line6->line6pcm)); + if (err < 0) + return err; + + default: + break; + } + + /* register audio system: */ + err = line6_register_audio(line6); + if (err < 0) + return err; + + line6_read_serial_number(line6, &toneport->serial_number); + line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); + + if (toneport_has_led(line6->type)) { + CHECK_RETURN(device_create_file + (&interface->dev, &dev_attr_led_red)); + CHECK_RETURN(device_create_file + (&interface->dev, &dev_attr_led_green)); + } + + toneport_setup(toneport); + + init_timer(&toneport->timer); + toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ; + toneport->timer.function = toneport_start_pcm; + toneport->timer.data = (unsigned long)toneport; + add_timer(&toneport->timer); + + return 0; +} + +/* + Init Toneport device (and clean up in case of failure). +*/ +int line6_toneport_init(struct usb_interface *interface, + struct usb_line6 *line6) +{ + int err = toneport_try_init(interface, line6); + + if (err < 0) + toneport_destruct(interface); + + return err; +} + +/* + Resume Toneport device after reset. +*/ +void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) +{ + toneport_setup(toneport); +} diff --git a/sound/usb/line6/toneport.h b/sound/usb/line6/toneport.h new file mode 100644 index 0000000..8cb1442 --- /dev/null +++ b/sound/usb/line6/toneport.h @@ -0,0 +1,51 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef TONEPORT_H +#define TONEPORT_H + +#include +#include + +#include "driver.h" + +struct usb_line6_toneport { + /** + Generic Line6 USB data. + */ + struct usb_line6 line6; + + /** + Source selector. + */ + int source; + + /** + Serial number of device. + */ + int serial_number; + + /** + Firmware version (x 100). + */ + int firmware_version; + + /** + Timer for delayed PCM startup. + */ + struct timer_list timer; +}; + +extern int line6_toneport_init(struct usb_interface *interface, + struct usb_line6 *line6); +extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); + +#endif diff --git a/sound/usb/line6/usbdefs.h b/sound/usb/line6/usbdefs.h new file mode 100644 index 0000000..f4d080e --- /dev/null +++ b/sound/usb/line6/usbdefs.h @@ -0,0 +1,27 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef USBDEFS_H +#define USBDEFS_H + +#define USB_INTERVALS_PER_SECOND 1000 + +/* device supports settings parameter via USB */ +#define LINE6_CAP_CONTROL (1 << 0) +/* device supports PCM input/output via USB */ +#define LINE6_CAP_PCM (1 << 1) +/* device support hardware monitoring */ +#define LINE6_CAP_HWMON (1 << 2) + +#define LINE6_FALLBACK_INTERVAL 10 +#define LINE6_FALLBACK_MAXPACKETSIZE 16 + +#endif diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c new file mode 100644 index 0000000..b4a41b0 --- /dev/null +++ b/sound/usb/line6/variax.c @@ -0,0 +1,239 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include + +#include "audio.h" +#include "driver.h" +#include "variax.h" + +#define VARIAX_OFFSET_ACTIVATE 7 + +/* + This message is sent by the device during initialization and identifies + the connected guitar version. +*/ +static const char variax_init_version[] = { + 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, + 0x07, 0x00, 0x00, 0x00 +}; + +/* + This message is the last one sent by the device during initialization. +*/ +static const char variax_init_done[] = { + 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b +}; + +static const char variax_activate[] = { + 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, + 0xf7 +}; + +/* forward declarations: */ +static void variax_startup2(unsigned long data); +static void variax_startup4(unsigned long data); +static void variax_startup5(unsigned long data); + +static void variax_activate_async(struct usb_line6_variax *variax, int a) +{ + variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; + line6_send_raw_message_async(&variax->line6, variax->buffer_activate, + sizeof(variax_activate)); +} + +/* + Variax startup procedure. + This is a sequence of functions with special requirements (e.g., must + not run immediately after initialization, must not run in interrupt + context). After the last one has finished, the device is ready to use. +*/ + +static void variax_startup1(struct usb_line6_variax *variax) +{ + CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); + + /* delay startup procedure: */ + line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, + variax_startup2, (unsigned long)variax); +} + +static void variax_startup2(unsigned long data) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6 *line6 = &variax->line6; + + /* schedule another startup procedure until startup is complete: */ + if (variax->startup_progress >= VARIAX_STARTUP_LAST) + return; + + variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; + line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, + variax_startup2, (unsigned long)variax); + + /* request firmware version: */ + line6_version_request_async(line6); +} + +static void variax_startup3(struct usb_line6_variax *variax) +{ + CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); + + /* delay startup procedure: */ + line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, + variax_startup4, (unsigned long)variax); +} + +static void variax_startup4(unsigned long data) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + + CHECK_STARTUP_PROGRESS(variax->startup_progress, + VARIAX_STARTUP_ACTIVATE); + + /* activate device: */ + variax_activate_async(variax, 1); + line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, + variax_startup5, (unsigned long)variax); +} + +static void variax_startup5(unsigned long data) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + + CHECK_STARTUP_PROGRESS(variax->startup_progress, + VARIAX_STARTUP_WORKQUEUE); + + /* schedule work for global work queue: */ + schedule_work(&variax->startup_work); +} + +static void variax_startup6(struct work_struct *work) +{ + struct usb_line6_variax *variax = + container_of(work, struct usb_line6_variax, startup_work); + + CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); + + /* ALSA audio interface: */ + line6_register_audio(&variax->line6); +} + +/* + Process a completely received message. +*/ +static void line6_variax_process_message(struct usb_line6 *line6) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; + const unsigned char *buf = variax->line6.buffer_message; + + switch (buf[0]) { + case LINE6_RESET: + dev_info(variax->line6.ifcdev, "VARIAX reset\n"); + break; + + case LINE6_SYSEX_BEGIN: + if (memcmp(buf + 1, variax_init_version + 1, + sizeof(variax_init_version) - 1) == 0) { + variax_startup3(variax); + } else if (memcmp(buf + 1, variax_init_done + 1, + sizeof(variax_init_done) - 1) == 0) { + /* notify of complete initialization: */ + variax_startup4((unsigned long)variax); + } + break; + } +} + +/* + Variax destructor. +*/ +static void variax_destruct(struct usb_interface *interface) +{ + struct usb_line6_variax *variax = usb_get_intfdata(interface); + + if (variax == NULL) + return; + line6_cleanup_audio(&variax->line6); + + del_timer(&variax->startup_timer1); + del_timer(&variax->startup_timer2); + cancel_work_sync(&variax->startup_work); + + kfree(variax->buffer_activate); +} + +/* + Workbench device disconnected. +*/ +static void line6_variax_disconnect(struct usb_interface *interface) +{ + if (interface == NULL) + return; + + variax_destruct(interface); +} + +/* + Try to init workbench device. +*/ +static int variax_try_init(struct usb_interface *interface, + struct usb_line6 *line6) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; + int err; + + line6->process_message = line6_variax_process_message; + line6->disconnect = line6_variax_disconnect; + + init_timer(&variax->startup_timer1); + init_timer(&variax->startup_timer2); + INIT_WORK(&variax->startup_work, variax_startup6); + + if ((interface == NULL) || (variax == NULL)) + return -ENODEV; + + /* initialize USB buffers: */ + variax->buffer_activate = kmemdup(variax_activate, + sizeof(variax_activate), GFP_KERNEL); + + if (variax->buffer_activate == NULL) { + dev_err(&interface->dev, "Out of memory\n"); + return -ENOMEM; + } + + /* initialize audio system: */ + err = line6_init_audio(&variax->line6); + if (err < 0) + return err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(&variax->line6); + if (err < 0) + return err; + + /* initiate startup procedure: */ + variax_startup1(variax); + return 0; +} + +/* + Init workbench device (and clean up in case of failure). +*/ +int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) +{ + int err = variax_try_init(interface, line6); + + if (err < 0) + variax_destruct(interface); + + return err; +} diff --git a/sound/usb/line6/variax.h b/sound/usb/line6/variax.h new file mode 100644 index 0000000..dfb94e5 --- /dev/null +++ b/sound/usb/line6/variax.h @@ -0,0 +1,70 @@ +/* + * Line6 Linux USB driver - 0.9.1beta + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef VARIAX_H +#define VARIAX_H + +#include +#include +#include +#include + +#include "driver.h" + +#define VARIAX_STARTUP_DELAY1 1000 +#define VARIAX_STARTUP_DELAY3 100 +#define VARIAX_STARTUP_DELAY4 100 + +/* + Stages of Variax startup procedure +*/ +enum { + VARIAX_STARTUP_INIT = 1, + VARIAX_STARTUP_VERSIONREQ, + VARIAX_STARTUP_WAIT, + VARIAX_STARTUP_ACTIVATE, + VARIAX_STARTUP_WORKQUEUE, + VARIAX_STARTUP_SETUP, + VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 +}; + +struct usb_line6_variax { + /** + Generic Line6 USB data. + */ + struct usb_line6 line6; + + /** + Buffer for activation code. + */ + unsigned char *buffer_activate; + + /** + Handler for device initializaton. + */ + struct work_struct startup_work; + + /** + Timers for device initializaton. + */ + struct timer_list startup_timer1; + struct timer_list startup_timer2; + + /** + Current progress in startup procedure. + */ + int startup_progress; +}; + +extern int line6_variax_init(struct usb_interface *interface, + struct usb_line6 *line6); + +#endif -- cgit v0.10.2 From e69229f2eb9d5f44981840eaf014fcb5ed60faac Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Aug 2014 10:56:09 +0200 Subject: m68k/atari: Remove obsolete keyboard_tasklet scheduling If CONFIG_VT=n: arch/m68k/atari/built-in.o: In function `atari_keyboard_interrupt': atakeyb.c:(.text+0x1846): undefined reference to `keyboard_tasklet' atakeyb.c:(.text+0x1852): undefined reference to `keyboard_tasklet' I think the keyboard_tasklet scheduling is no longer needed, as I believe it's handled by drivers/tty/vt/keyboard.c based on events received from the input subsystem. So just remove it. Signed-off-by: Geert Uytterhoeven Tested-by: Michael Schmitz diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index ad91969..7bea01c 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -170,7 +170,6 @@ repeat: if (acia_stat & ACIA_RDRF) { /* received a character */ scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ - tasklet_schedule(&keyboard_tasklet); interpret_scancode: switch (kb_state.state) { case KEYBOARD: -- cgit v0.10.2 From 3566c964767811f3965979fa9598027b6550026d Mon Sep 17 00:00:00 2001 From: alex chen Date: Mon, 12 Jan 2015 19:01:03 +0800 Subject: GFS2: fix sprintf format specifier Sprintf format specifier "%d" and "%u" are mixed up in gfs2_recovery_done() and freeze_show(). So correct them. Signed-off-by: Alex Chen Reviewed-by: Joseph Qi Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 573bd3b..1b64577 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -439,7 +439,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, ls->ls_recover_jid_done = jid; ls->ls_recover_jid_status = message; - sprintf(env_jid, "JID=%d", jid); + sprintf(env_jid, "JID=%u", jid); sprintf(env_status, "RECOVERY=%s", message == LM_RD_SUCCESS ? "Done" : "Failed"); kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 3ab566b..ae8e881 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -96,7 +96,7 @@ static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) struct super_block *sb = sdp->sd_vfs; int frozen = (sb->s_writers.frozen == SB_UNFROZEN) ? 0 : 1; - return snprintf(buf, PAGE_SIZE, "%u\n", frozen); + return snprintf(buf, PAGE_SIZE, "%d\n", frozen); } static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) -- cgit v0.10.2 From a8fc91afab2f6bc50ce5b5be86dd7fc4af159c70 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 4 Jan 2015 15:04:34 +0100 Subject: atyfb: mark DMI system id table as __initconst We can mark the DMI system id table as __initconst by using a helper variable that'll tell us if we need to unregister the reboot notifier in atyfb_exit() instead of matching the DMI system id again. This frees up ~680 bytes of runtime memory, the DMI table occupies. Signed-off-by: Mathias Krause Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 37ec09b..8789e48 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -3948,7 +3948,7 @@ static struct notifier_block atyfb_reboot_notifier = { .notifier_call = atyfb_reboot_notify, }; -static const struct dmi_system_id atyfb_reboot_ids[] = { +static const struct dmi_system_id atyfb_reboot_ids[] __initconst = { { .ident = "HP OmniBook 500", .matches = { @@ -3960,6 +3960,7 @@ static const struct dmi_system_id atyfb_reboot_ids[] = { { } }; +static bool registered_notifier = false; static int __init atyfb_init(void) { @@ -3982,15 +3983,17 @@ static int __init atyfb_init(void) if (err1 && err2) return -ENODEV; - if (dmi_check_system(atyfb_reboot_ids)) + if (dmi_check_system(atyfb_reboot_ids)) { register_reboot_notifier(&atyfb_reboot_notifier); + registered_notifier = true; + } return 0; } static void __exit atyfb_exit(void) { - if (dmi_check_system(atyfb_reboot_ids)) + if (registered_notifier) unregister_reboot_notifier(&atyfb_reboot_notifier); #ifdef CONFIG_PCI -- cgit v0.10.2 From 77a7f1837a9c6f9cfb6ce0d5b166e1f1f7b117b3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 31 Dec 2014 12:25:38 +0530 Subject: fbdev: geocode: remove unneeded NULL check the check for info is not required as we are checking it immediately after gx1fb_init_fbinfo() and returnig -ENOMEM if it is NULL. Signed-off-by: Sudip Mukherjee Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c index 2794ba1..9bee874 100644 --- a/drivers/video/fbdev/geode/gx1fb_core.c +++ b/drivers/video/fbdev/geode/gx1fb_core.c @@ -374,10 +374,8 @@ static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) release_mem_region(gx1_gx_base() + 0x8300, 0x100); } - if (info) { - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); return ret; } -- cgit v0.10.2 From 0e8787313a00d4202aad249d0734a30bbde1485b Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Dec 2014 22:33:20 +0100 Subject: video: omapdss: Add opa362 driver opa362 is amplifier for video and can be connected to the tvout pads of the OMAP3. It has one gpio control for enable/disable of the output (high impedance). Signed-off-by: H. Nikolaus Schaller Signed-off-by: Marek Belisko Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/omap2/displays-new/Kconfig b/drivers/video/fbdev/omap2/displays-new/Kconfig index e6cfc38..5747101 100644 --- a/drivers/video/fbdev/omap2/displays-new/Kconfig +++ b/drivers/video/fbdev/omap2/displays-new/Kconfig @@ -1,6 +1,12 @@ menu "OMAP Display Device Drivers (new device model)" depends on OMAP2_DSS +config DISPLAY_ENCODER_OPA362 + tristate "OPA362 external analog amplifier" + help + Driver for OPA362 external analog TV amplifier controlled + through a GPIO. + config DISPLAY_ENCODER_TFP410 tristate "TFP410 DPI to DVI Encoder" help diff --git a/drivers/video/fbdev/omap2/displays-new/Makefile b/drivers/video/fbdev/omap2/displays-new/Makefile index 0323a8a..9aa176b 100644 --- a/drivers/video/fbdev/omap2/displays-new/Makefile +++ b/drivers/video/fbdev/omap2/displays-new/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c new file mode 100644 index 0000000..84a6b33 --- /dev/null +++ b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c @@ -0,0 +1,285 @@ +/* + * OPA362 analog video amplifier with output/power control + * + * Copyright (C) 2014 Golden Delicious Computers + * Author: H. Nikolaus Schaller + * + * based on encoder-tfp410 + * + * Copyright (C) 2013 Texas Instruments + * Author: Tomi Valkeinen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include